summaryrefslogtreecommitdiffstats
path: root/sys/fs/devfs/devfs_vnops.c
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2001-05-23 17:48:20 +0000
committerphk <phk@FreeBSD.org>2001-05-23 17:48:20 +0000
commitc8d4d78546538496d4cac6d6cf12ca82333f3913 (patch)
treed31fe437967aeead24106629dcedd2d9bf4f3be8 /sys/fs/devfs/devfs_vnops.c
parentf4106abaf047abe04fb9b76b136b64f9b7ba425c (diff)
downloadFreeBSD-src-c8d4d78546538496d4cac6d6cf12ca82333f3913.zip
FreeBSD-src-c8d4d78546538496d4cac6d6cf12ca82333f3913.tar.gz
Change the way deletes are managed in DEVFS.
This fixes a number of warnings relating to removed cloned devices. It also makes it possible to recreate deleted devices with mknod(2). The major/minor arguments are ignored.
Diffstat (limited to 'sys/fs/devfs/devfs_vnops.c')
-rw-r--r--sys/fs/devfs/devfs_vnops.c154
1 files changed, 113 insertions, 41 deletions
diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
index b73955c..7be4970 100644
--- a/sys/fs/devfs/devfs_vnops.c
+++ b/sys/fs/devfs/devfs_vnops.c
@@ -34,6 +34,13 @@
* $FreeBSD$
*/
+/*
+ * TODO:
+ * remove empty directories
+ * mknod: hunt down DE_DELETED, compare name, reinstantiate.
+ * mkdir: want it ?
+ */
+
#include <opt_devfs.h>
#ifndef NODEVFS
@@ -56,6 +63,7 @@
static int devfs_access __P((struct vop_access_args *ap));
static int devfs_getattr __P((struct vop_getattr_args *ap));
static int devfs_lookupx __P((struct vop_lookup_args *ap));
+static int devfs_mknod __P((struct vop_mknod_args *ap));
static int devfs_print __P((struct vop_print_args *ap));
static int devfs_read __P((struct vop_read_args *ap));
static int devfs_readdir __P((struct vop_readdir_args *ap));
@@ -66,6 +74,42 @@ static int devfs_revoke __P((struct vop_revoke_args *ap));
static int devfs_setattr __P((struct vop_setattr_args *ap));
static int devfs_symlink __P((struct vop_symlink_args *ap));
+/*
+ * Construct the fully qualified path name relative to the mountpoint
+ */
+static char *
+devfs_fqpn(char *buf, struct vnode *dvp, struct componentname *cnp)
+{
+ int i;
+ struct devfs_dirent *de, *dd;
+ struct devfs_mount *dmp;
+
+ dmp = VFSTODEVFS(dvp->v_mount);
+ dd = dvp->v_data;
+ i = SPECNAMELEN;
+ buf[i] = '\0';
+ i -= cnp->cn_namelen;
+ if (i < 0)
+ return (NULL);
+ bcopy(cnp->cn_nameptr, buf + i, cnp->cn_namelen);
+ de = dd;
+ while (de != dmp->dm_basedir) {
+ i--;
+ if (i < 0)
+ return (NULL);
+ buf[i] = '/';
+ i -= de->de_dirent->d_namlen;
+ if (i < 0)
+ return (NULL);
+ bcopy(de->de_dirent->d_name, buf + i,
+ de->de_dirent->d_namlen);
+ de = TAILQ_FIRST(&de->de_dlist); /* "." */
+ de = TAILQ_NEXT(de, de_list); /* ".." */
+ de = de->de_dir;
+ }
+ return (buf + i);
+}
+
int
devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct proc *p)
{
@@ -212,7 +256,7 @@ devfs_lookupx(ap)
struct devfs_dirent *de, *dd;
struct devfs_mount *dmp;
dev_t cdev, *cpdev;
- int error, cloned, i, flags, nameiop;
+ int error, cloned, flags, nameiop;
char specname[SPECNAMELEN + 1], *pname;
cnp = ap->a_cnp;
@@ -276,41 +320,24 @@ devfs_lookupx(ap)
if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name,
de->de_dirent->d_namlen) != 0)
continue;
+ if (de->de_flags & DE_WHITEOUT)
+ goto notfound;
goto found;
}
+ if (nameiop == DELETE)
+ goto notfound;
+
/*
* 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;
- }
+ pname = devfs_fqpn(specname, dvp, cnp);
+ if (pname == NULL)
+ goto notfound;
cdev = NODEV;
- EVENTHANDLER_INVOKE(dev_clone, specname + i,
- strlen(specname + i), &cdev);
+ EVENTHANDLER_INVOKE(dev_clone, pname, strlen(pname), &cdev);
if (cdev == NODEV)
goto notfound;
@@ -375,6 +402,59 @@ devfs_lookup(struct vop_lookup_args *ap)
return (j);
}
+static int
+devfs_mknod(struct vop_mknod_args *ap)
+/*
+struct vop_mknod_args {
+ struct vnodeop_desc *a_desc;
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ struct vattr *a_vap;
+};
+*/
+{
+ struct componentname *cnp;
+ struct vnode *dvp, **vpp;
+ struct proc *p;
+ struct devfs_dirent *dd, *de;
+ struct devfs_mount *dmp;
+ int cloned, flags, nameiop;
+ int error;
+
+ dvp = ap->a_dvp;
+ dmp = VFSTODEVFS(dvp->v_mount);
+ lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curproc);
+
+ cnp = ap->a_cnp;
+ vpp = ap->a_vpp;
+ p = cnp->cn_proc;
+ flags = cnp->cn_flags;
+ nameiop = cnp->cn_nameiop;
+ cloned = 0;
+ dd = dvp->v_data;
+
+ error = ENOENT;
+ 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;
+ if (de->de_flags & DE_WHITEOUT)
+ break;
+ goto notfound;
+ }
+ if (de == NULL)
+ goto notfound;
+ de->de_flags &= ~DE_WHITEOUT;
+ error = devfs_allocv(de, dvp->v_mount, vpp, p);
+notfound:
+ lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc);
+ return (error);
+}
+
+
/* ARGSUSED */
static int
devfs_print(ap)
@@ -436,9 +516,10 @@ devfs_readdir(ap)
devfs_populate(dmp);
error = 0;
de = ap->a_vp->v_data;
- dd = TAILQ_FIRST(&de->de_dlist);
off = 0;
- while (dd != NULL) {
+ TAILQ_FOREACH(dd, &de->de_dlist, de_list) {
+ if (dd->de_flags & DE_WHITEOUT)
+ continue;
if (dd->de_dirent->d_type == DT_DIR)
de = dd->de_dir;
else
@@ -453,7 +534,6 @@ devfs_readdir(ap)
break;
}
off += dp->d_reclen;
- dd = TAILQ_NEXT(dd, de_list);
}
lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc);
uio->uio_offset = off;
@@ -489,11 +569,6 @@ devfs_reclaim(ap)
de = vp->v_data;
if (de != NULL)
de->de_vnode = NULL;
- if (de != NULL && de->de_flags & DE_ORPHAN) {
- if (de->de_symlink)
- FREE(de->de_symlink, M_DEVFS);
- FREE(de, M_DEVFS);
- }
vp->v_data = NULL;
if (vp->v_rdev != NODEV && vp->v_rdev != NULL) {
i = vcount(vp);
@@ -513,17 +588,13 @@ devfs_remove(ap)
{
struct vnode *vp = ap->a_vp;
struct devfs_dirent *dd;
- struct devfs_dirent *de, **dep;
+ struct devfs_dirent *de;
struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount);
lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curproc);
dd = ap->a_dvp->v_data;
de = vp->v_data;
- TAILQ_REMOVE(&dd->de_dlist, de, de_list);
- dep = devfs_itode(dmp, de->de_inode);
- if (dep != NULL)
- *dep = DE_DELETED;
- de->de_flags |= DE_ORPHAN;
+ de->de_flags |= DE_WHITEOUT;
lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curproc);
return (0);
}
@@ -668,6 +739,7 @@ static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = {
{ &vop_access_desc, (vop_t *) devfs_access },
{ &vop_getattr_desc, (vop_t *) devfs_getattr },
{ &vop_lookup_desc, (vop_t *) devfs_lookup },
+ { &vop_mknod_desc, (vop_t *) devfs_mknod },
{ &vop_pathconf_desc, (vop_t *) vop_stdpathconf },
{ &vop_print_desc, (vop_t *) devfs_print },
{ &vop_read_desc, (vop_t *) devfs_read },
OpenPOWER on IntegriCloud