summaryrefslogtreecommitdiffstats
path: root/sys/fs/devfs/devfs_vnops.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/devfs/devfs_vnops.c')
-rw-r--r--sys/fs/devfs/devfs_vnops.c406
1 files changed, 219 insertions, 187 deletions
diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
index e094589..86444ec 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 @@ loop:
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;
+
+ 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;
- de = ap->a_vp->v_data;
- if (ap->a_vp->v_type == VDIR)
+ if (nameiop == RENAME)
+ return (EOPNOTSUPP);
+
+ 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);
+ }
- 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;
+ 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 (ap->a_vap->va_gid != (gid_t)VNOVAL) {
- de->de_gid = ap->a_vap->va_gid;
- c = 1;
+
+ /*
+ * 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 (ap->a_vap->va_mode != (mode_t)VNOVAL) {
- de->de_mode = ap->a_vap->va_mode;
- c = 1;
+
+#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;
}
- 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);
+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);
}
@@ -516,6 +523,47 @@ devfs_revoke(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;
+ } */ *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 /* {
struct vnode *a_dvp;
@@ -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()
OpenPOWER on IntegriCloud