From c32d0a1dcdc8b0d797a12a1e9249a06eb55d9912 Mon Sep 17 00:00:00 2001 From: Poul-Henning Kamp Date: Sun, 27 Aug 2000 14:46:36 +0000 Subject: [PATCH] Reorder vop's alphabetically. Smarter use of devfs_allocv() (from bp@) Introduce devfs_find() ".." fixes to devfs_lookup (from bp@) --- sys/fs/devfs/devfs.h | 2 + sys/fs/devfs/devfs_devs.c | 43 ++-- sys/fs/devfs/devfs_vfsops.c | 72 +++---- sys/fs/devfs/devfs_vnops.c | 412 +++++++++++++++++++----------------- 4 files changed, 281 insertions(+), 248 deletions(-) diff --git a/sys/fs/devfs/devfs.h b/sys/fs/devfs/devfs.h index e144a4b4e146..c959e530275a 100644 --- a/sys/fs/devfs/devfs.h +++ b/sys/fs/devfs/devfs.h @@ -88,6 +88,8 @@ extern unsigned devfs_generation; extern vop_t **devfs_vnodeop_p; extern vop_t **devfs_specop_p; +int devfs_allocv __P((struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct proc *p)); +struct devfs_dirent * devfs_find __P((struct devfs_dirent *dd, const char *name, int namelen)); int devfs_populate __P((struct devfs_mount *dm)); struct devfs_dirent * devfs_newdirent __P((char *name, int namelen)); void devfs_purge __P((struct devfs_dirent *dd)); diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c index 8b301c93fc37..c3eb101ab1bb 100644 --- a/sys/fs/devfs/devfs_devs.c +++ b/sys/fs/devfs/devfs_devs.c @@ -41,6 +41,21 @@ #define DEVFS_INTERN #include +struct devfs_dirent * +devfs_find(struct devfs_dirent *dd, const char *name, int namelen) +{ + struct devfs_dirent *de; + + TAILQ_FOREACH(de, &dd->de_dlist, de_list) { + if (namelen != de->de_dirent->d_namlen) + continue; + if (bcmp(name, de->de_dirent->d_name, namelen) != 0) + continue; + break; + } + return (de); +} + struct devfs_dirent * devfs_newdirent(char *name, int namelen) { @@ -161,25 +176,20 @@ devfs_populate(struct devfs_mount *dm) continue; dd = dm->dm_basedir; s = dev->si_name; - nextdir: - for (q = s; *q != '/' && *q != '\0'; q++) - continue; - if (*q == '/') { - TAILQ_FOREACH(de, &dd->de_dlist, de_list) { - if (de->de_dirent->d_namlen != q - s) - continue; - if (bcmp(de->de_dirent->d_name, s, q - s)) - continue; - goto fdir; + for (;;) { + for (q = s; *q != '/' && *q != '\0'; q++) + continue; + if (*q != '/') + break; + de = devfs_find(dd, s, q - s); + if (de == NULL) { + de = devfs_vmkdir(s, q - s, dd); + de->de_inode = dm->dm_inode++; + TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); + dd->de_links++; } - de = devfs_vmkdir(s, q - s, dd); - de->de_inode = dm->dm_inode++; - TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); - dd->de_links++; - fdir: s = q + 1; dd = de; - goto nextdir; } de = devfs_newdirent(s, q - s); if (dev->si_flags & SI_ALIAS) { @@ -200,6 +210,7 @@ devfs_populate(struct devfs_mount *dm) de->de_dirent->d_type = DT_CHR; } dm->dm_dirent[i] = de; + de->de_dir = dd; TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); #if 0 printf("Add ino%d %s\n", i, dev->si_name); diff --git a/sys/fs/devfs/devfs_vfsops.c b/sys/fs/devfs/devfs_vfsops.c index b5ccac4a6342..d2fdda7e209a 100644 --- a/sys/fs/devfs/devfs_vfsops.c +++ b/sys/fs/devfs/devfs_vfsops.c @@ -67,43 +67,39 @@ devfs_mount(mp, path, data, ndp, p) struct nameidata *ndp; struct proc *p; { - int error = 0; + int error; u_int size; struct devfs_mount *fmp; struct vnode *rvp; + error = 0; /* - * Update is a no-op + * XXX: flag changes. */ if (mp->mnt_flag & MNT_UPDATE) return (EOPNOTSUPP); - MALLOC(fmp, struct devfs_mount *, sizeof(struct devfs_mount), M_DEVFS, M_WAITOK); - + MALLOC(fmp, struct devfs_mount *, sizeof(struct devfs_mount), + M_DEVFS, M_WAITOK); bzero(fmp, sizeof(*fmp)); - error = getnewvnode(VT_DEVFS, mp, devfs_vnodeop_p, &rvp); - if (error) { - FREE(fmp, M_DEVFS); - return (error); - } - - vhold(rvp); - rvp->v_type = VDIR; - rvp->v_flag |= VROOT; mp->mnt_flag |= MNT_LOCAL; mp->mnt_data = (qaddr_t) fmp; vfs_getnewfsid(mp); fmp->dm_inode = NDEVINO; - fmp->dm_root = rvp; fmp->dm_rootdir = devfs_vmkdir("(root)", 6, NULL); fmp->dm_rootdir->de_inode = 2; - rvp->v_data = fmp->dm_rootdir; - fmp->dm_basedir = fmp->dm_rootdir; + error = devfs_root(mp, &rvp); + if (error) { + FREE(fmp, M_DEVFS); + return (error); + } + VOP_UNLOCK(rvp, 0, p); + if (path != NULL) { (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); } else { @@ -127,55 +123,47 @@ devfs_unmount(mp, mntflags, p) { int error; int flags = 0; - struct vnode *rootvp = VFSTODEVFS(mp)->dm_root; + struct vnode *rootvp; struct devfs_mount *fmp; - fmp = (struct devfs_mount*) mp->mnt_data; + error = devfs_root(mp, &rootvp); + if (error) + return (error); + fmp = VFSTODEVFS(mp); if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - - /* - * Clear out buffer cache. I don't think we - * ever get anything cached at this level at the - * moment, but who knows... - */ if (rootvp->v_usecount > 2) return (EBUSY); devfs_purge(fmp->dm_rootdir); error = vflush(mp, rootvp, flags); if (error) return (error); - - /* - * Release reference on underlying root vnode - */ + vput(rootvp); vrele(rootvp); - /* - * And blow it away for future re-use - */ vgone(rootvp); - /* - * Finally, throw away the devfs_mount structure - */ - free(mp->mnt_data, M_DEVFS); mp->mnt_data = 0; + free(fmp, M_DEVFS); return 0; } +/* Return locked reference to root. */ + static int devfs_root(mp, vpp) struct mount *mp; struct vnode **vpp; { - struct proc *p = curproc; /* XXX */ + int error; + struct proc *p; struct vnode *vp; + struct devfs_mount *dmp; - /* - * Return locked reference to root. - */ - vp = VFSTODEVFS(mp)->dm_root; - VREF(vp); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + p = curproc; /* XXX */ + dmp = VFSTODEVFS(mp); + error = devfs_allocv(dmp->dm_rootdir, mp, &vp, p); + if (error) + return (error); + vp->v_flag |= VROOT; *vpp = vp; return (0); } diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c index e094589a728b..86444ec10e7b 100644 --- a/sys/fs/devfs/devfs_vnops.c +++ b/sys/fs/devfs/devfs_vnops.c @@ -67,16 +67,18 @@ static int devfs_setattr __P((struct vop_setattr_args *ap)); static int devfs_symlink __P((struct vop_symlink_args *ap)); -static int +int devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct proc *p) { int error; struct vnode *vp; + if (p == NULL) + p = curproc; /* XXX */ loop: vp = de->de_vnode; if (vp != NULL) { - if (vget(vp, 0, p ? p : curproc)) + if (vget(vp, LK_EXCLUSIVE, p ? p : curproc)) goto loop; *vpp = vp; return (0); @@ -101,148 +103,10 @@ devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, stru vp->v_data = de; de->de_vnode = vp; vhold(vp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); *vpp = vp; return (0); } -/* - * vp is the current namei directory - * ndp is the name to locate in that directory... - */ -static int -devfs_lookup(ap) - struct vop_lookup_args /* { - struct vnode * a_dvp; - struct vnode ** a_vpp; - struct componentname * a_cnp; - } */ *ap; -{ - struct componentname *cnp = ap->a_cnp; - struct vnode **vpp = ap->a_vpp; - struct vnode *dvp = ap->a_dvp; - char *pname = cnp->cn_nameptr; - struct proc *p = cnp->cn_proc; - struct devfs_dirent *dd; - struct devfs_dirent *de; - struct devfs_mount *dmp; - dev_t cdev; - int error, cloned, i; - char specname[SPECNAMELEN + 1]; - - *vpp = NULLVP; - -#if 0 - error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_proc); - if (error) - return (error); -#endif - - VOP_UNLOCK(dvp, 0, p); - if (cnp->cn_namelen == 1 && *pname == '.') { - *vpp = dvp; - VREF(dvp); - vn_lock(dvp, LK_SHARED | LK_RETRY, p); - return (0); - } - - cloned = 0; - - dmp = VFSTODEVFS(dvp->v_mount); -again: - - devfs_populate(dmp); - dd = dvp->v_data; - TAILQ_FOREACH(de, &dd->de_dlist, de_list) { - if (cnp->cn_namelen != de->de_dirent->d_namlen) - continue; - if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, de->de_dirent->d_namlen) != 0) - continue; - goto found; - } - - if (!cloned) { - /* - * OK, we didn't have an entry for the name we were asked for - * so we try to see if anybody can create it on demand. - * We need to construct the full "devname" for this device - * relative to "basedir" or the clone functions would not - * be able to tell "/dev/foo" from "/dev/bar/foo" - */ - i = SPECNAMELEN; - specname[i] = '\0'; - i -= cnp->cn_namelen; - if (i < 0) - goto noclone; - bcopy(cnp->cn_nameptr, specname + i, cnp->cn_namelen); - de = dd; - while (de != dmp->dm_basedir) { - i--; - if (i < 0) - goto noclone; - specname[i] = '/'; - i -= de->de_dirent->d_namlen; - if (i < 0) - goto noclone; - bcopy(de->de_dirent->d_name, specname + i, - de->de_dirent->d_namlen); - de = TAILQ_FIRST(&de->de_dlist); /* "." */ - de = TAILQ_NEXT(de, de_list); /* ".." */ - de = de->de_dir; - } - -#if 0 - printf("Finished specname: %d \"%s\"\n", i, specname + i); -#endif - cdev = NODEV; - EVENTHANDLER_INVOKE(devfs_clone, specname + i, - strlen(specname + i), &cdev); -#if 0 - printf("cloned %s -> %p %s\n", specname + i, cdev, - cdev == NODEV ? "NODEV" : cdev->si_name); -#endif - if (cdev != NODEV) { - cloned = 1; - goto again; - } - } - -noclone: - /* No luck, too bad. */ - - if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) && - (cnp->cn_flags & ISLASTCN)) { - cnp->cn_flags |= SAVENAME; - if (!(cnp->cn_flags & LOCKPARENT)) - VOP_UNLOCK(dvp, 0, p); - return (EJUSTRETURN); - } else { - vn_lock(dvp, LK_SHARED | LK_RETRY, p); - return (ENOENT); - } - - -found: - - error = devfs_allocv(de, dvp->v_mount, vpp, p); - if (error != 0) { - vn_lock(dvp, LK_SHARED | LK_RETRY, p); - return (error); - } - if ((cnp->cn_nameiop == DELETE) && (cnp->cn_flags & ISLASTCN)) { - if (*vpp == dvp) { - VREF(dvp); - *vpp = dvp; - return (0); - } - VREF(*vpp); - if (!(cnp->cn_flags & LOCKPARENT)) - VOP_UNLOCK(dvp, 0, p); - return (0); - } - vn_lock(*vpp, LK_SHARED | LK_RETRY, p); - if (!(cnp->cn_flags & LOCKPARENT)) - VOP_UNLOCK(dvp, 0, p); - return (0); -} static int devfs_access(ap) @@ -323,43 +187,186 @@ devfs_getattr(ap) } static int -devfs_setattr(ap) - struct vop_setattr_args /* { - struct vnode *a_vp; - struct vattr *a_vap; - struct ucred *a_cred; - struct proc *a_p; +devfs_lookup(ap) + struct vop_lookup_args /* { + struct vnode * a_dvp; + struct vnode ** a_vpp; + struct componentname * a_cnp; } */ *ap; { - struct devfs_dirent *de; - int c; + struct componentname *cnp; + struct vnode *dvp, **vpp; + struct proc *p; + struct devfs_dirent *de, *dd; + struct devfs_mount *dmp; + dev_t cdev; + int error, cloned, i, flags, nameiop; + char specname[SPECNAMELEN + 1], *pname; - de = ap->a_vp->v_data; - if (ap->a_vp->v_type == VDIR) - de = de->de_dir; + cnp = ap->a_cnp; + vpp = ap->a_vpp; + dvp = ap->a_dvp; + pname = cnp->cn_nameptr; + p = cnp->cn_proc; + flags = cnp->cn_flags; + nameiop = cnp->cn_nameiop; + dmp = VFSTODEVFS(dvp->v_mount); + cloned = 0; + dd = dvp->v_data; + + *vpp = NULLVP; - c = 0; - if (ap->a_vap->va_flags != VNOVAL) + if (nameiop == RENAME) return (EOPNOTSUPP); - if (ap->a_vap->va_uid != (uid_t)VNOVAL) { - de->de_uid = ap->a_vap->va_uid; - c = 1; - } - if (ap->a_vap->va_gid != (gid_t)VNOVAL) { - de->de_gid = ap->a_vap->va_gid; - c = 1; - } - if (ap->a_vap->va_mode != (mode_t)VNOVAL) { - de->de_mode = ap->a_vap->va_mode; - c = 1; - } - if (ap->a_vap->va_atime.tv_sec != VNOVAL) - de->de_atime = ap->a_vap->va_atime; - if (ap->a_vap->va_mtime.tv_sec != VNOVAL) - de->de_mtime = ap->a_vap->va_mtime; - if (c) - getnanotime(&de->de_ctime); + if (dvp->v_type != VDIR) + return (ENOTDIR); + + if ((flags & ISDOTDOT) && (dvp->v_flag & VROOT)) + return (EIO); + + error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_proc); + if (error) + return (error); + + if (cnp->cn_namelen == 1 && *pname == '.') { + if (nameiop != LOOKUP) + return (EINVAL); + *vpp = dvp; + VREF(dvp); + return (0); + } + + if (flags & ISDOTDOT) { + if (nameiop != LOOKUP) + return (EINVAL); + VOP_UNLOCK(dvp, 0, p); + de = TAILQ_FIRST(&dd->de_dlist); /* "." */ + de = TAILQ_NEXT(de, de_list); /* ".." */ + de = de->de_dir; + error = devfs_allocv(de, dvp->v_mount, vpp, p); + if (error) { + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); + return (error); + } + if ((flags & LOCKPARENT) && (flags & ISLASTCN)) + error = vn_lock(dvp, LK_EXCLUSIVE, p); + if (error) + vput(*vpp); + return (error); + } + + devfs_populate(dmp); + dd = dvp->v_data; + TAILQ_FOREACH(de, &dd->de_dlist, de_list) { + if (cnp->cn_namelen != de->de_dirent->d_namlen) + continue; + if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, + de->de_dirent->d_namlen) != 0) + continue; + goto found; + } + + /* + * OK, we didn't have an entry for the name we were asked for + * so we try to see if anybody can create it on demand. + * We need to construct the full "devname" for this device + * relative to "basedir" or the clone functions would not + * be able to tell "/dev/foo" from "/dev/bar/foo" + */ + i = SPECNAMELEN; + specname[i] = '\0'; + i -= cnp->cn_namelen; + if (i < 0) + goto notfound; + bcopy(cnp->cn_nameptr, specname + i, cnp->cn_namelen); + de = dd; + while (de != dmp->dm_basedir) { + i--; + if (i < 0) + goto notfound; + specname[i] = '/'; + i -= de->de_dirent->d_namlen; + if (i < 0) + goto notfound; + bcopy(de->de_dirent->d_name, specname + i, + de->de_dirent->d_namlen); + de = TAILQ_FIRST(&de->de_dlist); /* "." */ + de = TAILQ_NEXT(de, de_list); /* ".." */ + de = de->de_dir; + } + +#if 0 + printf("Finished specname: %d \"%s\"\n", i, specname + i); +#endif + cdev = NODEV; + EVENTHANDLER_INVOKE(devfs_clone, specname + i, + strlen(specname + i), &cdev); +#if 0 + printf("cloned %s -> %p %s\n", specname + i, cdev, + cdev == NODEV ? "NODEV" : cdev->si_name); +#endif + if (cdev == NODEV) + goto notfound; + + devfs_populate(dmp); + dd = dvp->v_data; + TAILQ_FOREACH(de, &dd->de_dlist, de_list) { + if (cnp->cn_namelen != de->de_dirent->d_namlen) + continue; + if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, + de->de_dirent->d_namlen) != 0) + continue; + goto found; + } + +notfound: + + if ((nameiop == CREATE || nameiop == RENAME) && + (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) { + cnp->cn_flags |= SAVENAME; + if (!(flags & LOCKPARENT)) + VOP_UNLOCK(dvp, 0, p); + return (EJUSTRETURN); + } + return (ENOENT); + + +found: + + if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) { + error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, p); + if (error) + return (error); + if (*vpp == dvp) { + VREF(dvp); + *vpp = dvp; + return (0); + } + error = devfs_allocv(de, dvp->v_mount, vpp, p); + if (error) + return (error); + if (!(flags & LOCKPARENT)) + VOP_UNLOCK(dvp, 0, p); + return (0); + } + error = devfs_allocv(de, dvp->v_mount, vpp, p); + if (error) + return (error); + if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) + VOP_UNLOCK(dvp, 0, p); + return (0); +} + +/* ARGSUSED */ +static int +devfs_print(ap) + struct vop_print_args /* { + struct vnode *a_vp; + } */ *ap; +{ + + printf("tag VT_DEVFS, devfs vnode\n"); return (0); } @@ -515,6 +522,47 @@ devfs_revoke(ap) return (0); } +static int +devfs_setattr(ap) + struct vop_setattr_args /* { + struct vnode *a_vp; + struct vattr *a_vap; + struct ucred *a_cred; + struct proc *a_p; + } */ *ap; +{ + struct devfs_dirent *de; + int c; + + de = ap->a_vp->v_data; + if (ap->a_vp->v_type == VDIR) + de = de->de_dir; + + c = 0; + if (ap->a_vap->va_flags != VNOVAL) + return (EOPNOTSUPP); + if (ap->a_vap->va_uid != (uid_t)VNOVAL) { + de->de_uid = ap->a_vap->va_uid; + c = 1; + } + if (ap->a_vap->va_gid != (gid_t)VNOVAL) { + de->de_gid = ap->a_vap->va_gid; + c = 1; + } + if (ap->a_vap->va_mode != (mode_t)VNOVAL) { + de->de_mode = ap->a_vap->va_mode; + c = 1; + } + if (ap->a_vap->va_atime.tv_sec != VNOVAL) + de->de_atime = ap->a_vap->va_atime; + if (ap->a_vap->va_mtime.tv_sec != VNOVAL) + de->de_mtime = ap->a_vap->va_mtime; + + if (c) + getnanotime(&de->de_ctime); + return (0); +} + static int devfs_symlink(ap) struct vop_symlink_args /* { @@ -530,7 +578,7 @@ devfs_symlink(ap) struct devfs_dirent *de; struct devfs_mount *dmp; - dmp = (struct devfs_mount *)ap->a_dvp->v_mount->mnt_data; + dmp = VFSTODEVFS(ap->a_dvp->v_mount); dd = ap->a_dvp->v_data; de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen); de->de_uid = 0; @@ -543,27 +591,11 @@ devfs_symlink(ap) bcopy(ap->a_target, de->de_symlink, i); TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0); - VREF(*(ap->a_vpp)); return (0); } /* - * Print out the contents of a devfs vnode. - */ -/* ARGSUSED */ -static int -devfs_print(ap) - struct vop_print_args /* { - struct vnode *a_vp; - } */ *ap; -{ - - printf("tag VT_DEVFS, devfs vnode\n"); - return (0); -} - -/* - * Kernfs "should never get here" operation + * DEVFS "should never get here" operation */ static int devfs_badop()