summaryrefslogtreecommitdiffstats
path: root/sys/fs/devfs/devfs_vfsops.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2006-09-18 13:23:08 +0000
committerkib <kib@FreeBSD.org>2006-09-18 13:23:08 +0000
commitecf34f450410ca3aac345b52bece9c0fb4ae459c (patch)
treea22547e48d6aa3545a66b54d100fbcab374bd630 /sys/fs/devfs/devfs_vfsops.c
parente84508ee5e22076fddd4af5d0ca3092768e7e584 (diff)
downloadFreeBSD-src-ecf34f450410ca3aac345b52bece9c0fb4ae459c.zip
FreeBSD-src-ecf34f450410ca3aac345b52bece9c0fb4ae459c.tar.gz
Resolve the devfs deadlock caused by LOR between devfs_mount->dm_lock and
vnode lock in devfs_allocv. Do this by temporary dropping dm_lock around vnode locking. For safe operation, add hold counters for both devfs_mount and devfs_dirent, and DE_DOOMED flag for devfs_dirent. The facilities allow to continue after dropping of the dm_lock, by making sure that referenced memory does not disappear. Reviewed by: tegge Tested by: kris Approved by: kan (mentor) PR: kern/102335
Diffstat (limited to 'sys/fs/devfs/devfs_vfsops.c')
-rw-r--r--sys/fs/devfs/devfs_vfsops.c24
1 files changed, 20 insertions, 4 deletions
diff --git a/sys/fs/devfs/devfs_vfsops.c b/sys/fs/devfs/devfs_vfsops.c
index 17db07a..8c1069a 100644
--- a/sys/fs/devfs/devfs_vfsops.c
+++ b/sys/fs/devfs/devfs_vfsops.c
@@ -77,6 +77,7 @@ devfs_mount(struct mount *mp, struct thread *td)
fmp = malloc(sizeof *fmp, M_DEVFS, M_WAITOK | M_ZERO);
fmp->dm_idx = alloc_unr(devfs_unr);
sx_init(&fmp->dm_lock, "devfsmount");
+ fmp->dm_holdcnt = 1;
mp->mnt_flag |= MNT_LOCAL;
mp->mnt_kern_flag |= MNTK_MPSAFE;
@@ -104,14 +105,25 @@ devfs_mount(struct mount *mp, struct thread *td)
return (0);
}
+void
+devfs_unmount_final(struct devfs_mount *fmp)
+{
+ sx_destroy(&fmp->dm_lock);
+ free(fmp, M_DEVFS);
+}
+
static int
devfs_unmount(struct mount *mp, int mntflags, struct thread *td)
{
int error;
int flags = 0;
struct devfs_mount *fmp;
+ int hold;
+ u_int idx;
fmp = VFSTODEVFS(mp);
+ KASSERT(fmp->dm_mount != NULL,
+ ("devfs_unmount unmounted devfs_mount"));
/* There is 1 extra root vnode reference from devfs_mount(). */
error = vflush(mp, 1, flags, td);
if (error)
@@ -119,11 +131,14 @@ devfs_unmount(struct mount *mp, int mntflags, struct thread *td)
sx_xlock(&fmp->dm_lock);
devfs_cleanup(fmp);
devfs_rules_cleanup(fmp);
- sx_xunlock(&fmp->dm_lock);
+ fmp->dm_mount = NULL;
+ hold = --fmp->dm_holdcnt;
mp->mnt_data = NULL;
- sx_destroy(&fmp->dm_lock);
- free_unr(devfs_unr, fmp->dm_idx);
- free(fmp, M_DEVFS);
+ idx = fmp->dm_idx;
+ sx_xunlock(&fmp->dm_lock);
+ free_unr(devfs_unr, idx);
+ if (hold == 0)
+ devfs_unmount_final(fmp);
return 0;
}
@@ -137,6 +152,7 @@ devfs_root(struct mount *mp, int flags, struct vnode **vpp, struct thread *td)
struct devfs_mount *dmp;
dmp = VFSTODEVFS(mp);
+ sx_xlock(&dmp->dm_lock);
error = devfs_allocv(dmp->dm_rootdir, mp, &vp, td);
if (error)
return (error);
OpenPOWER on IntegriCloud