aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorJulian Elischer <julian@FreeBSD.org>1995-09-09 12:51:56 +0000
committerJulian Elischer <julian@FreeBSD.org>1995-09-09 12:51:56 +0000
commit564643c636cad5b25c4395bb7d6fb635e3e6c8db (patch)
tree6813a2a1c74c25564927ac74b5afd61416997c3f /sys
parent2bf07b2bd791b3309ef53173bc97cc5158f8aec4 (diff)
Notes
Diffstat (limited to 'sys')
-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 ff9adcd6c3ce..cdc68403be80 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 7e9d57e8fcc6..ae6b2d0acad7 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 2aba6c1f79aa..8d220efbdab3 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)