Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys Correct umount semantics to return EBUSY when a filesyst...
details: https://anonhg.NetBSD.org/src/rev/3c53988d222b
branches: trunk
changeset: 786345:3c53988d222b
user: mlelstv <mlelstv%NetBSD.org@localhost>
date: Fri Apr 26 22:27:16 2013 +0000
description:
Correct umount semantics to return EBUSY when a filesystem is busy
instead of failing filesystem operations with EBUSY when attempting
an umount.
This fixes kern/38141.
diffstat:
sys/kern/vfs_mount.c | 57 +++++++++++++++++++++++++++++++++++----------------
sys/sys/mount.h | 6 ++--
2 files changed, 42 insertions(+), 21 deletions(-)
diffs (178 lines):
diff -r 4724adbc8474 -r 3c53988d222b sys/kern/vfs_mount.c
--- a/sys/kern/vfs_mount.c Fri Apr 26 21:20:47 2013 +0000
+++ b/sys/kern/vfs_mount.c Fri Apr 26 22:27:16 2013 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: vfs_mount.c,v 1.17 2013/02/13 14:03:48 hannken Exp $ */
+/* $NetBSD: vfs_mount.c,v 1.18 2013/04/26 22:27:16 mlelstv Exp $ */
/*-
* Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_mount.c,v 1.17 2013/02/13 14:03:48 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_mount.c,v 1.18 2013/04/26 22:27:16 mlelstv Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@@ -139,7 +139,7 @@
mp->mnt_op = vfsops;
mp->mnt_refcnt = 1;
TAILQ_INIT(&mp->mnt_vnodelist);
- rw_init(&mp->mnt_unmounting);
+ mutex_init(&mp->mnt_unmounting, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&mp->mnt_renamelock, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&mp->mnt_updating, MUTEX_DEFAULT, IPL_NONE);
error = vfs_busy(mp, NULL);
@@ -263,7 +263,7 @@
*/
KASSERT(mp->mnt_refcnt == 0);
specificdata_fini(mount_specificdata_domain, &mp->mnt_specdataref);
- rw_destroy(&mp->mnt_unmounting);
+ mutex_destroy(&mp->mnt_unmounting);
mutex_destroy(&mp->mnt_updating);
mutex_destroy(&mp->mnt_renamelock);
if (mp->mnt_op != NULL) {
@@ -276,6 +276,9 @@
* Mark a mount point as busy, and gain a new reference to it. Used to
* prevent the file system from being unmounted during critical sections.
*
+ * vfs_busy can be called multiple times and by multiple threads
+ * and must be accompanied by the same number of vfs_unbusy calls.
+ *
* => The caller must hold a pre-existing reference to the mount.
* => Will fail if the file system is being unmounted, or is unmounted.
*/
@@ -285,21 +288,18 @@
KASSERT(mp->mnt_refcnt > 0);
- if (__predict_false(!rw_tryenter(&mp->mnt_unmounting, RW_READER))) {
- if (nextp != NULL) {
- KASSERT(mutex_owned(&mountlist_lock));
- *nextp = CIRCLEQ_NEXT(mp, mnt_list);
- }
- return EBUSY;
- }
+ mutex_enter(&mp->mnt_unmounting);
if (__predict_false((mp->mnt_iflag & IMNT_GONE) != 0)) {
- rw_exit(&mp->mnt_unmounting);
+ mutex_exit(&mp->mnt_unmounting);
if (nextp != NULL) {
KASSERT(mutex_owned(&mountlist_lock));
*nextp = CIRCLEQ_NEXT(mp, mnt_list);
}
return ENOENT;
}
+ ++mp->mnt_busynest;
+ KASSERT(mp->mnt_busynest != 0);
+ mutex_exit(&mp->mnt_unmounting);
if (nextp != NULL) {
mutex_exit(&mountlist_lock);
}
@@ -310,6 +310,8 @@
/*
* Unbusy a busy filesystem.
*
+ * Every successful vfs_busy() call must be undone by a vfs_unbusy() call.
+ *
* => If keepref is true, preserve reference added by vfs_busy().
* => If nextp != NULL, acquire mountlist_lock.
*/
@@ -322,7 +324,10 @@
if (nextp != NULL) {
mutex_enter(&mountlist_lock);
}
- rw_exit(&mp->mnt_unmounting);
+ mutex_enter(&mp->mnt_unmounting);
+ KASSERT(mp->mnt_busynest != 0);
+ mp->mnt_busynest--;
+ mutex_exit(&mp->mnt_unmounting);
if (!keepref) {
vfs_destroy(mp);
}
@@ -796,9 +801,22 @@
* mount point. See dounmount() for details.
*/
mutex_enter(&syncer_mutex);
- rw_enter(&mp->mnt_unmounting, RW_WRITER);
+
+ /*
+ * Abort unmount attempt when the filesystem is in use
+ */
+ mutex_enter(&mp->mnt_unmounting);
+ if (mp->mnt_busynest != 0) {
+ mutex_exit(&mp->mnt_unmounting);
+ mutex_exit(&syncer_mutex);
+ return EBUSY;
+ }
+
+ /*
+ * Abort unmount attempt when the filesystem is not mounted
+ */
if ((mp->mnt_iflag & IMNT_GONE) != 0) {
- rw_exit(&mp->mnt_unmounting);
+ mutex_exit(&mp->mnt_unmounting);
mutex_exit(&syncer_mutex);
return ENOENT;
}
@@ -821,6 +839,7 @@
mutex_exit(&syncer_mutex);
}
mp->mnt_iflag |= IMNT_UNMOUNT;
+ mutex_enter(&mp->mnt_updating);
async = mp->mnt_flag & MNT_ASYNC;
mp->mnt_flag &= ~MNT_ASYNC;
cache_purgevfs(mp); /* remove cache entries for this file sys */
@@ -835,15 +854,17 @@
error = VFS_UNMOUNT(mp, flags);
}
if (error) {
+ mp->mnt_iflag &= ~IMNT_UNMOUNT;
+ mutex_exit(&mp->mnt_unmounting);
if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0)
(void) vfs_allocate_syncvnode(mp);
- mp->mnt_iflag &= ~IMNT_UNMOUNT;
mp->mnt_flag |= async;
- rw_exit(&mp->mnt_unmounting);
+ mutex_exit(&mp->mnt_updating);
if (used_syncer)
mutex_exit(&syncer_mutex);
return (error);
}
+ mutex_exit(&mp->mnt_updating);
vfs_scrubvnlist(mp);
mutex_enter(&mountlist_lock);
if ((coveredvp = mp->mnt_vnodecovered) != NULLVP)
@@ -856,7 +877,7 @@
if (used_syncer)
mutex_exit(&syncer_mutex);
vfs_hooks_unmount(mp);
- rw_exit(&mp->mnt_unmounting);
+ mutex_exit(&mp->mnt_unmounting);
vfs_destroy(mp); /* reference from mount() */
if (coveredvp != NULLVP) {
vrele(coveredvp);
diff -r 4724adbc8474 -r 3c53988d222b sys/sys/mount.h
--- a/sys/sys/mount.h Fri Apr 26 21:20:47 2013 +0000
+++ b/sys/sys/mount.h Fri Apr 26 22:27:16 2013 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: mount.h,v 1.208 2012/11/05 17:16:18 dholland Exp $ */
+/* $NetBSD: mount.h,v 1.209 2013/04/26 22:27:16 mlelstv Exp $ */
/*
* Copyright (c) 1989, 1991, 1993
@@ -114,10 +114,10 @@
struct vnode *mnt_syncer; /* syncer vnode */
void *mnt_transinfo; /* for FS-internal use */
void *mnt_data; /* private data */
- krwlock_t mnt_unmounting; /* to prevent new activity */
+ kmutex_t mnt_unmounting; /* to prevent new activity */
kmutex_t mnt_renamelock; /* per-fs rename lock */
int mnt_refcnt; /* ref count on this structure */
- int mnt_recursecnt; /* count of write locks */
+ unsigned int mnt_busynest; /* vfs_busy nestings */
int mnt_flag; /* flags */
int mnt_iflag; /* internal flags */
int mnt_fs_bshift; /* offset shift for lblkno */
Home |
Main Index |
Thread Index |
Old Index