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