diff options
author | kan <kan@FreeBSD.org> | 2009-03-02 20:51:39 +0000 |
---|---|---|
committer | kan <kan@FreeBSD.org> | 2009-03-02 20:51:39 +0000 |
commit | e17295cf6f26850137ec6961ede7e51335800027 (patch) | |
tree | 9bdfa8b0a45be61bcefa1da8f539dc8e2b94de30 /sys/kern/vfs_subr.c | |
parent | 59b707a4088dcbed0e291bb0f6a50159053fd9e6 (diff) | |
download | FreeBSD-src-e17295cf6f26850137ec6961ede7e51335800027.zip FreeBSD-src-e17295cf6f26850137ec6961ede7e51335800027.tar.gz |
Change vfs_busy to wait until an outcome of pending unmount
operation is known and to retry or fail accordingly to that
outcome. This fixes the problem with namespace traversing
programs failing with random ENOENT errors if someone just
happened to try to unmount that same filesystem at the same
time.
Reported by: dhw
Reviewed by: kib, attilio
Sponsored by: Juniper Networks, Inc.
Diffstat (limited to 'sys/kern/vfs_subr.c')
-rw-r--r-- | sys/kern/vfs_subr.c | 18 |
1 files changed, 13 insertions, 5 deletions
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 6f1cdf3..9411e81 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -345,7 +345,19 @@ vfs_busy(struct mount *mp, int flags) MNT_ILOCK(mp); MNT_REF(mp); - if (mp->mnt_kern_flag & MNTK_UNMOUNT) { + /* + * If mount point is currenly being unmounted, sleep until the + * mount point fate is decided. If thread doing the unmounting fails, + * it will clear MNTK_UNMOUNT flag before waking us up, indicating + * that this mount point has survived the unmount attempt and vfs_busy + * should retry. Otherwise the unmounter thread will set MNTK_REFEXPIRE + * flag in addition to MNTK_UNMOUNT, indicating that mount point is + * about to be really destroyed. vfs_busy needs to release its + * reference on the mount point in this case and return with ENOENT, + * telling the caller that mount mount it tried to busy is no longer + * valid. + */ + while (mp->mnt_kern_flag & MNTK_UNMOUNT) { if (flags & MBF_NOWAIT || mp->mnt_kern_flag & MNTK_REFEXPIRE) { MNT_REL(mp); MNT_IUNLOCK(mp); @@ -357,12 +369,8 @@ vfs_busy(struct mount *mp, int flags) mtx_unlock(&mountlist_mtx); mp->mnt_kern_flag |= MNTK_MWAIT; msleep(mp, MNT_MTX(mp), PVFS, "vfs_busy", 0); - MNT_REL(mp); - MNT_IUNLOCK(mp); if (flags & MBF_MNTLSTLOCK) mtx_lock(&mountlist_mtx); - CTR1(KTR_VFS, "%s: failed busying after sleep", __func__); - return (ENOENT); } if (flags & MBF_MNTLSTLOCK) mtx_unlock(&mountlist_mtx); |