summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjh <jh@FreeBSD.org>2010-08-22 16:08:12 +0000
committerjh <jh@FreeBSD.org>2010-08-22 16:08:12 +0000
commit6471734221163a849155000055c63f15d80fae6d (patch)
tree13369b484c9a86d80644c4cb8f72bac1f1713a03
parentbf52da60ea59f04f32f405bab687c60a59101d19 (diff)
downloadFreeBSD-src-6471734221163a849155000055c63f15d80fae6d.zip
FreeBSD-src-6471734221163a849155000055c63f15d80fae6d.tar.gz
Introduce and use devfs_populate_vp() to unlock a vnode before calling
devfs_populate(). This is a prerequisite for the automatic removal of empty directories which will be committed in the future. Reviewed by: kib (previous version)
-rw-r--r--sys/fs/devfs/devfs_vnops.c82
1 files changed, 56 insertions, 26 deletions
diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
index abf1dfad..2e106fe 100644
--- a/sys/fs/devfs/devfs_vnops.c
+++ b/sys/fs/devfs/devfs_vnops.c
@@ -185,6 +185,43 @@ devfs_clear_cdevpriv(void)
devfs_fpdrop(fp);
}
+/*
+ * On success devfs_populate_vp() returns with dmp->dm_lock held.
+ */
+static int
+devfs_populate_vp(struct vnode *vp)
+{
+ struct devfs_mount *dmp;
+ int locked;
+
+ ASSERT_VOP_LOCKED(vp, "devfs_populate_vp");
+
+ dmp = VFSTODEVFS(vp->v_mount);
+ locked = VOP_ISLOCKED(vp);
+
+ sx_xlock(&dmp->dm_lock);
+ DEVFS_DMP_HOLD(dmp);
+
+ /* Can't call devfs_populate() with the vnode lock held. */
+ VOP_UNLOCK(vp, 0);
+ devfs_populate(dmp);
+
+ sx_xunlock(&dmp->dm_lock);
+ vn_lock(vp, locked | LK_RETRY);
+ sx_xlock(&dmp->dm_lock);
+ if (DEVFS_DMP_DROP(dmp)) {
+ sx_xunlock(&dmp->dm_lock);
+ devfs_unmount_final(dmp);
+ return (EBADF);
+ }
+ if (vp->v_iflag & VI_DOOMED) {
+ sx_xunlock(&dmp->dm_lock);
+ return (EBADF);
+ }
+
+ return (0);
+}
+
static int
devfs_vptocnp(struct vop_vptocnp_args *ap)
{
@@ -813,14 +850,6 @@ devfs_lookupx(struct vop_lookup_args *ap, int *dm_unlock)
return (error);
}
- DEVFS_DMP_HOLD(dmp);
- devfs_populate(dmp);
- if (DEVFS_DMP_DROP(dmp)) {
- *dm_unlock = 0;
- sx_xunlock(&dmp->dm_lock);
- devfs_unmount_final(dmp);
- return (ENOENT);
- }
dd = dvp->v_data;
de = devfs_find(dd, cnp->cn_nameptr, cnp->cn_namelen, 0);
while (de == NULL) { /* While(...) so we can use break */
@@ -843,7 +872,20 @@ devfs_lookupx(struct vop_lookup_args *ap, int *dm_unlock)
EVENTHANDLER_INVOKE(dev_clone,
td->td_ucred, pname, strlen(pname), &cdev);
sx_sunlock(&clone_drain_lock);
- sx_xlock(&dmp->dm_lock);
+
+ if (cdev == NULL)
+ sx_xlock(&dmp->dm_lock);
+ else if (devfs_populate_vp(dvp) != 0) {
+ *dm_unlock = 0;
+ sx_xlock(&dmp->dm_lock);
+ if (DEVFS_DMP_DROP(dmp)) {
+ sx_xunlock(&dmp->dm_lock);
+ devfs_unmount_final(dmp);
+ } else
+ sx_xunlock(&dmp->dm_lock);
+ dev_rel(cdev);
+ return (ENOENT);
+ }
if (DEVFS_DMP_DROP(dmp)) {
*dm_unlock = 0;
sx_xunlock(&dmp->dm_lock);
@@ -852,19 +894,10 @@ devfs_lookupx(struct vop_lookup_args *ap, int *dm_unlock)
dev_rel(cdev);
return (ENOENT);
}
+
if (cdev == NULL)
break;
- DEVFS_DMP_HOLD(dmp);
- devfs_populate(dmp);
- if (DEVFS_DMP_DROP(dmp)) {
- *dm_unlock = 0;
- sx_xunlock(&dmp->dm_lock);
- devfs_unmount_final(dmp);
- dev_rel(cdev);
- return (ENOENT);
- }
-
dev_lock();
dde = &cdev2priv(cdev)->cdp_dirents[dmp->dm_idx];
if (dde != NULL && *dde != NULL)
@@ -909,9 +942,11 @@ devfs_lookup(struct vop_lookup_args *ap)
struct devfs_mount *dmp;
int dm_unlock;
+ if (devfs_populate_vp(ap->a_dvp) != 0)
+ return (ENOTDIR);
+
dmp = VFSTODEVFS(ap->a_dvp->v_mount);
dm_unlock = 1;
- sx_xlock(&dmp->dm_lock);
j = devfs_lookupx(ap, &dm_unlock);
if (dm_unlock == 1)
sx_xunlock(&dmp->dm_lock);
@@ -1139,12 +1174,7 @@ devfs_readdir(struct vop_readdir_args *ap)
}
dmp = VFSTODEVFS(ap->a_vp->v_mount);
- sx_xlock(&dmp->dm_lock);
- DEVFS_DMP_HOLD(dmp);
- devfs_populate(dmp);
- if (DEVFS_DMP_DROP(dmp)) {
- sx_xunlock(&dmp->dm_lock);
- devfs_unmount_final(dmp);
+ if (devfs_populate_vp(ap->a_vp) != 0) {
if (tmp_ncookies != NULL)
ap->a_ncookies = tmp_ncookies;
return (EIO);
OpenPOWER on IntegriCloud