diff options
Diffstat (limited to 'sys/miscfs/devfs')
| -rw-r--r-- | sys/miscfs/devfs/README | 118 | ||||
| -rw-r--r-- | sys/miscfs/devfs/devfs_proto.h | 27 | ||||
| -rw-r--r-- | sys/miscfs/devfs/devfs_tree.c | 1297 | ||||
| -rw-r--r-- | sys/miscfs/devfs/devfs_vfsops.c | 313 | ||||
| -rw-r--r-- | sys/miscfs/devfs/devfs_vnops.c | 2014 | ||||
| -rw-r--r-- | sys/miscfs/devfs/devfsdefs.h | 203 | ||||
| -rw-r--r-- | sys/miscfs/devfs/reproto.sh | 45 |
7 files changed, 0 insertions, 4017 deletions
diff --git a/sys/miscfs/devfs/README b/sys/miscfs/devfs/README deleted file mode 100644 index fba4214b41af..000000000000 --- a/sys/miscfs/devfs/README +++ /dev/null @@ -1,118 +0,0 @@ -$FreeBSD$ - -this file is: /sys/miscfs/devfs/README - -to enable: add -options DEVFS - -to your config file.. -expect it to be highly useless for a while, -as the only devices that register themselves are the floppy, -the pcaudio stuff, speaker, null,mem,zero,io,kmem. - -it works like this: - -There is a tree of nodes that describe the layout of the DEVFS as seen by -the drivers.. they add nodes to this tree. This is called the 'back' layer -for reasons that will become obvious in a second. Think of it as a -BLUEPRINT of the DEVFS tree. Each back node has associated with it -a "devnode" struct, that holds information about the device -(or directory) and a pointer to the vnode if one has been associated -with that node. The back node itself can be considered to be -a directory entry, and contains the default name of the device, -and a link to the directory that holds it. It is sometimes refered -to in the code as the dev_name. The devnode can be considered the inode. - -When you mount the devfs somewhere (you can mount it multiple times in -multiple places), a front layer is created that contains a tree of 'front' -nodes. - -Think of this as a Transparency, layed over the top of the blueprint. -(or possibly a photocopy). - -The front and back nodes are identical in type, but the back nodes -are reserved for kernel use only, and are protected from the user. -The back plane has a mount structure and all that stuff, but it is in -fact not really mounted. (and is thus not reachable via namei). -Internal kernel routines can open devices in this plane -even if the external devfs has not been mounted yet :) -(e.g. to find the root device) - -To start with there is a 1:1 relationship between the front nodes -and the backing nodes, however once the front plane has been created -the nodes can be moved around within that plane (or deleted). -Think of this as the ability to revise a transparency... -the blueprint is untouched. - -There is a "devnode" struct associated with each front note also. -Front nodes that refer to devices, use the same "devnode" struct that is used -by their associated backing node, so that multiple front nodes that -point to the same device will use the same "devnode" struct, and through -that, the same vnode, ops, modification times, flags, owner and group. -Front nodes representing directories and symlinks have their own -"devnode" structs, and may therefore differ. (have different vnodes) -i.e. if you have two devfs trees mounted, you can change the -directories in one without changing the other. -e.g. remove or rename nodes - -Multiple mountings are like multiple transparencies, -each showing through to the original blueprint. - -Information that is to be shared between these mounts is stored -in the 'backing' node for that object. Once you have erased 'front' -object, there is no memory of where the backing object was, and -except for the possibility of searching the entire backing tree -for the node with the correct major/minor/type, I don't see that -it is easily recovered.. Particularly as there will eventually be -(I hope) devices that go direct from the backing node to the driver -without going via the cdevsw table.. they may not even have -major/minor numbers. - -I see 'mount -u' as a possible solution to recovering a broken dev tree. -(though umount+mount would do the same) - -Because non device nodes (directories and symlinks) have their own -"devnode" structs on each layer, these may have different -flags, owners, and contents on each layer. -e.g. if you have a chroot tree like erf.tfs.com has, you -may want different permissions or owners on the chroot mount of the DEVFS -than you want in the real one. You might also want to delete some sensitive -devices from the chroot tree. - -Directories also have backing nodes but there is nothing to stop -the user from removing a front node from the directory front node. -(except permissions of course). This is because the front directory -nodes keep their own records as to which front nodes are members -of that directory and do not refer to their original backing node -for this information. - -The front nodes may be moved to other directories (including -directories) however this does not break the linkage between the -backing nodes and the front nodes. The backing node never moves. If -a driver decides to remove a device from the backing tree, the FS -code follows the links to all the front nodes linked to that backing -node, and deletes them, no matter where they've been moved to. -(active vnodes are redirected to point to the deadfs). - -If a directory has been moved, and a new backing node is inserted -into its own back node, the new front node will appear in that front -directory, even though it's been moved, because the directory that -gets the front node is found via the links and not by name. - -a mount -u might be considered to be a request to 'refresh' the -plane that controls to the mount being updated.. that would have the -effect of 're-propogating' through any backing nodes that find they -have no front nodes in that plane. - - -NOTES FOR RELEASE 1.2 -1/ this is very preliminary -2/ the routines have greatly simplified since release 1.1 -(I guess the break did me good :) -3/ many features are not present yet.. -e.g. symlinks, a comprehensive registration interface (only a crude one) -ability to unlink and mv nodes. -4/ I'm pretty sure my use of vnodes is bad and it may be 'losing' -them, or alternatively, corrupting things.. I need a vnode specialist -to look at this. - diff --git a/sys/miscfs/devfs/devfs_proto.h b/sys/miscfs/devfs/devfs_proto.h deleted file mode 100644 index 846c48ecad85..000000000000 --- a/sys/miscfs/devfs/devfs_proto.h +++ /dev/null @@ -1,27 +0,0 @@ -/* $FreeBSD$ */ -/* THIS FILE HAS BEEN PRODUCED AUTOMATICALLY */ -void devfs_sinit(void *junk); -devnm_p dev_findname(dn_p dir,char *name); -int dev_finddir(char *orig_path, dn_p dirnode, int create, dn_p *dn_pp); -int dev_add_name(char *name, dn_p dirnode, devnm_p back, dn_p dnp, - devnm_p *devnm_pp); -int dev_add_node(int entrytype, union typeinfo *by, dn_p proto, - dn_p *dn_pp,struct devfsmount *dvm); -int dev_touch(devnm_p key) /* update the node for this dev */; -void devfs_dn_free(dn_p dnp); -int devfs_propogate(devnm_p parent,devnm_p child); -int dev_dup_plane(struct devfsmount *devfs_mp_p); -void devfs_free_plane(struct devfsmount *devfs_mp_p); -int dev_dup_entry(dn_p parent, devnm_p back, devnm_p *dnm_pp, - struct devfsmount *dvm); -int dev_free_name(devnm_p devnmp); -void dev_free_hier(devnm_p devnmp); -int devfs_vntodn(struct vnode *vn_p, dn_p *dn_pp); -int devfs_dntovn(dn_p dnp, struct vnode **vn_pp); -int dev_add_entry(char *name, dn_p parent, int type, union typeinfo *by, - dn_p proto, struct devfsmount *dvm, devnm_p *nm_pp); -int devfs_mount(struct mount *mp, char *path, caddr_t data, - struct nameidata *ndp, struct proc *p); -void devfs_dropvnode(dn_p dnp); -/* THIS FILE PRODUCED AUTOMATICALLY */ -/* DO NOT EDIT (see reproto.sh) */ diff --git a/sys/miscfs/devfs/devfs_tree.c b/sys/miscfs/devfs/devfs_tree.c deleted file mode 100644 index d47917a4804f..000000000000 --- a/sys/miscfs/devfs/devfs_tree.c +++ /dev/null @@ -1,1297 +0,0 @@ - -/* - * Copyright 1997,1998 Julian Elischer. All rights reserved. - * julian@freebsd.org - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - - -/* SPLIT_DEVS means each devfs uses a different vnode for the same device */ -/* Otherwise the same device always ends up at the same vnode even if */ -/* reached througgh a different devfs instance. The practical difference */ -/* is that with the same vnode, chmods and chowns show up on all instances of */ -/* a device. (etc) */ - -#define SPLIT_DEVS 1 /* maybe make this an option */ -/*#define SPLIT_DEVS 1*/ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/conf.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/proc.h> -#include <sys/vnode.h> -#include <sys/devfsext.h> - -#include <machine/stdarg.h> - -#include <miscfs/devfs/devfsdefs.h> - - -static MALLOC_DEFINE(M_DEVFSNODE, "DEVFS node", "DEVFS node"); -static MALLOC_DEFINE(M_DEVFSNAME, "DEVFS name", "DEVFS name"); - -static void devfs_add_to_tree(dev_t dev, uid_t uid, gid_t gid, int perms); -devnm_p dev_root; /* root of the backing tree */ -static struct mount *devfs_hidden_mount; -int devfs_up_and_going; - -/* - * Set up the root directory node in the backing plane - * This is happenning before the vfs system has been - * set up yet, so be careful about what we reference.. - * Notice that the ops are by indirection.. as they haven't - * been set up yet! - * DEVFS has a hidden mountpoint that is used as the anchor point - * for the internal 'blueprint' version of the dev filesystem tree. - */ -/*proto*/ -void -devfs_sinit(void *junk) -{ - int retval; /* we will discard this */ - - /* - * call the right routine at the right time with the right args.... - */ - retval = dev_add_entry("root", NULL, DEV_DIR, NULL, NULL, NULL, &dev_root); - devfs_create_hook = devfs_add_to_tree; -#ifdef PARANOID - if(retval) panic("devfs_sinit: dev_add_entry failed "); -#endif - devfs_hidden_mount = (struct mount *)malloc(sizeof(struct mount), - M_MOUNT,M_NOWAIT); -#ifdef PARANOID - if(!devfs_hidden_mount) panic("devfs_sinit: malloc failed"); -#endif - bzero(devfs_hidden_mount,sizeof(struct mount)); - devfs_mount(devfs_hidden_mount,"dummy",NULL,NULL,NULL); - dev_root->dnp->dvm = (struct devfsmount *)devfs_hidden_mount->mnt_data; - devfs_up_and_going = 1; - printf("DEVFS: ready for devices\n"); - /* part 2 of this is done later */ -} -SYSINIT(devfs, SI_SUB_DEVFS, SI_ORDER_FIRST, devfs_sinit, NULL) - - -/***********************************************************************\ -************************************************************************* -* Routines used to find our way to a point in the tree * -************************************************************************* -\***********************************************************************/ - - -/***************************************************************\ -* Search down the linked list off a dir to find "name" * -* return the dn_p for that node. -\***************************************************************/ -/*proto*/ -devnm_p -dev_findname(dn_p dir,char *name) -{ - devnm_p newfp; - DBPRINT((" dev_findname(%s)\n",name)); - if(dir->type != DEV_DIR) return 0;/*XXX*/ /* printf?*/ - - if(name[0] == '.') - { - if(name[1] == 0) - { - return dir->by.Dir.myname; - } - if((name[1] == '.') && (name[2] == 0)) - { - /* for root, .. == . */ - return dir->by.Dir.parent->by.Dir.myname; - } - } - newfp = dir->by.Dir.dirlist; - while(newfp) - { - if(!(strcmp(name,newfp->name))) - return newfp; - newfp = newfp->next; - } - return NULL; -} - -/***********************************************************************\ -* Given a starting node (0 for root) and a pathname, return the node * -* for the end item on the path. It MUST BE A DIRECTORY. If the 'CREATE' * -* option is true, then create any missing nodes in the path and create * -* and return the final node as well. * -* This is used to set up a directory, before making nodes in it.. * -* * -* Warning: This function is RECURSIVE. * -* char *orig_path, find this dir (err if not dir) * -* dn_p dirnode, starting point (0 = root) * -* int create, create path if not found * -* dn_p *dn_pp) where to return the node of the dir * -\***********************************************************************/ -/*proto*/ -int -dev_finddir(char *orig_path, dn_p dirnode, int create, dn_p *dn_pp) -{ - devnm_p devnmp; - dn_p dnp; - char pathbuf[DEVMAXPATHSIZE]; - char *path; - char *name; - register char *cp; - int retval; - - - DBPRINT(("dev_finddir\n")); - /***************************************\ - * If no parent directory is given * - * then start at the root of the tree * - \***************************************/ - if(!dirnode) dirnode = dev_root->dnp; - - /***************************************\ - * Sanity Checks * - \***************************************/ - if(dirnode->type != DEV_DIR) return ENOTDIR; - if(strlen(orig_path) > (DEVMAXPATHSIZE - 1)) return ENAMETOOLONG; - - - path = pathbuf; - strcpy(path,orig_path); - - /***************************************\ - * always absolute, skip leading / * - * get rid of / or // or /// etc. * - \***************************************/ - while(*path == '/') path++; - - /***************************************\ - * If nothing left, then parent was it.. * - \***************************************/ - if ( *path == '\0' ) { - *dn_pp = dirnode; - return 0; - } - - /***************************************\ - * find the next segment of the name * - \***************************************/ - cp = name = path; - while((*cp != '/') && (*cp != 0)) { - cp++; - } - - /***********************************************\ - * Check to see if it's the last component * - \***********************************************/ - if(*cp) { - path = cp + 1; /* path refers to the rest */ - *cp = 0; /* name is now a separate string */ - if(!(*path)) { - path = (char *)0; /* was trailing slash */ - } - } else { - path = NULL; /* no more to do */ - } - - /***************************************\ - * Start scanning along the linked list * - \***************************************/ - devnmp = dev_findname(dirnode,name); - if(devnmp) { /* check it's a directory */ - dnp = devnmp->dnp; - if(dnp->type != DEV_DIR) return ENOTDIR; - } else { - /***************************************\ - * The required element does not exist * - * So we will add it if asked to. * - \***************************************/ - if(!create) return ENOENT; - - if((retval = dev_add_entry(name, dirnode, DEV_DIR, - NULL, NULL, NULL, &devnmp)) != 0) { - return retval; - } - dnp = devnmp->dnp; - devfs_propogate(dirnode->by.Dir.myname,devnmp); - } - if(path != NULL) { /* decide whether to recurse more or return */ - return (dev_finddir(path,dnp,create,dn_pp)); - } else { - *dn_pp = dnp; - return 0; - } -} - - -/***********************************************************************\ -* Add a new NAME element to the devfs * -* If we're creating a root node, then dirname is NULL * -* Basically this creates a new namespace entry for the device node * -* * -* Creates a name node, and links it to the supplied node * -\***********************************************************************/ -/*proto*/ -int -dev_add_name(char *name, dn_p dirnode, devnm_p back, dn_p dnp, - devnm_p *devnm_pp) -{ - devnm_p devnmp; - - DBPRINT(("dev_add_name\n")); - if(dirnode != NULL ) { - if(dirnode->type != DEV_DIR) return(ENOTDIR); - - if( dev_findname(dirnode,name)) - return(EEXIST); - } - /* - * make sure the name is legal - * slightly misleading in the case of NULL - */ - if( !name || (strlen(name) > (DEVMAXNAMESIZE - 1))) - return (ENAMETOOLONG); - - /* - * Allocate and fill out a new directory entry - */ - if(!(devnmp = (devnm_p)malloc(sizeof(devnm_t), - M_DEVFSNAME, M_NOWAIT))) { - return ENOMEM; - } - bzero(devnmp,sizeof(devnm_t)); - - /* 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 "); - } - - /* - * Link the two together - * include the implicit link in the count of links to the devnode.. - * this stops it from being accidentally freed later. - */ - devnmp->dnp = dnp; - dnp->links++ ; /* implicit from our own name-node */ - - /* - * Make sure that we can find all the links that reference a node - * so that we can get them all if we need to zap the node. - */ - if(dnp->linklist) { - devnmp->nextlink = dnp->linklist; - devnmp->prevlinkp = devnmp->nextlink->prevlinkp; - devnmp->nextlink->prevlinkp = &(devnmp->nextlink); - *devnmp->prevlinkp = devnmp; - dnp->linklist = devnmp; - } else { - devnmp->nextlink = devnmp; - devnmp->prevlinkp = &(devnmp->nextlink); - dnp->linklist = devnmp; - } - - /* - * If the node is a directory, then we need to handle the - * creation of the .. link. - * A NULL dirnode indicates a root node, so point to ourself. - */ - if(dnp->type == DEV_DIR) { - dnp->by.Dir.myname = devnmp; - /* - * If we are unlinking from an old dir, decrement its links - * as we point our '..' elsewhere - * Note: it's up to the calling code to remove the - * us from the original directory's list - */ - 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 the name into the directory entry. - */ - strcpy(devnmp->name, name); - - - /* - * Check if we are not making a root node.. - * (i.e. have parent) - */ - if(dirnode) { - /* - * Put it on the END of the linked list of directory entries - */ - devnmp->parent = dirnode; /* null for root */ - devnmp->prevp = dirnode->by.Dir.dirlast; - devnmp->next = *(devnmp->prevp); /* should be NULL */ /*right?*/ - *(devnmp->prevp) = devnmp; - dirnode->by.Dir.dirlast = &(devnmp->next); - dirnode->by.Dir.entrycount++; - dirnode->len += strlen(name) + 8;/*ok, ok?*/ - } - - *devnm_pp = devnmp; - return 0 ; -} - - -/***********************************************************************\ -* Add a new element to the devfs plane. * -* * -* Creates a new dev_node to go with it if the prototype should not be * -* reused. (Is a DIR, or we select SPLIT_DEVS at compile time) * -* 'by' gives us info to make our node if we don't have a prototype. * -* If 'by is null and proto exists, then the 'by' field of * -* the proto is used intead in the CREATE case. * -* 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 * -* Even in SPLIT_DEVS mode, * -* if the node already exists on the wanted plane, just return it * -\***********************************************************************/ -/*proto*/ -int -dev_add_node(int entrytype, union typeinfo *by, dn_p proto, - dn_p *dn_pp,struct devfsmount *dvm) -{ - dn_p dnp; - - DBPRINT(("dev_add_node\n")); -#if defined SPLIT_DEVS - /* - * If we have a prototype, then check if there is already a sibling - * on the mount plane we are looking at, if so, just return it. - */ - if (proto) { - dnp = proto->nextsibling; - while( dnp != proto) { - if (dnp->dvm == dvm) { - *dn_pp = dnp; - return (0); - } - dnp = dnp->nextsibling; - } - if (by == NULL) - by = &(proto->by); - } -#else /* SPLIT_DEVS */ - if ( proto ) { - switch (proto->type) { - case DEV_BDEV: - case DEV_CDEV: - case DEV_DDEV: - *dn_pp = proto; - return 0; - } - } -#endif /* SPLIT_DEVS */ - if(!(dnp = (dn_p)malloc(sizeof(devnode_t), - M_DEVFSNODE, M_NOWAIT))) - { - return ENOMEM; - } - - /* - * If we have a proto, that means that we are duplicating some - * other device, which can only happen if we are not at the back plane - */ - if(proto) { - bcopy(proto, dnp, sizeof(devnode_t)); - dnp->links = 0; - dnp->linklist = NULL; - dnp->vn = NULL; - dnp->len = 0; - /* add to END of siblings list */ - dnp->prevsiblingp = proto->prevsiblingp; - *(dnp->prevsiblingp) = dnp; - dnp->nextsibling = proto; - proto->prevsiblingp = &(dnp->nextsibling); - } else { - /* - * We have no prototype, so start off with a clean slate - */ - bzero(dnp,sizeof(devnode_t)); - dnp->type = entrytype; - getnanotime(&(dnp->ctime)); - dnp->mtime = dnp->ctime; - dnp->atime = dnp->ctime; - dnp->nextsibling = dnp; - dnp->prevsiblingp = &(dnp->nextsibling); - } - dnp->dvm = dvm; - - /* - * 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; - case DEV_SLNK: - /* - * As it's a symlink allocate and store the link info - * Symlinks should only ever be created by the user, - * so they are not on the back plane and should not be - * propogated forward.. a bit like directories in that way.. - * A symlink only exists on one plane and has its own - * node.. therefore we might be on any random plane. - */ - dnp->by.Slnk.name = malloc(by->Slnk.namelen+1, - M_DEVFSNODE, M_NOWAIT); - if (!dnp->by.Slnk.name) { - free(dnp,M_DEVFSNODE); - return ENOMEM; - } - strncpy(dnp->by.Slnk.name,by->Slnk.name,by->Slnk.namelen); - dnp->by.Slnk.namelen = by->Slnk.namelen; - dnp->ops = &devfs_vnodeop_p; - dnp->mode |= 0555; /* default perms */ - break; - case DEV_BDEV: - /* - * Make sure it has DEVICE type ops - * and device specific fields are correct - */ - dnp->ops = &devfs_spec_vnodeop_p; - dnp->by.dev.dev = by->dev.dev; - break; - case DEV_CDEV: - /* - * Make sure it has DEVICE type ops - * and device specific fields are correct - */ - dnp->ops = &devfs_spec_vnodeop_p; - dnp->by.dev.dev = by->dev.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->by.Ddev.ops = by->Ddev.ops; - dnp->ops = by->Ddev.ops; - break; - default: - return EINVAL; - } - - *dn_pp = dnp; - return 0 ; -} - - -/*proto*/ -int -dev_touch(devnm_p key) /* update the node for this dev */ -{ - DBPRINT(("dev_touch\n")); - getnanotime(&(key->dnp->mtime)); - return 0; /*XXX*/ -} - -/*proto*/ -void -devfs_dn_free(dn_p dnp) -{ - if(--dnp->links <= 0 ) /* can be -1 for initial free, on error */ - { - /*probably need to do other cleanups XXX */ - if (dnp->nextsibling != dnp) { - dn_p* prevp = dnp->prevsiblingp; - *prevp = dnp->nextsibling; - dnp->nextsibling->prevsiblingp = prevp; - - } - if(dnp->type == DEV_SLNK) { - free(dnp->by.Slnk.name,M_DEVFSNODE); - } - devfs_dropvnode(dnp); - free (dnp, M_DEVFSNODE); - } -} - -/***********************************************************************\ -* Front Node Operations * -* Add or delete a chain of front nodes * -\***********************************************************************/ - -/***********************************************************************\ -* Given a directory backing node, and a child backing node, add the * -* appropriate front nodes to the front nodes of the directory to * -* represent the child node to the user * -* * -* on failure, front nodes will either be correct or not exist for each * -* front dir, however dirs completed will not be stripped of completed * -* frontnodes on failure of a later frontnode * -* * -* This allows a new node to be propogated through all mounted planes * -* * -\***********************************************************************/ -/*proto*/ -int -devfs_propogate(devnm_p parent,devnm_p child) -{ - int error; - devnm_p newnmp; - dn_p dnp = child->dnp; - dn_p pdnp = parent->dnp; - dn_p adnp = parent->dnp; - int type = child->dnp->type; - - DBPRINT((" devfs_propogate\n")); - /***********************************************\ - * Find the other instances of the parent node * - \***********************************************/ - for (adnp = pdnp->nextsibling; - adnp != pdnp; - adnp = adnp->nextsibling) - { - /* - * Make the node, using the original as a prototype) - * if the node already exists on that plane it won't be - * re-made.. - */ - if ((error = dev_add_entry(child->name, adnp, type, - NULL, dnp, adnp->dvm, &newnmp)) != 0) { - printf("duplicating %s failed\n",child->name); - } - } - 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) - * then the devfs_node will still exist as the ref count will be non-0 - * removing a directory node will remove all sup-nodes on all planes (ZAP) - * - * Used by device drivers to remove nodes that are no longer relevant - * The argument is the 'cookie' they were given when they created the node - * this function is exported.. see sys/devfsext.h - ***********************************************************************/ -void -devfs_remove_dev(void *devnmp) -{ - dn_p dnp = ((devnm_p)devnmp)->dnp; - dn_p dnp2; - - DBPRINT(("devfs_remove_dev\n")); - /* keep removing the next sibling till only we exist. */ - while((dnp2 = dnp->nextsibling) != dnp) { - - /* - * Keep removing the next front node till no more exist - */ - dnp->nextsibling = dnp2->nextsibling; - dnp->nextsibling->prevsiblingp = &(dnp->nextsibling); - dnp2->nextsibling = dnp2; - dnp2->prevsiblingp = &(dnp2->nextsibling); - while(dnp2->linklist) - { - dev_free_name(dnp2->linklist); - } - } - - /* - * then free the main node - * If we are not running in SPLIT_DEVS mode, then - * THIS is what gets rid of the propogated nodes. - */ - while(dnp->linklist) - { - dev_free_name(dnp->linklist); - } - return ; -} - - -/*************************************************************** - * duplicate the backing tree into a tree of nodes hung off the - * mount point given as the argument. Do this by - * calling dev_dup_entry which recurses all the way - * up the tree.. - * If we are the first plane, just return the base root - **************************************************************/ -/*proto*/ -int -dev_dup_plane(struct devfsmount *devfs_mp_p) -{ - devnm_p new; - int error = 0; - - DBPRINT((" dev_dup_plane\n")); - if(devfs_up_and_going) { - if((error = dev_dup_entry(NULL, dev_root, &new, devfs_mp_p)) != 0) { - return error; - } - } else { /* we are doing the dummy mount during initialisation.. */ - new = dev_root; - } - devfs_mp_p->plane_root = new; - - return error; -} - - - -/***************************************************************\ -* Free a whole plane -\***************************************************************/ -/*proto*/ -void -devfs_free_plane(struct devfsmount *devfs_mp_p) -{ - devnm_p devnmp; - - DBPRINT((" devfs_free_plane\n")); - devnmp = devfs_mp_p->plane_root; - if(devnmp) { - dev_free_hier(devnmp); - dev_free_name(devnmp); - } - devfs_mp_p->plane_root = NULL; -} - -/***************************************************************\ -* Create and link in a new front element.. * -* Parent can be 0 for a root node * -* Not presently usable to make a symlink XXX * -* (Ok, symlinks don't propogate) -* recursively will create subnodes corresponding to equivalent * -* child nodes in the base level * -\***************************************************************/ -/*proto*/ -int -dev_dup_entry(dn_p parent, devnm_p back, devnm_p *dnm_pp, - struct devfsmount *dvm) -{ - devnm_p newnmp; - devnm_p newback; - devnm_p newfront; - int error; - dn_p dnp = back->dnp; - int type = dnp->type; - - DBPRINT((" dev_dup_entry\n")); - /* - * go get the node made (if we need to) - * use the back one as a prototype - */ - if ((error = dev_add_entry(back->name, parent, type, - NULL, dnp, - parent?parent->dvm:dvm, &newnmp)) != 0) { - printf("duplicating %s failed\n",back->name); - } - - /* - * If we have just made the root, then insert the pointer to the - * mount information - */ - if(dvm) { - newnmp->dnp->dvm = dvm; - } - - /* - * If it is a directory, then recurse down all the other - * subnodes in it.... - * note that this time we don't pass on the mount info.. - */ - if (type == DEV_DIR) - { - for(newback = back->dnp->by.Dir.dirlist; - newback; newback = newback->next) - { - if((error = dev_dup_entry(newnmp->dnp, - newback, &newfront, NULL)) != 0) - { - break; /* back out with an error */ - } - } - } - *dnm_pp = newnmp; - return error; -} - -/***************************************************************\ -* Free a name 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 * -\***************************************************************/ -/*proto*/ -int -dev_free_name(devnm_p devnmp) -{ - dn_p parent = devnmp->parent; - dn_p dnp = devnmp->dnp; - - DBPRINT((" dev_free_name\n")); - if(dnp) { - if(dnp->type == DEV_DIR) - { - if(dnp->by.Dir.dirlist) - return (ENOTEMPTY); - devfs_dn_free(dnp); /* account for '.' */ - devfs_dn_free(dnp->by.Dir.parent); /* '..' */ - } - /* - * unlink us from the list of links for this node - * If we are the only link, it's easy! - * if we are a DIR of course there should not be any - * other links. - */ - if(devnmp->nextlink == devnmp) { - dnp->linklist = NULL; - } else { - if(dnp->linklist == devnmp) { - dnp->linklist = devnmp->nextlink; - } - devnmp->nextlink->prevlinkp = devnmp->prevlinkp; - *devnmp->prevlinkp = devnmp->nextlink; - } - devfs_dn_free(dnp); - } - - /* - * unlink ourselves from the directory on this plane - */ - if(parent) /* if not fs root */ - { - if( (*devnmp->prevp = devnmp->next) )/* yes, assign */ - { - devnmp->next->prevp = devnmp->prevp; - } - else - { - parent->by.Dir.dirlast - = devnmp->prevp; - } - parent->by.Dir.entrycount--; - parent->len -= strlen(devnmp->name) + 8; - } - - /***************************************************************\ - * If the front node has its own devnode structure, * - * then free it. * - \***************************************************************/ - free(devnmp,M_DEVFSNAME); - return 0; -} - -/***************************************************************\ -* Free a hierarchy starting at a directory node name * -* 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 * -* leave the node itself allocated. * -\***************************************************************/ -/*proto*/ -void -dev_free_hier(devnm_p devnmp) -{ - dn_p dnp = devnmp->dnp; - - DBPRINT((" dev_free_hier\n")); - if(dnp) { - if(dnp->type == DEV_DIR) - { - while(dnp->by.Dir.dirlist) - { - dev_free_hier(dnp->by.Dir.dirlist); - dev_free_name(dnp->by.Dir.dirlist); - } - } - } -} - -/*******************************************************\ -********************************************************* -* ROUTINES to control the connection between devfs * -* nodes and the system's vnodes * -********************************************************* -\*******************************************************/ - -/*******************************************************\ -* Theoretically this could be called for any kind of * -* vnode, however in practice it must be a DEVFS vnode * -\*******************************************************/ -/*proto*/ -int -devfs_vntodn(struct vnode *vn_p, dn_p *dn_pp) -{ - -DBPRINT((" vntodn ")); - if(vn_p->v_tag != VT_DEVFS) - { - printf("bad-tag2 "); - Debugger("bad-tag "); - return(EINVAL); - } -#if 0 - /* - * XXX: This is actually a "normal" case when vclean calls us without - * XXX: incrementing the reference count first. - */ - if(vn_p->v_usecount == 0) - { - printf("No references! "); - } -#endif - switch(vn_p->v_type) { - case VBAD: - printf("bad-type2 (VBAD)"); - return(EINVAL); -#if 0 - case VNON: - printf("bad-type2 (VNON)"); - return(EINVAL); -#endif - default: - break; - } - *dn_pp = (dn_p)vn_p->v_data; - - return(0); -} - -/***************************************************************\ -* given a dev_node, find the appropriate vnode if one is already* -* associated, or get a new one an associate it with the dev_node* -* need to check about vnode references.. should we increment it?* -\***************************************************************/ -/*proto*/ -int -devfs_dntovn(dn_p dnp, struct vnode **vn_pp) -{ - struct vnode *vn_p; - int error = 0; - struct proc *p = curproc; /* XXX */ - - vn_p = dnp->vn; -DBPRINT(("dntovn ")); - if( vn_p) - { - if(vn_p->v_id != dnp->vn_id) - { -#if 0 - /* XXX: This is `normal'... */ - printf("bad-id "); -#endif - goto skip; - } - if(vn_p->v_tag != VT_DEVFS) - { -#if 0 - /* XXX: This is `normal'... */ - printf("bad-tag "); -#endif - goto skip; - } - if(vn_p->v_op != *(dnp->ops)) - { - printf("bad-ops "); - goto skip; - } - if((dn_p)(vn_p->v_data) != dnp) - { - printf("bad-rev_link "); - goto skip; - } - if(vn_p->v_type != VNON) - { - vget(vn_p, LK_EXCLUSIVE, p); - *vn_pp = vn_p; - return(0); - } - else - { - printf("bad-type"); - } -skip: - vn_p = (struct vnode *) 0; - } - if(!(error = getnewvnode(VT_DEVFS, - dnp->dvm->mount, - *(dnp->ops), - &vn_p))) - { - dnp->vn = vn_p; - dnp->vn_id = vn_p->v_id; - *vn_pp = vn_p; -DBPRINT(("(New vnode)")); - switch(dnp->type) - { - case DEV_SLNK: - vn_p->v_type = VLNK; - break; - case DEV_DIR: - if(dnp->by.Dir.parent == dnp) - { - vn_p->v_flag |= VROOT; - } - vn_p->v_type = VDIR; - break; - case DEV_BDEV: - vn_p->v_type = VBLK; - addalias(vn_p, dnp->by.dev.dev); - break; - case DEV_CDEV: - vn_p->v_type = VCHR; - addalias(vn_p, dnp->by.dev.dev); - break; - case DEV_DDEV: - break; - } - if ( vn_p) - { - vn_p->v_mount = dnp->dvm->mount;/* XXX Duplicated */ - *vn_pp = vn_p; - vn_p->v_data = (void *)dnp; - } - else - { - error = EINVAL; - } - vn_lock(vn_p, LK_EXCLUSIVE | LK_RETRY, p); - } - return error; -} - -/***********************************************************************\ -* add a whole device, with no prototype.. make name element and node * -* Used for adding the original device entries * -\***********************************************************************/ -/*proto*/ -int -dev_add_entry(char *name, dn_p parent, int type, union typeinfo *by, - dn_p proto, struct devfsmount *dvm, devnm_p *nm_pp) -{ - dn_p dnp; - int error = 0; - - DBPRINT((" devfs_add_entry\n")); - if ((error = dev_add_node(type, by, proto, &dnp, - (parent?parent->dvm:dvm))) != 0) - { - printf("Device %s: base node allocation failed (Errno=%d)\n", - name,error); - return error; - } - if ((error = dev_add_name(name ,parent ,NULL, dnp, nm_pp)) != 0) - { - devfs_dn_free(dnp); /* 1->0 for dir, 0->(-1) for other */ - printf("Device %s: name slot allocation failed (Errno=%d)\n", - name,error); - - } - return error; -} - -static void -devfs_add_to_tree(dev_t dev, uid_t uid, gid_t gid, int perms) -{ - - struct cdevsw *devsw = dev->si_devsw; - - dev->si_devfs = devfs_add_devswf(dev->si_devsw, minor(dev), DV_CHR, - uid, gid, perms, "%s", dev->si_name ); - - /* XXX HACK .. name may not start in 'r' */ - if ((devsw->d_bmaj != -1) - && (dev->si_name[0] == 'r') - && ((devsw->d_flags & D_TYPEMASK) == D_DISK)) { - dev->si_bdevfs = devfs_add_devswf(devsw, minor(dev), DV_BLK, - uid, gid, perms, dev->si_name + 1); - } -} -/***********************************************************************\ -* Add the named device entry into the given directory, and make it * -* The appropriate type... (called (sometimes indirectly) by drivers..) * -* this function is exported.. see sys/devfsext.h * -* Has the capacity to take printf type arguments to format the device * -* names * -\***********************************************************************/ -void * -devfs_add_devswf(void *devsw, int minor, int chrblk, uid_t uid, - gid_t gid, int perms, char *fmt, ...) -{ - int major; - devnm_p new_dev; - dn_p dnp; /* devnode for parent directory */ - int retval; - union typeinfo by; - struct cdevsw *cd; - - va_list ap; - char *name, *path, buf[256]; /* XXX */ - int i; - - va_start(ap, fmt); - i = kvprintf(fmt, NULL, (void*)buf, 32, ap); - va_end(ap); - buf[i] = '\0'; - name = NULL; - - for(i=strlen(buf); i>0; i--) - if(buf[i] == '/') { - name=&buf[i]; - buf[i]=0; - break; - } - - if (name) { - *name++ = '\0'; - path = buf; - } else { - name = buf; - path = "/"; - } - - DBPRINT(("dev_add\n")); - retval = dev_finddir(path,NULL,1,&dnp); - if (retval) return 0; - switch(chrblk) - { - case DV_CHR: - cd = devsw; - major = cd->d_maj; - if ( major == -1 ) return NULL; - by.dev.dev = makedev(major, minor); - if( dev_add_entry(name, dnp, DEV_CDEV, &by, NULL, NULL, &new_dev)) - return NULL; - break; - case DV_BLK: - cd = devsw; - major = cd->d_bmaj; - if ( major == -1 ) return NULL; - by.dev.dev = makebdev(major, minor); - if( dev_add_entry(name, dnp, DEV_BDEV, &by, NULL, NULL, &new_dev)) - return NULL; - break; - default: - return NULL; - } - new_dev->dnp->gid = gid; - new_dev->dnp->uid = uid; - new_dev->dnp->mode |= perms; - devfs_propogate(dnp->by.Dir.myname,new_dev); - 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.. * -* this function is exported.. see sys/devfsext.h * -\***********************************************************************/ -void * -devfs_makelink(void *original, char *fmt, ...) -{ - devnm_p new_dev; - devnm_p orig = (devnm_p) original; - dn_p dirnode; /* devnode for parent directory */ - int retval; - - va_list ap; - char *p, buf[256]; /* XXX */ - int i; - - va_start(ap, fmt); - i = kvprintf(fmt, NULL, (void*)buf, 32, ap); - va_end(ap); - buf[i] = '\0'; - p = NULL; - - for(i=strlen(buf); i>0; i--) - if(buf[i] == '/') { - p=&buf[i]; - buf[i]=0; - break; - } - - DBPRINT(("dev_add\n")); - - /* - * The DEV_CDEV below is not used other than it must NOT be DEV_DIR - * the correctness of original should be checked.. - */ - - if (p) { - *p++ = '\0'; - retval = dev_finddir(buf,NULL,1,&dirnode); - if (retval) return 0; - if( dev_add_name(p, dirnode, NULL, orig->dnp, &new_dev)) - return NULL; - } else { - retval = dev_finddir("/",NULL,1,&dirnode); - if (retval) return 0; - if( dev_add_name(buf, dirnode, NULL, orig->dnp, &new_dev)) - return NULL; - } - devfs_propogate(dirnode->by.Dir.myname,new_dev); - return new_dev; -} - -/* - * internal kernel call to open a device. Return either 0 or an open vnode. - */ -struct vnode * -devfs_open_device(char *path, int type) -{ - register char *lastslash; - char *nextpart; - devnm_p nm_p; - dn_p dirnode; - struct vnode *vn; - - /* - * If the caller didn't supply a full path, ignore and be - * noisy about it. - */ - if (*path != '/') { - printf (__FUNCTION__ ": caller supplied bad path\n"); - return (NULL); - } - - /* - * find the last '/'. Unfortunatly rindex() while being in - * libkern source, is not being compiled.. do it by hand. - * lastslash = strrchr(path,(int)'c'); - * There will be at LEAST one '/'. - */ - { - register char *p = path; /* don't destroy path */ - - for (lastslash = NULL;*p; ++p) { - if (*p == '/') - lastslash = p; - } - } - dirnode = dev_root->dnp; - if(lastslash != path) { - /* find the directory we need */ - *lastslash = '\0'; - if (dev_finddir(path, dirnode, NULL, &dirnode) != 0) { - *lastslash = '/'; - return (NULL); - } - /* ok we found the directory, put the slash back */ - *lastslash = '/'; - } - nextpart = ++lastslash; - if (*nextpart == '\0') - return (NULL); - /* - * Now only return true if it exists and is the right type. - */ - if ((nm_p = dev_findname(dirnode, nextpart)) == NULL) { - return (NULL); - } - switch(type) { - case DV_BLK: - if( nm_p->dnp->type != DEV_BDEV) - return (NULL); - break; - case DV_CHR: - if( nm_p->dnp->type != DEV_CDEV) - return (NULL); - break; - } - - if ( devfs_dntovn(nm_p->dnp, &vn)) - return (NULL); - -#if 0 - if ( VOP_OPEN(vn, FREAD, proc0.p_ucred, &proc0)) { - vput(vn); - return (NULL); - } -#endif - return (vn); -} - -/* - * internal kernel call to close a devfs device. - * It should have been openned by th ecall above. - * try not mix it with user-openned vnodes. - * Frees the vnode. - */ -void -devfs_close_device(struct vnode *vn) -{ -#if 0 - VOP_CLOSE(vn, 0, proc0.p_ucred, &proc0) ; -#endif - vput(vn); -} - -#if 0 -/* - * Little utility routine for compatibilty. - * Returns the dev_t that a devfs vnode represents. - * should go away after dev_t go away :). - */ -dev_t -devfs_vntodev(struct vnode *vn) -{ - register dn_p dnp; - dnp = (dn_p)vn->v_data; - switch (dnp->type) { - case DEV_BDEV: - return (dnp->by.dev.dev); - break; - case DEV_CDEV: - return (dnp->by.dev.dev); - break; - } - panic ("bad devfs DEVICE vnode"); -} -#endif diff --git a/sys/miscfs/devfs/devfs_vfsops.c b/sys/miscfs/devfs/devfs_vfsops.c deleted file mode 100644 index f440a83244e9..000000000000 --- a/sys/miscfs/devfs/devfs_vfsops.c +++ /dev/null @@ -1,313 +0,0 @@ -/*- - * Copyright 1997,1998 Julian Elischer. All rights reserved. - * julian@freebsd.org - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - * - */ - - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/vnode.h> -#include <sys/mount.h> -#include <sys/malloc.h> - -#include <miscfs/devfs/devfsdefs.h> - -static MALLOC_DEFINE(M_DEVFSMNT, "DEVFS mount", "DEVFS mount structure"); - -static int devfs_statfs( struct mount *mp, struct statfs *sbp, struct proc *p); - -/*- - * Called from the generic VFS startups. - * This is the second stage of DEVFS initialisation. - * The probed devices have already been loaded and the - * basic structure of the DEVFS created. - * We take the oportunity to mount the hidden DEVFS layer, so that - * devices from devfs get sync'd. - */ -static int -devfs_init(struct vfsconf *vfsp) -{ - struct mount *mp = dev_root->dnp->dvm->mount; - /*- - * fill in the missing members on the "hidden" mount - * we could almost use vfs_rootmountalloc() to do this. - */ - lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0); - mp->mnt_op = vfsp->vfc_vfsops; - mp->mnt_vfc = vfsp; - mp->mnt_stat.f_type = vfsp->vfc_typenum; - mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; - strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); - mp->mnt_vnodecovered = NULLVP; - - /* Mark a reference for the "invisible" blueprint mount */ - mp->mnt_vfc->vfc_refcount++; - TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); - - printf("DEVFS: ready to run\n"); - return 0; /*XXX*/ -} - -/*- - * mp - pointer to 'mount' structure - * path - addr in user space of mount point (ie /usr or whatever) - * data - addr in user space of mount params including the - * name of the block special file to treat as a filesystem. - * ndp - namei data pointer - * p - proc pointer - * devfs is special in that it doesn't require any device to be mounted.. - * It makes up its data as it goes along. - * it must be mounted during single user.. until it is, only std{in/out/err} - * and the root filesystem are available. - */ -/*proto*/ -int -devfs_mount(struct mount *mp, char *path, caddr_t data, - struct nameidata *ndp, struct proc *p) -{ - struct devfsmount *devfs_mp_p; /* devfs specific mount info */ - int error; - u_int size; - -DBPRINT(("mount ")); - - /*- - * If they just want to update, we don't need to do anything. - */ - if (mp->mnt_flag & MNT_UPDATE) - { - return 0; - } - - /*- - * Well, it's not an update, it's a real mount request. - * Time to get dirty. - * HERE we should check to see if we are already mounted here. - */ - - devfs_mp_p = (struct devfsmount *)malloc(sizeof *devfs_mp_p, - M_DEVFSMNT, M_WAITOK); - if (devfs_mp_p == NULL) - return (ENOMEM); - bzero(devfs_mp_p,sizeof(*devfs_mp_p)); - devfs_mp_p->mount = mp; - - /*- - * Fill out some fields - */ - mp->mnt_data = (qaddr_t)devfs_mp_p; - if (mp->mnt_vfc == NULL) - mp->mnt_stat.f_type = -1; /* doing hidden mountpoint */ - else - mp->mnt_stat.f_type = mp->mnt_vfc->vfc_typenum; - mp->mnt_stat.f_fsid.val[0] = (intptr_t)(void *)devfs_mp_p; - mp->mnt_stat.f_fsid.val[1] = mp->mnt_stat.f_type; - mp->mnt_flag |= MNT_LOCAL; - - if((error = dev_dup_plane(devfs_mp_p)) != 0) - { - mp->mnt_data = (qaddr_t)0; - free((caddr_t)devfs_mp_p, M_DEVFSMNT); - return (error); - } - - /*- - * Copy in the name of the directory the filesystem - * is to be mounted on. - * And we clear the remainder of the character strings - * to be tidy. - * Then, we try to fill in the filesystem stats structure - * as best we can with whatever we can think of at the time - */ - - if(devfs_up_and_going) { - copyinstr(path, (caddr_t)mp->mnt_stat.f_mntonname, - sizeof(mp->mnt_stat.f_mntonname)-1, &size); - bzero(mp->mnt_stat.f_mntonname + size, - sizeof(mp->mnt_stat.f_mntonname) - size); - } else { - bcopy("dummy_mount", (caddr_t)mp->mnt_stat.f_mntonname,12); - } - bzero(mp->mnt_stat.f_mntfromname , MNAMELEN ); - bcopy("devfs",mp->mnt_stat.f_mntfromname, 5); - (void)devfs_statfs(mp, &mp->mnt_stat, p); - return 0; -} - - -/*- - * Unmount the filesystem described by mp. - */ -static int -devfs_unmount( struct mount *mp, int mntflags, struct proc *p) -{ - struct devfsmount *devfs_mp_p = (struct devfsmount *)mp->mnt_data; - int flags = 0; - int error; - - if (mntflags & MNT_FORCE) { - flags |= FORCECLOSE; - } - error = vflush(mp, NULLVP, flags); - if (error) - return error; - -DBPRINT(("unmount ")); - devfs_free_plane(devfs_mp_p); - free((caddr_t)devfs_mp_p, M_DEVFSMNT); - mp->mnt_data = (qaddr_t)0; - mp->mnt_flag &= ~MNT_LOCAL; - - return 0; -} - -/* return the address of the root vnode in *vpp */ -static int -devfs_root(struct mount *mp, struct vnode **vpp) -{ - struct devfsmount *devfs_mp_p = (struct devfsmount *)(mp->mnt_data); - -DBPRINT(("root ")); - devfs_dntovn(devfs_mp_p->plane_root->dnp,vpp); - return 0; -} - -static int -devfs_statfs( struct mount *mp, struct statfs *sbp, struct proc *p) -{ - struct devfsmount *devfs_mp_p = (struct devfsmount *)mp->mnt_data; - -/*- - * Fill in the stat block. - */ -DBPRINT(("statfs ")); - sbp->f_type = mp->mnt_stat.f_type; - sbp->f_flags = 0; /* XXX */ - sbp->f_bsize = 128; - sbp->f_iosize = 1024; /* XXX*/ - sbp->f_blocks = 128; - sbp->f_bfree = 0; - sbp->f_bavail = 0; - sbp->f_files = 128; - sbp->f_ffree = 0; /* what to put in here? */ - sbp->f_fsid.val[0] = (intptr_t)(void *)devfs_mp_p; - sbp->f_fsid.val[1] = mp->mnt_stat.f_type; - -/*- - * Copy the mounted on and mounted from names into - * the passed in stat block, if it is not the one - * in the mount structure. - */ - if (sbp != &mp->mnt_stat) { - bcopy((caddr_t)mp->mnt_stat.f_mntonname, - (caddr_t)&sbp->f_mntonname[0], MNAMELEN); - bcopy((caddr_t)mp->mnt_stat.f_mntfromname, - (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); - } - return 0; -} - -/*- - * Go through the disk queues to initiate sandbagged IO; - * go through the inodes to write those that have been modified; - * initiate the writing of the super block if it has been modified. - * - * Note: we are always called with the filesystem marked `MPBUSY'. - */ -static int -devfs_sync(struct mount *mp, int waitfor,struct ucred *cred,struct proc *p) -{ - register struct vnode *vp, *nvp; - int error, allerror = 0; - -DBPRINT(("sync ")); - - /*- - * Write back modified superblock. - * Consistency check that the superblock - * is still in the buffer cache. - */ - /*- - * Write back each (modified) inode. - */ -loop: - for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { - /*- - * If the vnode that we are about to sync is no longer - * associated with this mount point, start over. - */ - if (vp->v_mount != mp) - goto loop; - nvp = vp->v_mntvnodes.le_next; - if (VOP_ISLOCKED(vp, NULL)) - continue; - if (TAILQ_EMPTY(&vp->v_dirtyblkhd)) - continue; - if (vp->v_type == VBLK) { - if (vget(vp, LK_EXCLUSIVE, p)) - goto loop; - error = VOP_FSYNC(vp, cred, waitfor, p); - if (error) - allerror = error; - vput(vp); - } -#ifdef NOTYET - else { - struct timeval tv; - - tv = time; - /* VOP_UPDATE(vp, &tv, &tv, waitfor == MNT_WAIT); */ - VOP_UPDATE(vp, &tv, &tv, 0); - } -#endif - } - /*- - * Force stale file system control information to be flushed. - *( except that htat makes no sense with devfs - */ - return (allerror); -} - -static struct vfsops devfs_vfsops = { - devfs_mount, - vfs_stdstart, - devfs_unmount, - devfs_root, - vfs_stdquotactl, - devfs_statfs, - devfs_sync, - vfs_stdvget, - vfs_stdfhtovp, - vfs_stdcheckexp, - vfs_stdvptofh, - devfs_init, - vfs_stduninit, - vfs_stdextattrctl, -}; - -VFS_SET(devfs_vfsops, devfs, 0); diff --git a/sys/miscfs/devfs/devfs_vnops.c b/sys/miscfs/devfs/devfs_vnops.c deleted file mode 100644 index 9a9c1204c71c..000000000000 --- a/sys/miscfs/devfs/devfs_vnops.c +++ /dev/null @@ -1,2014 +0,0 @@ -/* - * Copyright 1997,1998 Julian Elischer. All rights reserved. - * julian@freebsd.org - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/bio.h> -#include <sys/buf.h> -#include <sys/namei.h> -#include <sys/kernel.h> -#include <sys/fcntl.h> -#include <sys/conf.h> -#include <sys/lock.h> -#include <sys/stat.h> -#include <sys/mount.h> -#include <sys/proc.h> -#include <sys/time.h> -#include <sys/vnode.h> -#include <sys/dirent.h> -#include <miscfs/devfs/devfsdefs.h> -#include <sys/vmmeter.h> - -#include <vm/vm.h> -#include <vm/vm_object.h> -#include <vm/vm_page.h> -#include <vm/vm_pager.h> - - -/* - * Insert description here - */ - - -/* - * Convert a component of a pathname into a pointer to a locked node. - * This is a very central and rather complicated routine. - * If the file system is not maintained in a strict tree hierarchy, - * this can result in a deadlock situation (see comments in code below). - * - * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on - * whether the name is to be looked up, created, renamed, or deleted. - * When CREATE, RENAME, or DELETE is specified, information usable in - * creating, renaming, or deleting a directory entry may be calculated. - * If flag has LOCKPARENT or'ed into it and the target of the pathname - * exists, lookup returns both the target and its parent directory locked. - * When creating or renaming and LOCKPARENT is specified, the target may - * not be ".". When deleting and LOCKPARENT is specified, the target may - * be "."., but the caller must check to ensure it does an vrele and DNUNLOCK - * instead of two DNUNLOCKs. - * - * Overall outline of devfs_lookup: - * - * check accessibility of directory - * null terminate the component (lookup leaves the whole string alone) - * look for name in cache, if found, then if at end of path - * and deleting or creating, drop it, else return name - * search for name in directory, to found or notfound - * notfound: - * if creating, return locked directory, - * else return error - * found: - * if at end of path and deleting, return information to allow delete - * if at end of path and rewriting (RENAME and LOCKPARENT), lock target - * node and return info to allow rewrite - * if not at end, add name to cache; if at end and neither creating - * nor deleting, add name to cache - * On return to lookup, remove the null termination we put in at the start. - * - * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent node unlocked. - */ -static int -devfs_lookup(struct vop_lookup_args *ap) - /*struct vop_lookup_args { - struct vnode * a_dvp; directory vnode ptr - struct vnode ** a_vpp; where to put the result - struct componentname * a_cnp; the name we want - };*/ -{ - struct componentname *cnp = ap->a_cnp; - struct vnode *dir_vnode = ap->a_dvp; - 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; - int wantparent = flags & (LOCKPARENT|WANTPARENT); - int error = 0; - struct proc *p = cnp->cn_proc; - char heldchar; /* the char at the end of the name componet */ - - *result_vnode = NULL; /* safe not sorry */ /*XXX*/ - -DBPRINT(("lookup\n")); - - if (dir_vnode->v_usecount == 0) - printf("dir had no refs "); - if (devfs_vntodn(dir_vnode,&dir_node)) - { - printf("vnode has changed?\n"); - vprint("=",dir_vnode); - return(EINVAL); - } - - /* - * Check accessiblity of directory. - */ - if (dir_node->type != DEV_DIR) /* XXX or symlink? */ - { - return (ENOTDIR); - } - if ((error = VOP_ACCESS(dir_vnode, VEXEC, cnp->cn_cred, p)) != 0) - { - return (error); - } - - /* - * We now have a segment name to search for, and a directory to search. - * - */ - -/***********************************************************************\ -* SEARCH FOR NAME * -* while making sure the component is null terminated for the strcmp * -\***********************************************************************/ - - heldchar = cnp->cn_nameptr[cnp->cn_namelen]; - cnp->cn_nameptr[cnp->cn_namelen] = '\0'; - new_nodename = dev_findname(dir_node,cnp->cn_nameptr); - cnp->cn_nameptr[cnp->cn_namelen] = heldchar; - if(!new_nodename) { - /*******************************************************\ - * Failed to find it.. (That may be good) * - \*******************************************************/ - new_node = NULL; /* to be safe */ - /* - * If creating, and at end of pathname - * then can consider - * allowing file to be created. - */ - if (!(flags & ISLASTCN) || !(op == CREATE || op == RENAME)) { - return ENOENT; - } - /* - * Access for write is interpreted as allowing - * creation of files in the directory. - */ - if ((error = VOP_ACCESS(dir_vnode, VWRITE, - cnp->cn_cred, p)) != 0) - { -DBPRINT(("MKACCESS ")); - return (error); - } - /* - * We return with the directory locked, so that - * the parameters we set up above will still be - * valid if we actually decide to add a new entry. - * We return ni_vp == NULL to indicate that the entry - * does not currently exist; we leave a pointer to - * the (locked) directory vnode in namei_data->ni_dvp. - * The pathname buffer is saved so that the name - * can be obtained later. - * - * NB - if the directory is unlocked, then this - * information cannot be used. - */ - cnp->cn_flags |= SAVENAME; /*XXX why? */ - if (!lockparent) - VOP_UNLOCK(dir_vnode, 0, p); - return (EJUSTRETURN); - } - - /***************************************************************\ - * Found it.. this is not always a good thing.. * - \***************************************************************/ - new_node = new_nodename->dnp; - new_node->last_lookup = new_nodename; /* for unlink */ - /* - * If deleting, and at end of pathname, return - * parameters which can be used to remove file. - * If the wantparent flag isn't set, we return only - * the directory (in namei_data->ni_dvp), otherwise we go - * on and lock the node, being careful with ".". - */ - if (op == DELETE && (flags & ISLASTCN)) { - /* - * Write access to directory required to delete files. - */ - if ((error = VOP_ACCESS(dir_vnode, VWRITE, - cnp->cn_cred, p)) != 0) - return (error); - /* - * we are trying to delete '.'. What does this mean? XXX - */ - if (dir_node == new_node) { - VREF(dir_vnode); - *result_vnode = dir_vnode; - return (0); - } - /* - * If directory is "sticky", then user must own - * the directory, or the file in it, else she - * may not delete it (unless she's root). This - * implements append-only directories. - */ - devfs_dntovn(new_node,result_vnode); -#ifdef NOTYET - if ((dir_node->mode & ISVTX) && - cnp->cn_cred->cr_uid != 0 && - cnp->cn_cred->cr_uid != dir_node->uid && - cnp->cn_cred->cr_uid != new_node->uid) { - VOP_UNLOCK(*result_vnode, 0, p); - return (EPERM); - } -#endif - if (!lockparent) - VOP_UNLOCK(dir_vnode, 0, p); - return (0); - } - - /* - * If rewriting (RENAME), return the vnode and the - * information required to rewrite the present directory - * Must get node of directory entry to verify it's a - * regular file, or empty directory. - */ - if (op == RENAME && wantparent && (flags & ISLASTCN)) { - /* - * Are we allowed to change the holding directory? - */ - if ((error = VOP_ACCESS(dir_vnode, VWRITE, - cnp->cn_cred, p)) != 0) - return (error); - /* - * Careful about locking second node. - * This can only occur if the target is ".". - */ - if (dir_node == new_node) - return (EISDIR); - devfs_dntovn(new_node,result_vnode); - /* hmm save the 'from' name (we need to delete it) */ - cnp->cn_flags |= SAVENAME; - if (!lockparent) - VOP_UNLOCK(dir_vnode, 0, p); - return (0); - } - - /* - * Step through the translation in the name. We do not unlock the - * directory because we may need it again if a symbolic link - * is relative to the current directory. Instead we save it - * unlocked as "saved_dir_node" XXX. We must get the target - * node before unlocking - * the directory to insure that the node will not be removed - * before we get it. We prevent deadlock by always fetching - * nodes from the root, moving down the directory tree. Thus - * when following backward pointers ".." we must unlock the - * parent directory before getting the requested directory. - * There is a potential race condition here if both the current - * and parent directories are removed before the lock for the - * node associated with ".." returns. We hope that this occurs - * infrequently since we cannot avoid this race condition without - * implementing a sophisticated deadlock detection algorithm. - * Note also that this simple deadlock detection scheme will not - * work if the file system has any hard links other than ".." - * that point backwards in the directory structure. - */ - if (flags & ISDOTDOT) { - VOP_UNLOCK(dir_vnode, 0, p); /* race to get the node */ - devfs_dntovn(new_node,result_vnode); - if (lockparent && (flags & ISLASTCN)) - vn_lock(dir_vnode, LK_EXCLUSIVE | LK_RETRY, p); - } else if (dir_node == new_node) { - VREF(dir_vnode); /* we want ourself, ie "." */ - *result_vnode = dir_vnode; - } else { - devfs_dntovn(new_node,result_vnode); - if (!lockparent || (flags & ISLASTCN)) - VOP_UNLOCK(dir_vnode, 0, p); - } - -DBPRINT(("GOT\n")); - return (0); -} - -/* - */ - -static int -devfs_access(struct vop_access_args *ap) - /*struct vop_access_args { - struct vnode *a_vp; - int a_mode; - struct ucred *a_cred; - struct proc *a_p; - } */ -{ - /* - * mode is filled with a combination of VREAD, VWRITE, - * and/or VEXEC bits turned on. In an octal number these - * are the Y in 0Y00. - */ - struct vnode *vp = ap->a_vp; - int mode = ap->a_mode; - struct ucred *cred = ap->a_cred; - dn_p dnp; - int error; - gid_t *gp; - int i; - -DBPRINT(("access\n")); - if ((error = devfs_vntodn(vp,&dnp)) != 0) - { - printf("devfs_vntodn returned %d ",error); - return error; - } - - /* - * if we are not running as a process, we are in the - * kernel and we DO have permission - */ - if (ap->a_p == NULL) - return 0; - - /* - * Access check is based on only one of owner, group, public. - * If not owner, then check group. If not a member of the - * group, then check public access. - */ - if (cred->cr_uid != dnp->uid) - { - /* failing that.. try groups */ - mode >>= 3; - gp = cred->cr_groups; - for (i = 0; i < cred->cr_ngroups; i++, gp++) - { - if (dnp->gid == *gp) - { - goto found; - } - } - /* failing that.. try general access */ - mode >>= 3; -found: - ; - } - if ((dnp->mode & mode) == mode) - return (0); - /* - * Root gets to do anything. - * but only use suser_xxx prives as a last resort - * (Use of super powers is recorded in ap->a_p->p_acflag) - */ - if( suser_xxx(cred, ap->a_p, 0) == 0) /* XXX what if no proc? */ - return 0; - return (EACCES); -} - -static int -devfs_getattr(struct vop_getattr_args *ap) - /*struct vop_getattr_args { - struct vnode *a_vp; - struct vattr *a_vap; - struct ucred *a_cred; - struct proc *a_p; - } */ -{ - struct vnode *vp = ap->a_vp; - struct vattr *vap = ap->a_vap; - dn_p dnp; - int error; - -DBPRINT(("getattr\n")); - if ((error = devfs_vntodn(vp,&dnp)) != 0) - { - printf("devfs_vntodn returned %d ",error); - return error; - } - vap->va_rdev = 0;/* default value only */ - vap->va_mode = dnp->mode; - switch (dnp->type) - { - case DEV_DIR: - vap->va_rdev = (udev_t)dnp->dvm; - vap->va_mode |= (S_IFDIR); - break; - case DEV_CDEV: - vap->va_rdev = dev2udev(vp->v_rdev); - vap->va_mode |= (S_IFCHR); - break; -#if nolonger - case DEV_BDEV: - vap->va_rdev = dev2budev(vp->v_rdev); - vap->va_mode |= (S_IFBLK); - break; -#endif - case DEV_SLNK: - break; - } - vap->va_type = vp->v_type; - vap->va_nlink = dnp->links; - vap->va_uid = dnp->uid; - vap->va_gid = dnp->gid; - vap->va_fsid = (intptr_t)(void *)dnp->dvm; - vap->va_fileid = (intptr_t)(void *)dnp; - vap->va_size = dnp->len; /* now a u_quad_t */ - vap->va_blocksize = 512; - /* - * XXX If the node times are in Jan 1, 1970, then - * update them to the boot time. - * When we made the node, the date/time was not yet known. - */ - if(dnp->ctime.tv_sec < (24 * 3600)) - { - TIMEVAL_TO_TIMESPEC(&boottime,&(dnp->ctime)); - TIMEVAL_TO_TIMESPEC(&boottime,&(dnp->mtime)); - TIMEVAL_TO_TIMESPEC(&boottime,&(dnp->atime)); - } - if (dnp->flags & IN_ACCESS) { - nanotime(&dnp->atime); - dnp->flags &= ~IN_ACCESS; - } - vap->va_ctime = dnp->ctime; - vap->va_mtime = dnp->mtime; - vap->va_atime = dnp->atime; - vap->va_gen = 0; - vap->va_flags = 0; - vap->va_bytes = dnp->len; /* u_quad_t */ - vap->va_filerev = 0; /* XXX */ /* u_quad_t */ - vap->va_vaflags = 0; /* XXX */ - return 0; -} - -static int -devfs_setattr(struct vop_setattr_args *ap) - /*struct vop_setattr_args { - struct vnode *a_vp; - struct vattr *a_vap; - struct ucred *a_cred; - struct proc *a_p; - } */ -{ - struct vnode *vp = ap->a_vp; - struct vattr *vap = ap->a_vap; - struct ucred *cred = ap->a_cred; - struct proc *p = ap->a_p; - int error = 0; - gid_t *gp; - int i; - dn_p dnp; - - if (vap->va_flags != VNOVAL) /* XXX needs to be implemented */ - return (EOPNOTSUPP); - - if ((error = devfs_vntodn(vp,&dnp)) != 0) - { - printf("devfs_vntodn returned %d ",error); - return error; - } -DBPRINT(("setattr\n")); - if ((vap->va_type != VNON) || - (vap->va_nlink != VNOVAL) || - (vap->va_fsid != VNOVAL) || - (vap->va_fileid != VNOVAL) || - (vap->va_blocksize != VNOVAL) || - (vap->va_rdev != VNOVAL) || - (vap->va_bytes != VNOVAL) || - (vap->va_gen != VNOVAL )) - { - return EINVAL; - } - - - /* - * Anyone can touch the files in such a way that the times are set - * to NOW (e.g. run 'touch') if they have write permissions - * however only the owner or root can set "un-natural times. - * They also don't need write permissions. - */ - if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { -#if 0 /* - * This next test is pointless under devfs for now.. - * as there is only one devfs hiding under potentially many - * mountpoints and actual device node are really 'mounted' under - * a FAKE mountpoint inside the kernel only, no matter where it - * APPEARS they are mounted to the outside world.. - * A readonly devfs doesn't exist anyway. - */ - if (vp->v_mount->mnt_flag & MNT_RDONLY) - return (EROFS); -#endif - if (((vap->va_vaflags & VA_UTIMES_NULL) == 0) && - (cred->cr_uid != dnp->uid) && - suser_xxx(cred, p, 0)) - return (EPERM); - if(VOP_ACCESS(vp, VWRITE, cred, p)) - return (EACCES); - dnp->atime = vap->va_atime; - dnp->mtime = vap->va_mtime; - nanotime(&dnp->ctime); - return (0); - } - - /* - * Change the permissions.. must be root or owner to do this. - */ - if (vap->va_mode != (u_short)VNOVAL) { - if ((cred->cr_uid != dnp->uid) - && suser_xxx(cred, p, 0)) - return (EPERM); - /* set drwxwxrwx stuff */ - dnp->mode &= ~07777; - dnp->mode |= vap->va_mode & 07777; - } - - /* - * Change the owner.. must be root to do this. - */ - if (vap->va_uid != (uid_t)VNOVAL) { - if (suser_xxx(cred, p, 0)) - return (EPERM); - dnp->uid = vap->va_uid; - } - - /* - * Change the group.. must be root or owner to do this. - * If we are the owner, we must be in the target group too. - * don't use suser_xxx() unless you have to as it reports - * whether you needed suser_xxx powers or not. - */ - if (vap->va_gid != (gid_t)VNOVAL) { - if (cred->cr_uid == dnp->uid){ - gp = cred->cr_groups; - for (i = 0; i < cred->cr_ngroups; i++, gp++) { - if (vap->va_gid == *gp) - goto cando; - } - } - /* - * we can't do it with normal privs, - * do we have an ace up our sleeve? - */ - if( suser_xxx(cred, p, 0)) - return (EPERM); -cando: - dnp->gid = vap->va_gid; - } -#if 0 - /* - * Copied from somewhere else - * but only kept as a marker and reminder of the fact that - * flags should be handled some day - */ - if (vap->va_flags != VNOVAL) { - if (error = suser_xxx(cred, p, 0)) - return error; - if (cred->cr_uid == 0) - ; - else { - } - } -#endif - return error; -} - - -static int -devfs_xread(struct vop_read_args *ap) - /*struct vop_read_args { - struct vnode *a_vp; - struct uio *a_uio; - int a_ioflag; - struct ucred *a_cred; - } */ -{ - int error = 0; - dn_p dnp; - struct vnode *vp = ap->a_vp; - -DBPRINT(("read\n")); - if ((error = devfs_vntodn(vp,&dnp)) != 0) - { - printf("devfs_vntodn returned %d ",error); - return error; - } - - - switch (vp->v_type) { - case VREG: - return(EINVAL); - case VDIR: - return VOP_READDIR(vp,ap->a_uio,ap->a_cred, - NULL,NULL,NULL); - case VCHR: - case VBLK: - panic("devfs: vnode methods"); - - default: - panic("devfs_read(): bad file type"); - break; - } -} - -/* - * Write data to a file or directory. - */ -static int -devfs_xwrite(struct vop_write_args *ap) - /*struct vop_write_args { - struct vnode *a_vp; - struct uio *a_uio; - int a_ioflag; - struct ucred *a_cred; - } */ -{ - struct vnode *vp = ap->a_vp; - - switch (vp->v_type) { - case VREG: - return(EINVAL); - case VDIR: - return(EISDIR); - case VCHR: - case VBLK: - panic("devfs: vnode methods"); - default: - panic("devfs_xwrite(): bad file type"); - } -} - - -static int -devfs_remove(struct vop_remove_args *ap) - /*struct vop_remove_args { - struct vnode *a_dvp; - struct vnode *a_vp; - struct componentname *a_cnp; - } */ -{ - struct vnode *vp = ap->a_vp; - struct vnode *dvp = ap->a_dvp; - struct componentname *cnp = ap->a_cnp; - dn_p tp, tdp; - devnm_p tnp; - int doingdirectory = 0; - int error = 0; - uid_t ouruid = cnp->cn_cred->cr_uid; - - -DBPRINT(("remove\n")); - /* - * 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(dvp, &tdp)) != 0) { -abortit: - return (error); - } - if ((error = devfs_vntodn(vp, &tp)) != 0) goto abortit; - /* - * Assuming we are atomic, dev_lookup left this for us - */ - tnp = tp->last_lookup; - - - /* - * Check we are doing legal things WRT the new flags - */ - if ((tp->flags & (IMMUTABLE | APPEND)) - || (tdp->flags & APPEND) /*XXX eh?*/ ) { - error = EPERM; - goto abortit; - } - - /* - * Make sure that we don't try do something stupid - */ - if ((tp->type) == DEV_DIR) { - /* - * Avoid ".", "..", and aliases of "." for obvious reasons. - */ - if ( (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') - || (cnp->cn_flags&ISDOTDOT) ) { - error = EINVAL; - goto abortit; - } - doingdirectory++; - } - - /*********************************** - * Start actually doing things.... * - ***********************************/ - getnanotime(&(tdp->mtime)); - - - /* - * 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 abortit; - } - /* - * 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 abortit; - } - dev_free_name(tnp); - tp = NULL; - return (error); -} - -/* - */ -static int -devfs_link(struct vop_link_args *ap) - /*struct vop_link_args { - struct vnode *a_tdvp; - struct vnode *a_vp; - struct componentname *a_cnp; - } */ -{ - struct vnode *vp = ap->a_vp; - struct vnode *tdvp = ap->a_tdvp; - struct componentname *cnp = ap->a_cnp; - dn_p fp, tdp; - devnm_p tnp; - int error = 0; - -DBPRINT(("link\n")); - /* - * First catch an arbitrary restriction for this FS - */ - if(cnp->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)) != 0) goto abortit; - if ((error = devfs_vntodn(vp,&fp)) != 0) goto abortit; - - /* - * trying to move it out of devfs? (v_tag == VT_DEVFS) - */ - if ( (vp->v_tag != VT_DEVFS) - || (vp->v_tag != tdvp->v_tag) ) { - error = EXDEV; -abortit: - goto out; - } - - /* - * Check we are doing legal things WRT the new flags - */ - if (fp->flags & (IMMUTABLE | APPEND)) { - error = EPERM; - goto abortit; - } - - /*********************************** - * Start actually doing things.... * - ***********************************/ - getnanotime(&(tdp->atime)); - error = dev_add_name(cnp->cn_nameptr, - tdp, - NULL, - fp, - &tnp); -out: - return (error); - -} - -/* - * 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. - */ -static int -devfs_rename(struct vop_rename_args *ap) - /*struct vop_rename_args { - struct vnode *a_fdvp; - struct vnode *a_fvp; - struct componentname *a_fcnp; - struct vnode *a_tdvp; - struct vnode *a_tvp; - struct componentname *a_tcnp; - } */ -{ - 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; - struct proc *p = fcnp->cn_proc; - dn_p fp, fdp, tp, tdp; - devnm_p fnp,tnp; - int doingdirectory = 0; - int error = 0; - - /* - * 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)) != 0) goto abortit; - if ((error = devfs_vntodn(fdvp,&fdp)) != 0) goto abortit; - if ((error = devfs_vntodn(fvp,&fp)) != 0) goto abortit; - fnp = fp->last_lookup; - if (tvp) { - if ((error = devfs_vntodn(tvp,&tp)) != 0) goto abortit; - tnp = tp->last_lookup; - } 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: - if (tdvp == tvp) /* eh? */ - vrele(tdvp); - else - vput(tdvp); - if (tvp) - vput(tvp); - 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)) - || (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.... * - ***********************************/ - getnanotime(&(fp->atime)); - /* - * Check if just deleting a link name. - */ - if (fvp == tvp) { - if (fvp->v_type == VDIR) { - error = EINVAL; - goto abortit; - } - - /* Release destination completely. */ - vput(tdvp); - vput(tvp); - - /* Delete source. */ - 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; - } - 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 (vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p) == 0) { - fp->links--; /* we added one earlier*/ - vput(fvp); - } else - vrele(fvp); - return (error); -} - -static int -devfs_symlink(struct vop_symlink_args *ap) - /*struct vop_symlink_args { - struct vnode *a_dvp; - struct vnode **a_vpp; - struct componentname *a_cnp; - struct vattr *a_vap; - char *a_target; - } */ -{ - int error; - dn_p dnp; - union typeinfo by; - devnm_p nm_p; - -DBPRINT(("symlink\n")); - if((error = devfs_vntodn(ap->a_dvp, &dnp)) != 0) { - return (error); - } - - by.Slnk.name = ap->a_target; - by.Slnk.namelen = strlen(ap->a_target); - dev_add_entry(ap->a_cnp->cn_nameptr, dnp, DEV_SLNK, &by, - NULL, NULL, &nm_p); - if((error = devfs_dntovn(nm_p->dnp, ap->a_vpp)) != 0) { - return (error); - } - VOP_SETATTR(*ap->a_vpp, ap->a_vap, ap->a_cnp->cn_cred, - ap->a_cnp->cn_proc); - return 0; -} - -/* - * Vnode op for readdir - */ -static int -devfs_readdir(struct vop_readdir_args *ap) - /*struct vop_readdir_args { - struct vnode *a_vp; - struct uio *a_uio; - struct ucred *a_cred; - int *eofflag; - int *ncookies; - u_int **cookies; - } */ -{ - struct vnode *vp = ap->a_vp; - struct uio *uio = ap->a_uio; - struct dirent dirent; - dn_p dir_node; - devnm_p name_node; - char *name; - int error = 0; - int reclen; - int nodenumber; - int startpos,pos; - -DBPRINT(("readdir\n")); - -/* set up refs to dir */ - if ((error = devfs_vntodn(vp,&dir_node)) != 0) - return error; - if(dir_node->type != DEV_DIR) - return(ENOTDIR); - - pos = 0; - startpos = uio->uio_offset; - name_node = dir_node->by.Dir.dirlist; - nodenumber = 0; - getnanotime(&(dir_node->atime)); - - while ((name_node || (nodenumber < 2)) && (uio->uio_resid > 0)) - { - switch(nodenumber) - { - case 0: - dirent.d_fileno = (uintptr_t)(void *)dir_node; - name = "."; - dirent.d_namlen = 1; - dirent.d_type = DT_DIR; - break; - case 1: - if(dir_node->by.Dir.parent) - dirent.d_fileno - = (uintptr_t)(void *)dir_node->by.Dir.parent; - else - dirent.d_fileno = (uintptr_t)(void *)dir_node; - name = ".."; - dirent.d_namlen = 2; - dirent.d_type = DT_DIR; - break; - default: - dirent.d_fileno = (uintptr_t)(void *)name_node->dnp; - dirent.d_namlen = strlen(name_node->name); - name = name_node->name; - switch(name_node->dnp->type) { - case DEV_BDEV: - dirent.d_type = DT_BLK; - break; - case DEV_CDEV: - dirent.d_type = DT_CHR; - break; - case DEV_DDEV: - dirent.d_type = DT_SOCK; /*XXX*/ - break; - case DEV_DIR: - dirent.d_type = DT_DIR; - break; - case DEV_SLNK: - dirent.d_type = DT_LNK; - break; - default: - dirent.d_type = DT_UNKNOWN; - } - } - - reclen = dirent.d_reclen = GENERIC_DIRSIZ(&dirent); - - if(pos >= startpos) /* made it to the offset yet? */ - { - if (uio->uio_resid < reclen) /* will it fit? */ - break; - strcpy( dirent.d_name,name); - if ((error = uiomove ((caddr_t)&dirent, - dirent.d_reclen, uio)) != 0) - break; - } - pos += reclen; - if((nodenumber >1) && name_node) - name_node = name_node->next; - nodenumber++; - } - uio->uio_offset = pos; - - return (error); -} - - -/* - */ -static int -devfs_readlink(struct vop_readlink_args *ap) - /*struct vop_readlink_args { - struct vnode *a_vp; - struct uio *a_uio; - struct ucred *a_cred; - } */ -{ - struct vnode *vp = ap->a_vp; - struct uio *uio = ap->a_uio; - dn_p lnk_node; - int error = 0; - - -DBPRINT(("readlink\n")); -/* set up refs to dir */ - if ((error = devfs_vntodn(vp,&lnk_node)) != 0) - return error; - if(lnk_node->type != DEV_SLNK) - return(EINVAL); - if ((error = VOP_ACCESS(vp, VREAD, ap->a_cred, NULL)) != 0) { /* XXX */ - return error; - } - error = uiomove(lnk_node->by.Slnk.name, lnk_node->by.Slnk.namelen, uio); - return error; -} - -static int -devfs_reclaim(struct vop_reclaim_args *ap) - /*struct vop_reclaim_args { - struct vnode *a_vp; - } */ -{ - dn_p dnp = NULL; - int error; - struct vnode *vp = ap->a_vp; - -DBPRINT(("reclaim\n")); - if ((error = devfs_vntodn(vp,&dnp)) != 0) - { - printf("devfs_vntodn returned %d ",error); - return error; - } - - vp->v_data = NULL; - if (dnp) { - dnp->vn = 0; - dnp->vn_id = 0; - } - return(0); -} - -/* - * Print out the contents of a /devfs vnode. - */ -static int -devfs_print(struct vop_print_args *ap) - /*struct vop_print_args { - struct vnode *a_vp; - } */ -{ - - printf("tag VT_DEVFS, devfs vnode\n"); - return (0); -} - -/**************************************************************************\ -* pseudo ops * -\**************************************************************************/ - -/*proto*/ -void -devfs_dropvnode(dn_p dnp) -{ - struct vnode *vn_p; - -#ifdef PARANOID - if(!dnp) - { - printf("devfs: dn count dropped too early\n"); - } -#endif - vn_p = dnp->vn; - /* - * check if we have a vnode....... - */ - if((vn_p) && ( dnp->vn_id == vn_p->v_id) && (dnp == (dn_p)vn_p->v_data)) - { - VOP_REVOKE(vn_p, REVOKEALL); - } - dnp->vn = NULL; /* be pedantic about this */ -} - -/* struct vnode *speclisth[SPECHSZ];*/ /* till specfs goes away */ - -/* - * Open a special file. - struct vop_open_args { - struct vnode *a_vp; - int a_mode; - struct ucred *a_cred; - struct proc *a_p; - } *ap; - */ -/* ARGSUSED */ -static int -devfs_open( struct vop_open_args *ap) -{ - struct proc *p = ap->a_p; - struct vnode *vp = ap->a_vp; - int error; - dn_p dnp; - struct cdevsw *dsw; - dev_t dev = vp->v_rdev; - - if ((error = devfs_vntodn(vp,&dnp)) != 0) - return error; - - switch (vp->v_type) { - case VCHR: - dsw = devsw(dev); - if ( (dsw == NULL) || (dsw->d_open == NULL)) - return ENXIO; - if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE) && - vn_isdisk(vp, NULL)) { - /* - * When running in very secure mode, do not allow - * opens for writing of any disk devices. - */ - if (securelevel >= 2) - return (EPERM); - /* - * When running in secure mode, do not allow opens - * for writing if the device is mounted. - */ - if (securelevel >= 1 && vp->v_specmountpoint != NULL) - return (EPERM); - } - if ((dsw->d_flags & D_TYPEMASK) == D_TTY) - vp->v_flag |= VISTTY; - VOP_UNLOCK(vp, 0, p); - error = (*vp->v_rdev->si_devsw->d_open)( - vp->v_rdev, - ap->a_mode, - S_IFCHR, - p); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - return (error); - /* NOT REACHED */ - case VBLK: - dsw = devsw(dev); - if ( (dsw == NULL) || (dsw->d_open == NULL)) - return ENXIO; - /* - * When running in very secure mode, do not allow - * opens for writing of any disk block devices. - */ - if (securelevel >= 2 && ap->a_cred != FSCRED && - (ap->a_mode & FWRITE) && - (dsw->d_flags & D_TYPEMASK) == D_DISK) - return (EPERM); - - /* - * Do not allow opens of block devices that are - * currently mounted. - */ - error = vfs_mountedon(vp); - if (error) - return (error); - error = (*vp->v_rdev->si_devsw->d_open)( - vp->v_rdev, - ap->a_mode, - S_IFBLK, - p); - break; - default: - break; - } - return (error); -} - -/* ARGSUSED */ -static int -devfs_read( struct vop_read_args *ap) -{ - int error; - - error = VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap); - return (error); -} - -/* ARGSUSED */ -static int -devfs_write( struct vop_write_args *ap) -{ - int error; - - error = VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap); - return (error); -} - -/* - * Device ioctl operation. - struct vop_ioctl_args { - struct vnode *a_vp; - int a_command; - caddr_t a_data; - int a_fflag; - struct ucred *a_cred; - struct proc *a_p; - } - */ -/* ARGSUSED */ -static int -devfs_ioctl(struct vop_ioctl_args *ap) -{ - dn_p dnp; - int error; - struct vnode *vp = ap->a_vp; - - if ((error = devfs_vntodn(vp,&dnp)) != 0) - return error; - - - switch (vp->v_type) { - - case VCHR: - return ((*vp->v_rdev->si_devsw->d_ioctl)(vp->v_rdev, - ap->a_command, - ap->a_data, - ap->a_fflag, - ap->a_p)); - case VBLK: - return ((*vp->v_rdev->si_devsw->d_ioctl)(vp->v_rdev, - ap->a_command, - ap->a_data, - ap->a_fflag, - ap->a_p)); - default: - panic("devfs_ioctl"); - /* NOTREACHED */ - } -} - -/* - struct vop_poll_args { - struct vnode *a_vp; - int a_events; - struct ucred *a_cred; - struct proc *a_p; - } *ap; -*/ -/* ARGSUSED */ -static int -devfs_poll(struct vop_poll_args *ap) -{ - dn_p dnp; - int error; - struct vnode *vp = ap->a_vp; - - if ((error = devfs_vntodn(vp,&dnp)) != 0) - return error; - - - switch (vp->v_type) { - - case VCHR: - return (*vp->v_rdev->si_devsw->d_poll)(vp->v_rdev, - ap->a_events, - ap->a_p); - default: - return (vop_defaultop((struct vop_generic_args *)ap)); - - } -} -/* - * Synch buffers associated with a block device - struct vop_fsync_args { - struct vnode *a_vp; - struct ucred *a_cred; - int a_waitfor; - struct proc *a_p; - } - */ -/* ARGSUSED */ -static int -devfs_fsync(struct vop_fsync_args *ap) -{ - struct vnode *vp = ap->a_vp; - struct buf *bp; - struct buf *nbp; - int s; - dn_p dnp; - int error; - - if ((error = devfs_vntodn(vp,&dnp)) != 0) - return error; - - - if (vp->v_type == VCHR) - return (0); - /* - * Flush all dirty buffers associated with a block device. - */ -loop: - s = splbio(); - for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { - nbp = TAILQ_NEXT(bp, b_vnbufs); - if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) - continue; - if ((bp->b_flags & B_DELWRI) == 0) - panic("devfs_fsync: not dirty"); - if ((vp->v_flag & VOBJBUF) && (bp->b_flags & B_CLUSTEROK)) { - BUF_UNLOCK(bp); - vfs_bio_awrite(bp); - splx(s); - } else { - bremfree(bp); - splx(s); - bawrite(bp); - } - goto loop; - } - if (ap->a_waitfor == MNT_WAIT) { - while (vp->v_numoutput) { - vp->v_flag |= VBWAIT; - (void) tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "spfsyn", 0); - } -#ifdef DIAGNOSTIC - if (!TAILQ_EMPTY(&vp->v_dirtyblkhd)) { - vprint("devfs_fsync: dirty", vp); - splx(s); - goto loop; - } -#endif - } - splx(s); - return (0); -} - -/* - * Just call the device strategy routine - struct vop_strategy_args { - struct vnode *a_vp; - struct bio *a_bp; - } - */ -static int -devfs_strategy(struct vop_strategy_args *ap) -{ - struct buf *bp = ap->a_bp; - dn_p dnp; - int error; - struct vnode *vp = ap->a_vp; - - if ((vp->v_type != VCHR) - && (vp->v_type != VBLK)) - panic ("devfs_strat:badvnode type"); - if ((error = devfs_vntodn(vp,&dnp)) != 0) - return error; - - - if ((bp->b_iocmd == BIO_WRITE) && (LIST_FIRST(&bp->b_dep)) != NULL) - buf_start(bp); - switch (vp->v_type) { - case VCHR: - (*vp->v_rdev->si_devsw->d_strategy)(&bp->b_io); - break; - case VBLK: - (*vp->v_rdev->si_devsw->d_strategy)(&bp->b_io); - break; - default: - /* XXX set error code? */ - break; - } - return (0); -} - -/* - * I can't say I'm completely sure what this one is for. - * it's copied from specfs. - struct vop_freeblks_args { - struct vnode *a_vp; - daddr_t a_addr; - daddr_t a_length; - }; - */ -static int -devfs_freeblks(struct vop_freeblks_args *ap) -{ - struct cdevsw *bsw; - struct buf *bp; - struct vnode *vp = ap->a_vp; - - bsw = devsw(vp->v_rdev); - if ((bsw->d_flags & D_CANFREE) == 0) - return (0); - bp = geteblk(ap->a_length); - bp->b_iocmd = BIO_DELETE; - bp->b_dev = vp->v_rdev; - bp->b_blkno = ap->a_addr; - bp->b_offset = dbtob(ap->a_addr); - bp->b_bcount = ap->a_length; - DEV_STRATEGY(bp, 0); - return (0); -} - - -/* - * This is a noop, simply returning what one has been given. - struct vop_bmap_args { - struct vnode *a_vp; - daddr_t a_bn; - struct vnode **a_vpp; - daddr_t *a_bnp; - int *a_runp; - int *a_runb; - } - */ -static int -devfs_bmap(struct vop_bmap_args *ap) -{ - - if (ap->a_vpp != NULL) - *ap->a_vpp = ap->a_vp; - if (ap->a_bnp != NULL) - *ap->a_bnp = ap->a_bn; - if (ap->a_runp != NULL) - *ap->a_runp = 0; - if (ap->a_runb != NULL) - *ap->a_runb = 0; - return (0); -} - -/* - * Device close routine - struct vop_close_args { - struct vnode *a_vp; - int a_fflag; - struct ucred *a_cred; - struct proc *a_p; - } - */ -/* ARGSUSED */ -static int -devfs_close(struct vop_close_args *ap) -{ - struct vnode *vp = ap->a_vp; - dn_p dnp; - struct cdevsw *devswp; - dev_t dev; - int mode, error; - - if ((error = devfs_vntodn(vp,&dnp)) != 0) - return error; - - - switch (vp->v_type) { - - case VCHR: - devswp = vp->v_rdev->si_devsw; - dev = vp->v_rdev; - mode = S_IFCHR; - /* - * Hack: a tty device that is a controlling terminal - * has a reference from the session structure. - * We cannot easily tell that a character device is - * a controlling terminal, unless it is the closing - * process' controlling terminal. In that case, - * if the reference count is 2 (this last descriptor - * plus the session), release the reference from the session. - */ - if (vcount(vp) == 2 && ap->a_p && - (vp->v_flag & VXLOCK) == 0 && - vp == ap->a_p->p_session->s_ttyvp) { - vrele(vp); - ap->a_p->p_session->s_ttyvp = NULL; - } - if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0) - return (0); - - break; - - case VBLK: - devswp = vp->v_rdev->si_devsw; - dev = vp->v_rdev; - mode = S_IFBLK; - /* - * On last close of a block device (that isn't mounted) - * we must invalidate any in core blocks, so that - * we can, for instance, change floppy disks. - */ - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p); - error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0); - VOP_UNLOCK(vp, 0, ap->a_p); - if (error) - return (error); - - break; - default: - panic("devfs_close: not special"); - } - /* - * If the vnode is locked, then we are in the midst - * of forcably closing the device, otherwise we would normally - * only close on last reference. - * We do not want to really close the device if it - * is still in use unless we are trying to close it - * forcibly. Since every use (buffer, vnode, swap, cmap) - * holds a reference to the vnode, and because we mark - * any other vnodes that alias this device, when the - * sum of the reference counts on all the aliased - * vnodes descends to one, we are on last close. - * defeat this however if the device wants to be told of every - * close. - */ - if ((vp->v_flag & VXLOCK) - || (devswp->d_flags & D_TRACKCLOSE) - || (vcount(vp) <= 1)) { - return ((*devswp->d_close)(dev, ap->a_fflag, mode, ap->a_p)); - } - return (0); -} - -/* - * Special device advisory byte-level locks. - struct vop_advlock_args { - struct vnode *a_vp; - caddr_t a_id; - int a_op; - struct flock *a_fl; - int a_flags; - } - */ -/* ARGSUSED */ -static int -devfs_advlock(struct vop_advlock_args *ap) -{ - - return (ap->a_flags & F_FLOCK ? EOPNOTSUPP : EINVAL); -} - -/* - * Special device bad operation - */ -static int -devfs_badop(void) -{ - - panic("devfs_badop called"); - /* NOTREACHED */ -} - -static void -devfs_getpages_iodone(struct buf *bp) -{ - - bp->b_flags |= B_DONE; - wakeup(bp); -} - -static int -devfs_getpages(struct vop_getpages_args *ap) -{ - vm_offset_t kva; - int error; - int i, pcount, size, s; - daddr_t blkno; - struct buf *bp; - vm_page_t m; - vm_ooffset_t offset; - int toff, nextoff, nread; - struct vnode *vp = ap->a_vp; - int blksiz; - int gotreqpage; - - error = 0; - pcount = round_page(ap->a_count) / PAGE_SIZE; - - /* - * Calculate the offset of the transfer and do sanity check. - * FreeBSD currently only supports an 8 TB range due to b_blkno - * being in DEV_BSIZE ( usually 512 ) byte chunks on call to - * VOP_STRATEGY. XXX - */ - offset = IDX_TO_OFF(ap->a_m[0]->pindex) + ap->a_offset; - -#define DADDR_T_BIT (sizeof(daddr_t)*8) -#define OFFSET_MAX ((1LL << (DADDR_T_BIT + DEV_BSHIFT)) - 1) - - if (offset < 0 || offset > OFFSET_MAX) { - /* XXX still no %q in kernel. */ - printf("devfs_getpages: preposterous offset 0x%x%08x\n", - (u_int)((u_quad_t)offset >> 32), - (u_int)(offset & 0xffffffff)); - return (VM_PAGER_ERROR); - } - - blkno = btodb(offset); - - /* - * Round up physical size for real devices. We cannot round using - * v_mount's block size data because v_mount has nothing to do with - * the device. i.e. it's usually '/dev'. We need the physical block - * size for the device itself. - * - * We can't use v_specmountpoint because it only exists when the - * block device is mounted. However, we can use v_rdev. - */ - - if (vp->v_type == VBLK) - blksiz = vp->v_rdev->si_bsize_phys; - else - blksiz = DEV_BSIZE; - - size = (ap->a_count + blksiz - 1) & ~(blksiz - 1); - - bp = getpbuf(NULL); - kva = (vm_offset_t)bp->b_data; - - /* - * Map the pages to be read into the kva. - */ - pmap_qenter(kva, ap->a_m, pcount); - - /* Build a minimal buffer header. */ - bp->b_iocmd = BIO_READ; - bp->b_iodone = devfs_getpages_iodone; - - /* B_PHYS is not set, but it is nice to fill this in. */ - bp->b_rcred = bp->b_wcred = curproc->p_ucred; - if (bp->b_rcred != NOCRED) - crhold(bp->b_rcred); - if (bp->b_wcred != NOCRED) - crhold(bp->b_wcred); - bp->b_blkno = blkno; - bp->b_lblkno = blkno; - pbgetvp(vp, bp); - bp->b_bcount = size; - bp->b_bufsize = size; - bp->b_resid = 0; - - cnt.v_vnodein++; - cnt.v_vnodepgsin += pcount; - - /* Do the input. */ - BUF_STRATEGY(bp); - - s = splbio(); - - /* We definitely need to be at splbio here. */ - while ((bp->b_flags & B_DONE) == 0) - tsleep(bp, PVM, "spread", 0); - - splx(s); - - if ((bp->b_ioflags & BIO_ERROR) != 0) { - if (bp->b_error) - error = bp->b_error; - else - error = EIO; - } - - nread = size - bp->b_resid; - - if (nread < ap->a_count) { - bzero((caddr_t)kva + nread, - ap->a_count - nread); - } - pmap_qremove(kva, pcount); - - - gotreqpage = 0; - for (i = 0, toff = 0; i < pcount; i++, toff = nextoff) { - nextoff = toff + PAGE_SIZE; - m = ap->a_m[i]; - - m->flags &= ~PG_ZERO; - - if (nextoff <= nread) { - m->valid = VM_PAGE_BITS_ALL; - vm_page_undirty(m); - } else if (toff < nread) { - /* - * Since this is a VM request, we have to supply the - * unaligned offset to allow vm_page_set_validclean() - * to zero sub-DEV_BSIZE'd portions of the page. - */ - vm_page_set_validclean(m, 0, nread - toff); - } else { - m->valid = 0; - vm_page_undirty(m); - } - - if (i != ap->a_reqpage) { - /* - * Just in case someone was asking for this page we - * now tell them that it is ok to use. - */ - if (!error || (m->valid == VM_PAGE_BITS_ALL)) { - if (m->valid) { - if (m->flags & PG_WANTED) { - vm_page_activate(m); - } else { - vm_page_deactivate(m); - } - vm_page_wakeup(m); - } else { - vm_page_free(m); - } - } else { - vm_page_free(m); - } - } else if (m->valid) { - gotreqpage = 1; - /* - * Since this is a VM request, we need to make the - * entire page presentable by zeroing invalid sections. - */ - if (m->valid != VM_PAGE_BITS_ALL) - vm_page_zero_invalid(m, FALSE); - } - } - if (!gotreqpage) { - m = ap->a_m[ap->a_reqpage]; - printf("devfs_getpages: I/O read failure: (error code=%d)\n", - error); - printf(" size: %d, resid:" - " %ld, a_count: %d, valid: 0x%x\n", - size, bp->b_resid, ap->a_count, m->valid); - printf(" nread: %d, reqpage:" - " %d, pindex: %d, pcount: %d\n", - nread, ap->a_reqpage, m->pindex, pcount); - /* - * Free the buffer header back to the swap buffer pool. - */ - relpbuf(bp, NULL); - return VM_PAGER_ERROR; - } - /* - * Free the buffer header back to the swap buffer pool. - */ - relpbuf(bp, NULL); - return VM_PAGER_OK; -} - - - -/* These are the operations used by directories etc in a devfs */ - -vop_t **devfs_vnodeop_p; -static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = { - { &vop_default_desc, (vop_t *) vop_defaultop }, - { &vop_access_desc, (vop_t *) devfs_access }, - { &vop_bmap_desc, (vop_t *) devfs_badop }, - { &vop_getattr_desc, (vop_t *) devfs_getattr }, - { &vop_link_desc, (vop_t *) devfs_link }, - { &vop_lookup_desc, (vop_t *) devfs_lookup }, - { &vop_pathconf_desc, (vop_t *) vop_stdpathconf }, - { &vop_print_desc, (vop_t *) devfs_print }, - { &vop_read_desc, (vop_t *) devfs_xread }, - { &vop_readdir_desc, (vop_t *) devfs_readdir }, - { &vop_readlink_desc, (vop_t *) devfs_readlink }, - { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, - { &vop_remove_desc, (vop_t *) devfs_remove }, - { &vop_rename_desc, (vop_t *) devfs_rename }, - { &vop_setattr_desc, (vop_t *) devfs_setattr }, - { &vop_symlink_desc, (vop_t *) devfs_symlink }, - { &vop_write_desc, (vop_t *) devfs_xwrite }, - { NULL, NULL } -}; -static struct vnodeopv_desc devfs_vnodeop_opv_desc = - { &devfs_vnodeop_p, devfs_vnodeop_entries }; - -VNODEOP_SET(devfs_vnodeop_opv_desc); - - - -vop_t **devfs_spec_vnodeop_p; -static struct vnodeopv_entry_desc devfs_spec_vnodeop_entries[] = { - { &vop_default_desc, (vop_t *) vop_defaultop }, - { &vop_access_desc, (vop_t *) devfs_access }, - { &vop_advlock_desc, (vop_t *) devfs_advlock }, - { &vop_bmap_desc, (vop_t *) devfs_bmap }, - { &vop_close_desc, (vop_t *) devfs_close }, - { &vop_create_desc, (vop_t *) devfs_badop }, - { &vop_freeblks_desc, (vop_t *) devfs_freeblks }, - { &vop_fsync_desc, (vop_t *) devfs_fsync }, - { &vop_getattr_desc, (vop_t *) devfs_getattr }, - { &vop_getpages_desc, (vop_t *) devfs_getpages }, - { &vop_ioctl_desc, (vop_t *) devfs_ioctl }, - { &vop_lease_desc, (vop_t *) vop_null }, - { &vop_link_desc, (vop_t *) devfs_badop }, - { &vop_lookup_desc, (vop_t *) devfs_lookup }, - { &vop_mkdir_desc, (vop_t *) devfs_badop }, - { &vop_mknod_desc, (vop_t *) devfs_badop }, - { &vop_open_desc, (vop_t *) devfs_open }, - { &vop_pathconf_desc, (vop_t *) vop_stdpathconf }, - { &vop_poll_desc, (vop_t *) devfs_poll }, - { &vop_print_desc, (vop_t *) devfs_print }, - { &vop_read_desc, (vop_t *) devfs_read }, - { &vop_readdir_desc, (vop_t *) devfs_badop }, - { &vop_readlink_desc, (vop_t *) devfs_badop }, - { &vop_reallocblks_desc, (vop_t *) devfs_badop }, - { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, - { &vop_remove_desc, (vop_t *) devfs_badop }, - { &vop_rename_desc, (vop_t *) devfs_badop }, - { &vop_rmdir_desc, (vop_t *) devfs_badop }, - { &vop_setattr_desc, (vop_t *) devfs_setattr }, - { &vop_strategy_desc, (vop_t *) devfs_strategy }, - { &vop_symlink_desc, (vop_t *) devfs_symlink }, - { &vop_write_desc, (vop_t *) devfs_write }, - { NULL, NULL } -}; -static struct vnodeopv_desc devfs_spec_vnodeop_opv_desc = - { &devfs_spec_vnodeop_p, devfs_spec_vnodeop_entries }; - -VNODEOP_SET(devfs_spec_vnodeop_opv_desc); - diff --git a/sys/miscfs/devfs/devfsdefs.h b/sys/miscfs/devfs/devfsdefs.h deleted file mode 100644 index 7df378ccade8..000000000000 --- a/sys/miscfs/devfs/devfsdefs.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright 1997,1998 Julian Elischer. All rights reserved. - * julian@freebsd.org - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifdef DEVFS_DEBUG -#define DBPRINT(A) printf(A) -#else -#define DBPRINT(A) -#endif - -/* first a couple of defines for compatibility with inodes */ - -#define ISUID 04000 /* set user identifier when exec'ing */ -#define ISGID 02000 /* set group identifier when exec'ing */ -#define ISVTX 01000 /* save execution information on exit */ -#define IREAD 0400 /* read permission */ -#define IWRITE 0200 /* write permission */ -#define IEXEC 0100 /* execute permission */ - - -#define ILOCKED 0x0001 /* inode is locked */ -#define IWANT 0x0002 /* some process waiting on lock */ -#define IRENAME 0x0004 /* inode is being renamed */ -#define IUPD 0x0010 /* file has been modified */ -#define IACC 0x0020 /* inode access time to be updated */ -#define ICHG 0x0040 /* inode has been changed */ -#define IMOD 0x0080 /* inode has been modified */ -#define ISHLOCK 0x0100 /* file has shared lock */ -#define IEXLOCK 0x0200 /* file has exclusive lock */ -#define ILWAIT 0x0400 /* someone waiting on file lock */ - -/* - * Lock and unlock inodes. - */ -#ifdef notdef -#define DNLOCK(ip) { \ - while ((ip)->i_flag & ILOCKED) { \ - (ip)->i_flag |= IWANT; \ - (void) sleep((caddr_t)(ip), PINOD); \ - } \ - (ip)->i_flag |= ILOCKED; \ -} - -#define DNUNLOCK(ip) { \ - (ip)->i_flag &= ~ILOCKED; \ - if ((ip)->i_flag&IWANT) { \ - (ip)->i_flag &= ~IWANT; \ - wakeup((caddr_t)(ip)); \ - } \ -} -#else -#define DNLOCK(ip) -#define DNUNLOCK(ip) -#endif - - -#define DEVMAXNAMESIZE 32 -#define DEVMAXPATHSIZE 128 -#define DEV_DIR 1 -#define DEV_BDEV 2 -#define DEV_CDEV 3 -#define DEV_DDEV 4 -#define DEV_ALIAS 5 -#define DEV_SLNK 6 -#define DEV_PIPE 7 - - -extern vop_t **devfs_vnodeop_p; /* our own vector array for dirs */ -extern vop_t **devfs_spec_vnodeop_p; /* our own vector array for devs */ - -typedef struct dev_name *devnm_p; -typedef struct devnode *dn_p; - -struct devnode /* the equivalent of an INODE */ -{ - u_short type; - int flags; /* more inode compatible for now *//*XXXkill*/ -#define IN_ACCESS 0x0001 - u_short mode; /* basically inode compatible (drwxrwxrwx) */ - u_short uid; /* basically inode compatible */ - u_short gid; /* basically inode compatible */ - struct timespec atime; /* time of last access */ - struct timespec mtime; /* time of last modification */ - struct timespec ctime; /* time file changed */ - int links; /* how many file links does this node have? */ - struct devfsmount *dvm; /* the mount structure for this 'plane' */ - struct vnode *vn; /* address of last vnode that represented us */ - u_long vn_id; /* make sure we have the right vnode */ - int (***ops)(void *); /* yuk... pointer to pointer(s) to funcs */ - int len; /* of any associated info (e.g. dir data) */ - devnm_p linklist; /* circular list of hardlinks to this node */ - devnm_p last_lookup; /* name I was last looked up from */ - dn_p nextsibling; /* the list of equivelent nodes */ - dn_p *prevsiblingp; /* backpointer for the above */ - union typeinfo { - struct { - dev_t dev; - }dev; - struct { - int (***ops)(void *); /* duplicate, used in dev_add_node */ - int arg; - }Ddev; - struct { - devnm_p dirlist; - devnm_p *dirlast; - dn_p parent; - devnm_p myname; /* my entry in .. */ - int entrycount; - }Dir; - struct { - char *name; /* must be allocated separately */ - int namelen; - }Slnk; - struct { - devnm_p realthing; - devnm_p next; - }Alias; - struct { - struct socket *sock; - }Pipe; - }by; -}; -typedef struct devnode devnode_t; - -struct dev_name -{ - /*-----------------------directory entry fields-------------*/ - char name[DEVMAXNAMESIZE]; - dn_p dnp; /* the "inode" (devnode) pointer */ - dn_p parent; /* backpointer to the directory itself */ - devnm_p next; /* next object in this directory */ - devnm_p *prevp; /* previous pointer in directory linked list */ - devnm_p nextlink; /* next hardlink to this node */ - devnm_p *prevlinkp; /* previous hardlink pointer for this node */ - /*-----------------------aliases or backing nodes----------*/ - union { - struct { - devnm_p aliases; /* aliase chain (kill with us)*/ - } back; - struct { - devnm_p realthing; /* ptr to the backing node */ - } front; - } as; -}; - -typedef struct dev_name devnm_t; -extern int devfs_up_and_going; -extern devnm_p dev_root; - - -/* - * Rules for front nodes: - * Dirs hava a strict 1:1 relationship with their OWN devnode - * Symlinks similarly - * Device Nodes ALWAYS point to the devnode that is linked - * to the Backing node. (with a ref count) - */ - -/* - * DEVFS specific per/mount information, used to link a monted fs to a - * particular 'plane' of front nodes. - */ -struct devfsmount -{ - struct mount *mount; /* vfs mount struct for this fs */ - devnm_p plane_root; /* the root of this 'plane' */ - int flags; /* usefule some day 8-) */ -}; - -struct dev_vn_data -{ - char magic[6]; /* = "devfs" if correct */ - devnm_p front; - devnm_p back; -}; - -/* - * Prototypes for DEVFS virtual filesystem operations - */ -#include <miscfs/devfs/devfs_proto.h> diff --git a/sys/miscfs/devfs/reproto.sh b/sys/miscfs/devfs/reproto.sh deleted file mode 100644 index 1b671163db55..000000000000 --- a/sys/miscfs/devfs/reproto.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh -# -# This used to be a shell script, but had to become more sophisticated -# to allow for KNF function definitions. So rewrote in perl, but wrapped -# as a shell script. -# -# $FreeBSD$ -# -exec /usr/bin/perl << *EOF* -open(PROTO, ">devfs_proto.h") || die "Cannot open devfs_proto.h\n"; - -print PROTO "/* \\\$FreeBSD\\\$ */\n"; -print PROTO "/* THIS FILE HAS BEEN PRODUCED AUTOMATICALLY */\n"; - -while (\$file = <*.c>) { - if(open(F, \$file) == 0) { - warn "Cannot open \$file.\n"; - next; - } - - while(<F>) { - chop; - if (m|/\*proto\*/|) { - \$collecting = 1; - \$idx = 0; - } elsif (\$collecting) { - if (/^{/) { - \$text[\$idx - 1] .= ';'; - for (\$i = 0; \$i < \$idx; \$i++) { - print PROTO "\$text[\$i]"; - print PROTO \$i == 0? "\t": "\n"; - } - \$collecting = 0; - next; - } - \$text[\$idx++] = \$_; - } - } - close F; -} - -print PROTO "/* THIS FILE PRODUCED AUTOMATICALLY */\n" . - "/* DO NOT EDIT (see reproto.sh) */\n"; - -*EOF* |
