static int devfs_symlink(struct vnop_symlink_args *ap) /*struct vnop_symlink_args { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; struct vnode_attr *a_vap; char *a_target; vfs_context_t a_context; } */ { int error; devdirent_t *newent; DEVFS_LOCK(); error = devfs_make_symlink(VTODN(ap->a_dvp), ap->a_cnp->cn_nameptr, ap->a_vap->va_mode, ap->a_target, &newent); if (error == 0) { error = devfs_dntovn(newent->de_dnp, ap->a_vpp, vfs_context_proc(ap->a_context)); } DEVFS_UNLOCK(); return error; }
/* * Mknod vnode call */ static int devfs_mknod(struct vnop_mknod_args *ap) /* struct vnop_mknod_args { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; struct vnode_attr *a_vap; vfs_context_t a_context; } */ { struct componentname * cnp = ap->a_cnp; vfs_context_t ctx = cnp->cn_context; struct proc *p = vfs_context_proc(ctx); devnode_t * dev_p; devdirent_t * devent; devnode_t * dir_p; /* devnode for parent directory */ struct vnode * dvp = ap->a_dvp; int error = 0; devnode_type_t typeinfo; struct vnode_attr * vap = ap->a_vap; struct vnode ** vpp = ap->a_vpp; *vpp = NULL; if (!(vap->va_type == VBLK) && !(vap->va_type == VCHR)) { return (EINVAL); /* only support mknod of special files */ } typeinfo.dev = vap->va_rdev; DEVFS_LOCK(); dir_p = VTODN(dvp); error = dev_add_entry(cnp->cn_nameptr, dir_p, (vap->va_type == VBLK) ? DEV_BDEV : DEV_CDEV, &typeinfo, NULL, NULL, &devent); if (error) { goto failure; } dev_p = devent->de_dnp; error = devfs_dntovn(dev_p, vpp, p); if (error) goto failure; dev_p->dn_uid = vap->va_uid; dev_p->dn_gid = vap->va_gid; dev_p->dn_mode = vap->va_mode; VATTR_SET_SUPPORTED(vap, va_uid); VATTR_SET_SUPPORTED(vap, va_gid); VATTR_SET_SUPPORTED(vap, va_mode); failure: DEVFS_UNLOCK(); return (error); }
/* return the address of the root vnode in *vpp */ static int devfs_root(struct mount *mp, struct vnode **vpp, __unused vfs_context_t ctx) { struct devfsmount *devfs_mp_p = (struct devfsmount *)(mp->mnt_data); int error; DEVFS_LOCK(); /* last parameter to devfs_dntovn() is ignored */ error = devfs_dntovn(devfs_mp_p->plane_root->de_dnp, vpp, NULL); DEVFS_UNLOCK(); return error; }
static int devfs_symlink(struct vnop_symlink_args *ap) /*struct vnop_symlink_args { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; struct vnode_attr *a_vap; char *a_target; vfs_context_t a_context; } */ { struct componentname * cnp = ap->a_cnp; vfs_context_t ctx = cnp->cn_context; struct proc *p = vfs_context_proc(ctx); int error = 0; devnode_t * dir_p; devnode_type_t typeinfo; devdirent_t * nm_p; devnode_t * dev_p; struct vnode_attr * vap = ap->a_vap; struct vnode * * vpp = ap->a_vpp; typeinfo.Slnk.name = ap->a_target; typeinfo.Slnk.namelen = strlen(ap->a_target); DEVFS_LOCK(); dir_p = VTODN(ap->a_dvp); error = dev_add_entry(cnp->cn_nameptr, dir_p, DEV_SLNK, &typeinfo, NULL, NULL, &nm_p); if (error) { goto failure; } dev_p = nm_p->de_dnp; dev_p->dn_uid = dir_p->dn_uid; dev_p->dn_gid = dir_p->dn_gid; dev_p->dn_mode = vap->va_mode; dn_copy_times(dev_p, dir_p); error = devfs_dntovn(dev_p, vpp, p); failure: DEVFS_UNLOCK(); return error; }
static int devfs_mkdir(struct vnop_mkdir_args *ap) /*struct vnop_mkdir_args { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; struct vnode_attr *a_vap; vfs_context_t a_context; } */ { struct componentname * cnp = ap->a_cnp; vfs_context_t ctx = cnp->cn_context; struct proc *p = vfs_context_proc(ctx); int error = 0; devnode_t * dir_p; devdirent_t * nm_p; devnode_t * dev_p; struct vnode_attr * vap = ap->a_vap; struct vnode * * vpp = ap->a_vpp; DEVFS_LOCK(); dir_p = VTODN(ap->a_dvp); error = dev_add_entry(cnp->cn_nameptr, dir_p, DEV_DIR, NULL, NULL, NULL, &nm_p); if (error) { goto failure; } dev_p = nm_p->de_dnp; dev_p->dn_uid = dir_p->dn_uid; dev_p->dn_gid = dir_p->dn_gid; dev_p->dn_mode = vap->va_mode; dn_copy_times(dev_p, dir_p); error = devfs_dntovn(dev_p, vpp, p); failure: DEVFS_UNLOCK(); return error; }
/* * 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 vnop_lookup_args *ap) /*struct vnop_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 vfs_context_t a_context; };*/ { struct componentname *cnp = ap->a_cnp; vfs_context_t ctx = cnp->cn_context; struct proc *p = vfs_context_proc(ctx); struct vnode *dir_vnode = ap->a_dvp; struct vnode **result_vnode = ap->a_vpp; devnode_t * dir_node; /* the directory we are searching */ devnode_t * node = NULL; /* the node we are searching for */ devdirent_t * nodename; int flags = cnp->cn_flags; int op = cnp->cn_nameiop; /* LOOKUP, CREATE, RENAME, or DELETE */ int wantparent = flags & (LOCKPARENT|WANTPARENT); int error = 0; char heldchar; /* the char at the end of the name componet */ retry: *result_vnode = NULL; /* safe not sorry */ /*XXX*/ /* okay to look at directory vnodes ourside devfs lock as they are not aliased */ dir_node = VTODN(dir_vnode); /* * Make sure that our node is a directory as well. */ if (dir_node->dn_type != DEV_DIR) { return (ENOTDIR); } DEVFS_LOCK(); /* * temporarily terminate string component */ heldchar = cnp->cn_nameptr[cnp->cn_namelen]; cnp->cn_nameptr[cnp->cn_namelen] = '\0'; nodename = dev_findname(dir_node, cnp->cn_nameptr); /* * restore saved character */ cnp->cn_nameptr[cnp->cn_namelen] = heldchar; if (nodename) { /* entry exists */ node = nodename->de_dnp; /* Do potential vnode allocation here inside the lock * to make sure that our device node has a non-NULL dn_vn * associated with it. The device node might otherwise * get deleted out from under us (see devfs_dn_free()). */ error = devfs_dntovn(node, result_vnode, p); } DEVFS_UNLOCK(); if (error) { if (error == EAGAIN) goto retry; return error; } if (!nodename) { /* * we haven't called devfs_dntovn if we get here * we have not taken a reference on the node.. no * vnode_put is necessary on these error returns * * If it doesn't exist and we're not the last component, * or we're at the last component, but we're not creating * or renaming, return ENOENT. */ if (!(flags & ISLASTCN) || !(op == CREATE || op == RENAME)) { return ENOENT; } /* * 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. * * NB - if the directory is unlocked, then this * information cannot be used. */ return (EJUSTRETURN); } /* * from this point forward, we need to vnode_put the reference * picked up in devfs_dntovn if we decide to return an error */ /* * 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)) { /* * we are trying to delete '.'. What does this mean? XXX */ if (dir_node == node) { if (*result_vnode) { vnode_put(*result_vnode); *result_vnode = NULL; } if ( ((error = vnode_get(dir_vnode)) == 0) ) { *result_vnode = dir_vnode; } return (error); } 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)) { /* * Careful about locking second node. * This can only occur if the target is ".". */ if (dir_node == node) { error = EISDIR; goto drop_ref; } 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) == 0 && dir_node == node) { if (*result_vnode) { vnode_put(*result_vnode); *result_vnode = NULL; } if ( (error = vnode_get(dir_vnode)) ) { return (error); } *result_vnode = dir_vnode; } return (0); drop_ref: if (*result_vnode) { vnode_put(*result_vnode); *result_vnode = NULL; } return (error); }