summaryrefslogtreecommitdiffstats
path: root/sys/miscfs/devfs
diff options
context:
space:
mode:
authorjulian <julian@FreeBSD.org>1995-09-09 12:51:56 +0000
committerjulian <julian@FreeBSD.org>1995-09-09 12:51:56 +0000
commitde26dac73e741823c6709d241f04dc5b5cfe45ec (patch)
tree6813a2a1c74c25564927ac74b5afd61416997c3f /sys/miscfs/devfs
parent963f4486b05c8ad4bf733678713126e013fbf757 (diff)
downloadFreeBSD-src-de26dac73e741823c6709d241f04dc5b5cfe45ec.zip
FreeBSD-src-de26dac73e741823c6709d241f04dc5b5cfe45ec.tar.gz
More hacking on devfs..
I can now do an mv on devices and directories in devfs This was the hardest part.. link, delete and symlink will follow in short order. This code works but has definitly got vnode locking problems I am electing to get the structure of it working before spending too much time on the vnode confusion so it's probably not reliable at the moment.. never-the less it looks good. :)
Diffstat (limited to 'sys/miscfs/devfs')
-rw-r--r--sys/miscfs/devfs/devfs_proto.h8
-rw-r--r--sys/miscfs/devfs/devfs_tree.c391
-rw-r--r--sys/miscfs/devfs/devfs_vnops.c249
3 files changed, 469 insertions, 179 deletions
diff --git a/sys/miscfs/devfs/devfs_proto.h b/sys/miscfs/devfs/devfs_proto.h
index ff9adcd..cdc6840 100644
--- a/sys/miscfs/devfs/devfs_proto.h
+++ b/sys/miscfs/devfs/devfs_proto.h
@@ -1,20 +1,22 @@
/* THIS FILE PRODUCED AUTOMATICALLY */
void devfs_sinit(caddr_t junk) /*proto*/;
-dn_p dev_findname(dn_p dir,char *name) /*proto*/;
+devnm_p dev_findname(dn_p dir,char *name) /*proto*/;
int dev_finddir(char *orig_path, dn_p dirnode, int create, dn_p *dn_pp) /*proto*/;
-int dev_add_name(char *name, dn_p dirnode,devnm_p back, int entrytype, union typeinfo *by, devnm_p *devnm_pp) /*proto*/;
+int dev_add_name(char *name, dn_p dirnode, devnm_p back, dn_p dnp, devnm_p *devnm_pp) /*proto*/;
+int dev_add_node(int entrytype, union typeinfo *by, dn_p proto, dn_p *dn_pp) /*proto*/;
int dev_touch(devnm_p key) /* update the node for this dev */ /*proto*/;
void devfs_dn_free(dn_p dnp) /*proto*/;
int devfs_add_fronts(devnm_p parent,devnm_p child) /*proto*/;
void dev_remove_dev(devnm_p devnmp) /*proto*/;
int dev_dup_plane(struct devfsmount *devfs_mp_p) /*proto*/;
void devfs_free_plane(struct devfsmount *devfs_mp_p) /*proto*/;
-int dev_dup_name(dn_p parent, devnm_p back, devnm_p *dnm_pp, struct devfsmount *dvm) /*proto*/;
+int dev_dup_entry(dn_p parent, devnm_p back, devnm_p *dnm_pp, struct devfsmount *dvm) /*proto*/;
void dev_free_name(devnm_p devnmp) /*proto*/;
int devfs_vntodn(struct vnode *vn_p, dn_p *dn_pp) /*proto*/;
int devfs_dntovn(dn_p dnp, struct vnode **vn_pp) /*proto*/;
int get_cdev_major_num(caddr_t addr) /*proto*/;
int get_bdev_major_num(caddr_t addr) /*proto*/;
+int dev_add_entry(char *name, dn_p parent, int type, union typeinfo *by, devnm_p *nm_pp) /*proto*/ ;
int devfs_init(void) /*proto*/;
int devfs_mount( struct mount *mp, char *path, caddr_t data, struct nameidata *ndp, struct proc *p) /*proto*/;
int mountdevfs( struct mount *mp, struct proc *p) /*proto*/;
diff --git a/sys/miscfs/devfs/devfs_tree.c b/sys/miscfs/devfs/devfs_tree.c
index 7e9d57e..ae6b2d0 100644
--- a/sys/miscfs/devfs/devfs_tree.c
+++ b/sys/miscfs/devfs/devfs_tree.c
@@ -2,7 +2,7 @@
/*
* Written by Julian Elischer (julian@DIALix.oz.au)
*
- * $Header: /home/ncvs/src/sys/miscfs/devfs/devfs_tree.c,v 1.4 1995/09/07 06:01:33 julian Exp $
+ * $Header: /home/ncvs/src/sys/miscfs/devfs/devfs_tree.c,v 1.5 1995/09/08 04:46:14 julian Exp $
*/
#include "param.h"
@@ -39,9 +39,9 @@ void devfs_sinit(caddr_t junk) /*proto*/
/*
* call the right routine at the right time with the right args....
*/
- retval = dev_add_name("root",NULL,NULL,DEV_DIR,NULL,&dev_root);
+ retval = dev_add_entry("root", NULL, DEV_DIR, NULL, &dev_root);
#ifdef PARANOID
- if(retval) panic("devfs_sinit: dev_add_name failed ");
+ if(retval) panic("devfs_sinit: dev_add_entry failed ");
#endif
devfs_hidden_mount = (struct mount *)malloc(sizeof(struct mount),
M_MOUNT,M_NOWAIT);
@@ -66,7 +66,7 @@ void devfs_sinit(caddr_t junk) /*proto*/
* Search down the linked list off a dir to find "name" *
* return the dn_p for that node.
\***************************************************************/
-dn_p dev_findname(dn_p dir,char *name) /*proto*/
+devnm_p dev_findname(dn_p dir,char *name) /*proto*/
{
devnm_p newfp;
DBPRINT((" dev_findname(%s)\n",name));
@@ -76,21 +76,22 @@ dn_p dev_findname(dn_p dir,char *name) /*proto*/
{
if(name[1] == 0)
{
- return dir;
+ return dir->by.Dir.myname;
}
if((name[1] == '.') && (name[2] == 0))
{
- return dir->by.Dir.parent; /* for root, .. == . */
+ /* for root, .. == . */
+ return dir->by.Dir.parent->by.Dir.myname;
}
}
newfp = dir->by.Dir.dirlist;
while(newfp)
{
if(!(strcmp(name,newfp->name)))
- return newfp->dnp;
+ return newfp;
newfp = newfp->next;
}
- return (dn_p)0;
+ return NULL;
}
/***********************************************************************\
@@ -162,9 +163,10 @@ int dev_finddir(char *orig_path, dn_p dirnode, int create, dn_p *dn_pp) /*proto*
/***************************************\
* Start scanning along the linked list *
\***************************************/
- dnp = dev_findname(dirnode,name);
- if(dnp)
+ devnmp = dev_findname(dirnode,name);
+ if(devnmp)
{ /* check it's a directory */
+ dnp = devnmp->dnp;
if(dnp->type != DEV_DIR) return ENOTDIR;
}
else
@@ -175,7 +177,7 @@ int dev_finddir(char *orig_path, dn_p dirnode, int create, dn_p *dn_pp) /*proto*
\***************************************/
if(!create) return ENOENT;
- if(retval = dev_add_name(name, dirnode, NULL ,DEV_DIR,
+ if(retval = dev_add_entry(name, dirnode, DEV_DIR,
NULL, &devnmp))
{
return retval;
@@ -197,24 +199,20 @@ int dev_finddir(char *orig_path, dn_p dirnode, int create, dn_p *dn_pp) /*proto*
/***********************************************************************\
* Add a new element to the devfs backing structure. *
* If we're creating a root node, then dirname is NULL *
-* If devnode is non zero, then we just want to create a link to it *
-* This implies that we are not at base level and it's a not a DIR *
* *
-* Creates a name node, and (optionally) a new dev_node to go with it *
+* Creates a name node, and links it to the supplied node *
\***********************************************************************/
-int dev_add_name(char *name, dn_p dirnode,devnm_p back, int entrytype, union typeinfo *by, devnm_p *devnm_pp) /*proto*/
+int dev_add_name(char *name, dn_p dirnode, devnm_p back, dn_p dnp, devnm_p *devnm_pp) /*proto*/
{
devnm_p devnmp;
devnm_p realthing; /* needed to create an alias */
- dn_p dnp;
int retval;
DBPRINT(("dev_add_name\n"));
if(dirnode ) {
if(dirnode->type != DEV_DIR) return(ENOTDIR);
- dnp = dev_findname(dirnode,name);
- if(dnp) /* if we actually found it.. */
+ if( dev_findname(dirnode,name))
return(EEXIST);
}
/*
@@ -233,108 +231,11 @@ int dev_add_name(char *name, dn_p dirnode,devnm_p back, int entrytype, union typ
}
bzero(devnmp,sizeof(devnm_t));
- /*
- * If we don't already have one,
- * Allocate a devfs node..
- * If we already have one, create a new link to it.
- * DIR types ALWAYS get a new node..
- */
- if (( entrytype == DEV_DIR) || (!back)) {
- if(!(dnp = (dn_p)malloc(sizeof(devnode_t),
- M_DEVFSNODE, M_NOWAIT)))
- {
- free(devnmp,M_DEVFSNAME);
- return ENOMEM;
- }
- bzero(dnp,sizeof(devnode_t));
- /*
- * note the node type we are adding
- * and set the creation times to NOW
- * put in it's name
- */
- dnp->type = entrytype;
- TIMEVAL_TO_TIMESPEC(&time,&(dnp->ctime))
- dnp->mtime = dnp->ctime;
- dnp->atime = dnp->ctime;
- /*
- * fill out the dev node according to type
- */
- switch(entrytype) {
- case DEV_DIR:
- /*
- * As it's a directory, make sure
- * it has a null entries list
- */
- dnp->by.Dir.dirlast = &(dnp->by.Dir.dirlist);
- dnp->by.Dir.dirlist = (devnm_p)0;
- if ( dirnode ) {
- dnp->by.Dir.parent = (dn_p)dirnode;
- } else {
- /* root loops to self */
- dnp->by.Dir.parent = dnp;
- }
- dnp->by.Dir.parent->links++; /* account for .. */
- dnp->links++; /* for .*/
- dnp->by.Dir.myname = devnmp;
- /*
- * make sure that the ops associated with it are the ops
- * that we use (by default) for directories
- */
- dnp->ops = &devfs_vnodeop_p;
- dnp->mode |= 0555; /* default perms */
- break;
- /*******************************************************\
- * The rest of these can't happen except in the back plane*
- \*******************************************************/
- case DEV_BDEV:
- /*
- * Make sure it has DEVICE type ops
- * and device specific fields are correct
- */
- dnp->ops = &dev_spec_vnodeop_p;
- dnp->by.Bdev.bdevsw = by->Bdev.bdevsw;
- dnp->by.Bdev.dev = by->Bdev.dev;
- break;
- case DEV_CDEV:
- /*
- * Make sure it has DEVICE type ops
- * and device specific fields are correct
- */
- dnp->ops = &dev_spec_vnodeop_p;
- dnp->by.Cdev.cdevsw = by->Cdev.cdevsw;
- dnp->by.Cdev.dev = by->Cdev.dev;
- break;
- case DEV_DDEV:
- /*
- * store the address of (the address of) the ops
- * and the magic cookie to use with them
- */
- dnp->by.Ddev.arg = by->Ddev.arg;
- dnp->ops = by->Ddev.ops;
- break;
-
-
- case DEV_ALIAS:
- /*
- * point to the node we want to shadow
- * Also store the fact we exist so that aliases
- * can be deleted accuratly when the original node
- * is deleted.. (i.e. when device is removed)
- */
- realthing = by->Alias.realthing;
- dnp->by.Alias.realthing = realthing;
- dnp->by.Alias.next = realthing->as.back.aliases;
- realthing->as.back.aliases = devnmp;
- break;
- }
- /* inherrit our parent's mount info */
- if(dirnode) {
- dnp->dvm = dirnode->dvm;
- if(!dnp->dvm) printf("parent had null dvm ");
- }
- } else {
- dnp = back->dnp;
- if(!dnp->dvm) printf("node has null dvm ");
+ /* inherrit our parent's mount info */ /*XXX*/
+ /* a kludge but.... */
+ if(dirnode && ( dnp->dvm == NULL)) {
+ dnp->dvm = dirnode->dvm;
+ if(!dnp->dvm) printf("parent had null dvm ");
}
/*
@@ -344,6 +245,22 @@ int dev_add_name(char *name, dn_p dirnode,devnm_p back, int entrytype, union typ
*/
devnmp->dnp = dnp;
dnp->links++ ; /* implicit from our own name-node */
+ if(dnp->type == DEV_DIR) {
+ dnp->by.Dir.myname = devnmp;
+ /*
+ * If we are unlinking from an old dir, decrement it's links
+ * as we point our '..' elsewhere
+ */
+ if(dnp->by.Dir.parent) {
+ dnp->by.Dir.parent->links--;
+ }
+ if(dirnode) {
+ dnp->by.Dir.parent = dirnode;
+ } else {
+ dnp->by.Dir.parent = dnp;
+ }
+ dnp->by.Dir.parent->links++; /* account for the new '..' */
+ }
/*
* put in it's name
@@ -406,6 +323,102 @@ int dev_add_name(char *name, dn_p dirnode,devnm_p back, int entrytype, union typ
}
+/***********************************************************************\
+* Add a new element to the devfs backing structure. *
+* *
+* Creates a new dev_node to go with it *
+* 'by' gives us info to make our node *
+* note the 'links' count is 0 (except if a dir) *
+* but it is only cleared on a transition *
+* so this is ok till we link it to something *
+\***********************************************************************/
+int dev_add_node(int entrytype, union typeinfo *by, dn_p proto, dn_p *dn_pp) /*proto*/
+{
+ dn_p dnp;
+ int retval;
+
+ DBPRINT(("dev_add_node\n"));
+ if(!(dnp = (dn_p)malloc(sizeof(devnode_t),
+ M_DEVFSNODE, M_NOWAIT)))
+ {
+ return ENOMEM;
+ }
+ if(proto) {
+ /* XXX should check that we are NOT copying a device node */
+ bcopy(proto, dnp, sizeof(devnode_t));
+ /* some things you DON'T copy */
+ dnp->links = 0;
+ dnp->dvm = NULL;
+ dnp->vn = NULL;
+ dnp->len = 0;
+ } else {
+ bzero(dnp,sizeof(devnode_t));
+ dnp->type = entrytype;
+ TIMEVAL_TO_TIMESPEC(&time,&(dnp->ctime))
+ dnp->mtime = dnp->ctime;
+ dnp->atime = dnp->ctime;
+ }
+ /*
+ * fill out the dev node according to type
+ */
+ switch(entrytype) {
+ case DEV_DIR:
+ /*
+ * As it's a directory, make sure
+ * it has a null entries list
+ */
+ dnp->by.Dir.dirlast = &(dnp->by.Dir.dirlist);
+ dnp->by.Dir.dirlist = (devnm_p)0;
+ dnp->by.Dir.entrycount = 0;
+ /* until we know better, it has a null parent pointer*/
+ dnp->by.Dir.parent = NULL;
+ dnp->links++; /* for .*/
+ dnp->by.Dir.myname = NULL;
+ /*
+ * make sure that the ops associated with it are the ops
+ * that we use (by default) for directories
+ */
+ dnp->ops = &devfs_vnodeop_p;
+ dnp->mode |= 0555; /* default perms */
+ break;
+ /*******************************************************\
+ * The rest of these can't happen except in the back plane*
+ \*******************************************************/
+ case DEV_BDEV:
+ /*
+ * Make sure it has DEVICE type ops
+ * and device specific fields are correct
+ */
+ dnp->ops = &dev_spec_vnodeop_p;
+ dnp->by.Bdev.bdevsw = by->Bdev.bdevsw;
+ dnp->by.Bdev.dev = by->Bdev.dev;
+ break;
+ case DEV_CDEV:
+ /*
+ * Make sure it has DEVICE type ops
+ * and device specific fields are correct
+ */
+ dnp->ops = &dev_spec_vnodeop_p;
+ dnp->by.Cdev.cdevsw = by->Cdev.cdevsw;
+ dnp->by.Cdev.dev = by->Cdev.dev;
+ break;
+ case DEV_DDEV:
+ /*
+ * store the address of (the address of) the ops
+ * and the magic cookie to use with them
+ */
+ dnp->by.Ddev.arg = by->Ddev.arg;
+ dnp->ops = by->Ddev.ops;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ *dn_pp = dnp;
+ return 0 ;
+}
+
+
/***************************************************************\
* DEV_NODE reference count manipulations.. when a ref count *
* reaches 0, the node is to be deleted *
@@ -419,13 +432,7 @@ int dev_touch(devnm_p key) /* update the node for this dev */ /*proto*/
void devfs_dn_free(dn_p dnp) /*proto*/
{
- if(dnp->links <= 0)
- {
- printf("devfs node reference count bogus\n");
- Debugger("devfs_dn_free");
- return;
- }
- if(--dnp->links == 0 )
+ if(--dnp->links <= 0 ) /* can be -1 for initial free, on error */
{
/*probably need to do other cleanups XXX */
devfs_dropvnode(dnp);
@@ -454,6 +461,7 @@ int devfs_add_fronts(devnm_p parent,devnm_p child) /*proto*/
{
devnm_p newnmp;
devnm_p falias;
+ dn_p dnp = child->dnp;
int type = child->dnp->type;
DBPRINT((" devfs_add_fronts\n"));
@@ -462,27 +470,30 @@ int devfs_add_fronts(devnm_p parent,devnm_p child) /*proto*/
\***********************************************/
for (falias = parent->next_front; falias; falias = falias->next_front)
{
- if(dev_findname(falias->dnp,child->name))
- {
- printf("Device %s not created, already exists\n",
- child->name);
- continue;
+ /*
+ * If a Dir (XXX symlink too one day)
+ * Make the node, using the original as a prototype)
+ */
+ if(type == DEV_DIR) {
+ if (dev_add_node(type, NULL, dnp, &dnp))
+ {
+ printf("Device %s: node allocation failed\n",
+ child->name);
+ continue;
+ }
}
- if (dev_add_name(child->name,parent->dnp,child,
- type,NULL,&newnmp))
- {
- printf("Device %s: allocation failed\n",
- child->name);
+ if (dev_add_name(child->name,parent->dnp,child, dnp,&newnmp)) {
+ if( type == DEV_DIR) {
+ devfs_dn_free(dnp); /* 1->0 */
+ }
+ printf("Device %s: allocation failed\n", child->name);
continue;
}
}
- return(0); /* for now always succeed */
+ return 0; /* for now always succeed */
}
-
-
-
-
+
/***********************************************************************
* remove all instances of this devicename [for backing nodes..]
* note.. if there is another link to the node (non dir nodes only)
@@ -511,7 +522,7 @@ void dev_remove_dev(devnm_p devnmp) /*proto*/
/***************************************************************
* duplicate the backing tree into a tree of nodes hung off the
* mount point given as the argument. Do this by
- * calling dev_dup_name which recurses all the way
+ * calling dev_dup_entry which recurses all the way
* up the tree..
* If we are the first plane, just return the base root
**************************************************************/
@@ -522,7 +533,7 @@ int dev_dup_plane(struct devfsmount *devfs_mp_p) /*proto*/
DBPRINT((" dev_dup_plane\n"));
if(devfs_up_and_going) {
- if(error = dev_dup_name(NULL, dev_root, &new, devfs_mp_p)) {
+ if(error = dev_dup_entry(NULL, dev_root, &new, devfs_mp_p)) {
return error;
}
} else { /* we are doing the dummy mount during initialisation.. */
@@ -555,7 +566,7 @@ void devfs_free_plane(struct devfsmount *devfs_mp_p) /*proto*/
* recursively will create subnodes corresponding to equivalent *
* child nodes in the base level *
\***************************************************************/
-int dev_dup_name(dn_p parent, devnm_p back, devnm_p *dnm_pp, struct devfsmount *dvm) /*proto*/
+int dev_dup_entry(dn_p parent, devnm_p back, devnm_p *dnm_pp, struct devfsmount *dvm) /*proto*/
{
devnm_p newnmp;
struct devfsmount *dmt;
@@ -563,13 +574,27 @@ int dev_dup_name(dn_p parent, devnm_p back, devnm_p *dnm_pp, struct devfsmount *
devnm_p newfront;
int error;
dn_p dnp = back->dnp;
+ int type = back->dnp->type;
- DBPRINT((" dev_dup_name\n"));
+ DBPRINT((" dev_dup_entry\n"));
/*
- * go get the node made
+ * go get the node made (if we need to)
+ * use the back one as a prototype
*/
- error = dev_add_name(back->name,parent,back,dnp->type,NULL,&newnmp);
- if ( error ) return error;
+ if ( type == DEV_DIR) {
+ error = dev_add_node( dnp->type, NULL, dnp, &dnp);
+ if(error) {
+ printf("dev_dup_entry: node alloc failed\n");
+ return error;
+ }
+ }
+ error = dev_add_name(back->name,parent,back,dnp,&newnmp);
+ if ( error ) {
+ if ( type == DEV_DIR) {
+ devfs_dn_free(dnp); /* 1->0 */
+ }
+ return error;
+ }
/*
* If we have just made the root, then insert the pointer to the
@@ -589,7 +614,7 @@ int dev_dup_name(dn_p parent, devnm_p back, devnm_p *dnm_pp, struct devfsmount *
for(newback = back->dnp->by.Dir.dirlist;
newback; newback = newback->next)
{
- if(error = dev_dup_name(newnmp->dnp,
+ if(error = dev_dup_entry(newnmp->dnp,
newback, &newfront, NULL))
{
break; /* back out with an error */
@@ -604,26 +629,32 @@ int dev_dup_name(dn_p parent, devnm_p back, devnm_p *dnm_pp, struct devfsmount *
* Free a name node (and any below it of it's a directory node) *
* remember that if there are other names pointing to the *
* dev_node then it may not get freed yet *
+* can handle if there is no dnp *
\***************************************************************/
void dev_free_name(devnm_p devnmp) /*proto*/
{
dn_p parent = devnmp->parent;
+ dn_p dnp = devnmp->dnp;
devnm_p back;
DBPRINT((" dev_free_name\n"));
- if(devnmp->dnp->type == DEV_DIR)
- {
- while(devnmp->dnp->by.Dir.dirlist)
+ if(dnp) {
+ if(dnp->type == DEV_DIR)
{
- dev_free_name(devnmp->dnp->by.Dir.dirlist);
+ while(dnp->by.Dir.dirlist)
+ {
+ dev_free_name(dnp->by.Dir.dirlist);
+ }
+ /*
+ * drop the reference counts on our and our parent's
+ * nodes for "." and ".." (root has ".." -> "." )
+ */
+ devfs_dn_free(dnp); /* account for '.' */
+ devfs_dn_free(dnp->by.Dir.parent); /* '..' */
+ /* should only have one reference left
+ (from name element) */
}
- /*
- * drop the reference counts on our and our parent's
- * nodes for "." and ".." (root has ".." -> "." )
- */
- devfs_dn_free(devnmp->dnp); /* account for '.' */
- devfs_dn_free(devnmp->dnp->by.Dir.parent); /* and '..' */
- /* should only have one reference left (from name element) */
+ devfs_dn_free(dnp);
}
/*
* unlink ourselves from the directory on this plane
@@ -663,7 +694,6 @@ void dev_free_name(devnm_p devnmp) /*proto*/
* If the front node has it's own devnode structure, *
* then free it. *
\***************************************************************/
- devfs_dn_free(devnmp->dnp);
free(devnmp,M_DEVFSNAME);
return;
}
@@ -849,6 +879,30 @@ int get_bdev_major_num(caddr_t addr) /*proto*/
}
/***********************************************************************\
+* add a whole device, with not prototype.. make name element and node *
+\***********************************************************************/
+int dev_add_entry(char *name, dn_p parent, int type, union typeinfo *by, devnm_p *nm_pp) /*proto*/
+{
+ dn_p dnp;
+ int error = 0;
+
+ DBPRINT((" devfs_add_entry\n"));
+ if (error = dev_add_node(type, by, NULL, &dnp))
+ {
+ printf("Device %s: base node allocation failed\n", name);
+ return error;
+ }
+ if ( error = dev_add_name(name ,parent ,NULL, dnp, nm_pp))
+ {
+ devfs_dn_free(dnp); /* 1->0 for dir, 0->(-1) for other */
+ printf("Device %s: name slot allocation failed\n",
+ name);
+
+ }
+ return error;
+}
+
+/***********************************************************************\
* Add the named device entry into the given directory, and make it *
* The appropriate type... (called (sometimes indirectly) by drivers..) *
\***********************************************************************/
@@ -876,14 +930,14 @@ void *dev_add(char *path,
major = get_cdev_major_num(funct);
by.Cdev.cdevsw = cdevsw + major;
by.Cdev.dev = makedev(major, minor);
- if( dev_add_name(name, dnp, NULL, DEV_CDEV, &by,&new_dev))
+ if( dev_add_entry(name, dnp, DEV_CDEV, &by,&new_dev))
return NULL;
break;
case DV_BLK:
major = get_bdev_major_num(funct);
by.Bdev.bdevsw = bdevsw + major;
by.Bdev.dev = makedev(major, minor);
- if( dev_add_name(name, dnp, NULL, DEV_BDEV, &by, &new_dev))
+ if( dev_add_entry(name, dnp, DEV_BDEV, &by, &new_dev))
return NULL;
break;
default:
@@ -894,8 +948,7 @@ void *dev_add(char *path,
new_dev->dnp->mode |= perms;
return new_dev;
}
-
-
+
/***********************************************************************\
* Add the named device entry into the given directory, and make it *
* a link to the already created device given as an arg.. *
@@ -904,19 +957,19 @@ void *dev_link(char *path, char *name, void *original)
{
devnm_p new_dev;
devnm_p orig = (devnm_p) original;
- dn_p dnp; /* devnode for parent directory */
+ dn_p dirnode; /* devnode for parent directory */
int retval;
int major ;
union typeinfo by;
DBPRINT(("dev_add\n"));
- retval = dev_finddir(path,NULL,1,&dnp);
+ retval = dev_finddir(path,NULL,1,&dirnode);
if (retval) return 0;
/*
* The DEV_CDEV below is not used other than it must NOT be DEV_DIR
* the correctness of original shuold be checked..
*/
- if( dev_add_name(name, dnp, orig, DEV_CDEV, NULL,&new_dev))
+ if( dev_add_name(name, dirnode, NULL, orig->dnp, &new_dev))
return NULL;
return new_dev;
}
diff --git a/sys/miscfs/devfs/devfs_vnops.c b/sys/miscfs/devfs/devfs_vnops.c
index 2aba6c1..8d220ef 100644
--- a/sys/miscfs/devfs/devfs_vnops.c
+++ b/sys/miscfs/devfs/devfs_vnops.c
@@ -1,7 +1,7 @@
/*
* Written by Julian Elischer (julian@DIALix.oz.au)
*
- * $Header: /home/ncvs/src/sys/miscfs/devfs/devfs_vnops.c,v 1.10 1995/09/06 23:15:54 julian Exp $
+ * $Header: /home/ncvs/src/sys/miscfs/devfs/devfs_vnops.c,v 1.11 1995/09/07 06:01:36 julian Exp $
*
* symlinks can wait 'til later.
*/
@@ -77,6 +77,7 @@ int devfs_lookup(struct vop_lookup_args *ap) /*proto*/
struct vnode **result_vnode = ap->a_vpp;
dn_p dir_node; /* the directory we are searching */
dn_p new_node; /* the node we are searching for */
+ devnm_p new_nodename;
int flags = cnp->cn_flags;
int op = cnp->cn_nameiop; /* LOOKUP, CREATE, RENAME, or DELETE */
int lockparent = flags & LOCKPARENT;
@@ -174,12 +175,14 @@ DBPRINT(("errr, maybe not cached "));
heldchar = cnp->cn_nameptr[cnp->cn_namelen];
cnp->cn_nameptr[cnp->cn_namelen] = '\0';
- new_node = dev_findname(dir_node,cnp->cn_nameptr);
+ new_nodename = dev_findname(dir_node,cnp->cn_nameptr);
cnp->cn_nameptr[cnp->cn_namelen] = heldchar;
- if(new_node)
+ if(new_nodename)
{
+ new_node = new_nodename->dnp;
goto found;
}
+ new_node = NULL; /* to be safe */
/***********************************************************************\
* Failed to find it.. (That may be good) *
\***********************************************************************/
@@ -736,6 +739,7 @@ DBPRINT(("write\n"));
}
}
+/* presently not called from devices anyhow */
int devfs_ioctl(struct vop_ioctl_args *ap) /*proto*/
/*struct vop_ioctl_args {
struct vnode *a_vp;
@@ -760,7 +764,7 @@ int devfs_select(struct vop_select_args *ap) /*proto*/
} */
{
DBPRINT(("select\n"));
- return 1; /* DOS filesystems never block? */
+ return 1; /* filesystems never block? */
}
int devfs_mmap(struct vop_mmap_args *ap) /*proto*/
@@ -829,6 +833,33 @@ DBPRINT(("link\n"));
return 0;
}
+/*
+ * Rename system call. Seems overly complicated to me...
+ * rename("foo", "bar");
+ * is essentially
+ * unlink("bar");
+ * link("foo", "bar");
+ * unlink("foo");
+ * but ``atomically''.
+ *
+ * When the target exists, both the directory
+ * and target vnodes are locked.
+ * the source and source-parent vnodes are referenced
+ *
+ *
+ * Basic algorithm is:
+ *
+ * 1) Bump link count on source while we're linking it to the
+ * target. This also ensure the inode won't be deleted out
+ * from underneath us while we work (it may be truncated by
+ * a concurrent `trunc' or `open' for creation).
+ * 2) Link source to destination. If destination already exists,
+ * delete it first.
+ * 3) Unlink source reference to node if still around. If a
+ * directory was moved and the parent of the destination
+ * is different from the source, patch the ".." entry in the
+ * directory.
+ */
int devfs_rename(struct vop_rename_args *ap) /*proto*/
/*struct vop_rename_args {
struct vnode *a_fdvp;
@@ -839,8 +870,212 @@ int devfs_rename(struct vop_rename_args *ap) /*proto*/
struct componentname *a_tcnp;
} */
{
-DBPRINT(("rename\n"));
- return 0;
+ struct vnode *tvp = ap->a_tvp;
+ struct vnode *tdvp = ap->a_tdvp;
+ struct vnode *fvp = ap->a_fvp;
+ struct vnode *fdvp = ap->a_fdvp;
+ struct componentname *tcnp = ap->a_tcnp;
+ struct componentname *fcnp = ap->a_fcnp;
+ dn_p fp, fdp, tp, tdp;
+ devnm_p fnp,tnp;
+ int doingdirectory = 0, oldparent = 0, newparent = 0;
+ int error = 0;
+ uid_t outuid = tcnp->cn_cred->cr_uid;
+
+ /*
+ * First catch an arbitrary restriction for this FS
+ */
+ if(tcnp->cn_namelen > DEVMAXNAMESIZE) {
+ error = ENAMETOOLONG;
+ goto abortit;
+ }
+
+ /*
+ * Lock our directories and get our name pointers
+ * assume that the names are null terminated as they
+ * are the end of the path. Get pointers to all our
+ * devfs structures.
+ */
+ if ( error = devfs_vntodn(tdvp,&tdp)) goto abortit;
+ if ( error = devfs_vntodn(fdvp,&fdp)) goto abortit;
+ if ( error = devfs_vntodn(fvp,&fp)) goto abortit;
+ fnp = dev_findname(fdp,fcnp->cn_nameptr);
+ if(!fnp) panic("devfs_rename: source dissapeared");
+ if (tvp) {
+ if ( error = devfs_vntodn(tvp,&tp)) goto abortit;
+ tnp = dev_findname(tdp,tcnp->cn_nameptr);
+ if(!tnp) panic("devfs_rename: target dissapeared");
+ } else {
+ tp = NULL;
+ tnp = NULL;
+ }
+
+ /*
+ * trying to move it out of devfs? (v_tag == VT_DEVFS)
+ * if we move a dir across mnt points. we need to fix all
+ * the mountpoint pointers! XXX
+ * so for now keep dirs within the same mount
+ */
+ if ( (fvp->v_tag != VT_DEVFS)
+ || (fvp->v_tag != tdvp->v_tag)
+ || (tvp && (fvp->v_tag != tvp->v_tag))
+ || ((fp->type == DEV_DIR) && (fp->dvm != tdp->dvm ))) {
+ error = EXDEV;
+abortit:
+ VOP_ABORTOP(tdvp, tcnp);
+ if (tdvp == tvp) /* eh? */
+ vrele(tdvp);
+ else
+ vput(tdvp);
+ if (tvp)
+ vput(tvp);
+ VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
+ vrele(fdvp);
+ vrele(fvp);
+ return (error);
+ }
+
+ /*
+ * Check we are doing legal things WRT the new flags
+ */
+ if ((tp && (tp->flags & (IMMUTABLE | APPEND)))
+ || (fp->flags & (IMMUTABLE | APPEND))
+ || (tdp->flags & APPEND) /*XXX eh?*/
+ || (fdp->flags & APPEND)) {
+ error = EPERM;
+ goto abortit;
+ }
+
+ /*
+ * Make sure that we don't try do something stupid
+ */
+ if ((fp->type) == DEV_DIR) {
+ /*
+ * Avoid ".", "..", and aliases of "." for obvious reasons.
+ */
+ if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.')
+ || (fcnp->cn_flags&ISDOTDOT)
+ || (tcnp->cn_namelen == 1 && tcnp->cn_nameptr[0] == '.')
+ || (tcnp->cn_flags&ISDOTDOT)
+ || (tdp == fp )) {
+ error = EINVAL;
+ goto abortit;
+ }
+ doingdirectory++;
+ }
+
+ /*
+ * If ".." must be changed (ie the directory gets a new
+ * parent) then the source directory must not be in the
+ * directory heirarchy above the target, as this would
+ * orphan everything below the source directory. Also
+ * the user must have write permission in the source so
+ * as to be able to change "..".
+ */
+ if (doingdirectory && (tdp != fdp)) {
+ dn_p tmp,ntmp;
+ error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
+ tmp = tdp;
+ do {
+ if(tmp == fp) {
+ /* XXX unlock stuff here probably */
+ error = EINVAL;
+ goto out;
+ }
+ ntmp = tmp;
+ } while ((tmp = tmp->by.Dir.parent) != ntmp);
+ }
+
+ /***********************************
+ * Start actually doing things.... *
+ ***********************************/
+ TIMEVAL_TO_TIMESPEC(&time,&(fp->atime));
+ /*
+ * Check if just deleting a link name.
+ */
+ if (fvp == tvp) {
+ if (fvp->v_type == VDIR) {
+ error = EINVAL;
+ goto abortit;
+ }
+
+ /* Release destination completely. */
+ VOP_ABORTOP(tdvp, tcnp);
+ vput(tdvp);
+ vput(tvp);
+
+ /* Delete source. */
+ VOP_ABORTOP(fdvp, fcnp); /*XXX*/
+ vrele(fdvp);
+ vrele(fvp);
+ dev_free_name(fnp);
+ return 0;
+ }
+
+
+ /*
+ * 1) Bump link count while we're moving stuff
+ * around. If we crash somewhere before
+ * completing our work, too bad :)
+ */
+ fp->links++;
+ /*
+ * If the target exists zap it (unless it's a non-empty directory)
+ * We could do that as well but won't
+ */
+ if (tp) {
+ int ouruid = tcnp->cn_cred->cr_uid;
+ /*
+ * If the parent directory is "sticky", then the user must
+ * own the parent directory, or the destination of the rename,
+ * otherwise the destination may not be changed (except by
+ * root). This implements append-only directories.
+ * XXX shoudn't this be in generic code?
+ */
+ if ((tdp->mode & S_ISTXT)
+ && ouruid != 0
+ && ouruid != tdp->uid
+ && ouruid != tp->uid ) {
+ error = EPERM;
+ goto bad;
+ }
+ /*
+ * Target must be empty if a directory and have no links
+ * to it. Also, ensure source and target are compatible
+ * (both directories, or both not directories).
+ */
+ if (( doingdirectory) && (tp->links > 2)) {
+ printf("nlink = %d\n",tp->links); /*XXX*/
+ error = ENOTEMPTY;
+ goto bad;
+ }
+ cache_purge(tvp); /*XXX*/
+ dev_free_name(tnp);
+ tp = NULL;
+ }
+ dev_add_name(tcnp->cn_nameptr,tdp,fnp->as.front.realthing,fp,&tnp);
+ fnp->dnp = NULL;
+ fp->links--; /* one less link to it.. */
+ dev_free_name(fnp);
+ fp->links--; /* we added one earlier*/
+ if (tdp)
+ vput(tdvp);
+ if (tp)
+ vput(fvp);
+ vrele(ap->a_fvp);
+ return (error);
+
+bad:
+ if (tp)
+ vput(tvp);
+ vput(tdvp);
+out:
+ if (VOP_LOCK(fvp) == 0) {
+ fp->links--; /* we added one earlier*/
+ vput(fvp);
+ } else
+ vrele(fvp);
+ return (error);
}
@@ -1227,7 +1462,7 @@ void devfs_dropvnode(dn_p dnp) /*proto*/
#define devfs_seek ((int (*) __P((struct vop_seek_args *)))nullop)
#define devfs_remove ((int (*) __P((struct vop_remove_args *)))devfs_enotsupp)
#define devfs_link ((int (*) __P((struct vop_link_args *)))devfs_enotsupp)
-#define devfs_rename ((int (*) __P((struct vop_rename_args *)))devfs_enotsupp)
+/*#define devfs_rename ((int (*) __P((struct vop_rename_args *)))devfs_enotsupp)*/
#define devfs_mkdir ((int (*) __P((struct vop_mkdir_args *)))devfs_enotsupp)
#define devfs_rmdir ((int (*) __P((struct vop_rmdir_args *)))devfs_enotsupp)
#define devfs_symlink ((int (*) __P((struct vop_symlink_args *)))devfs_enotsupp)
OpenPOWER on IntegriCloud