Author: kib
Date: Mon Jul 28 01:23:59 2014
New Revision: 269175
URL: http://svnweb.freebsd.org/changeset/base/269175

Log:
  MFC r268617:
  Rework the tmpfs unmount.

Modified:
  stable/10/sys/fs/tmpfs/tmpfs.h
  stable/10/sys/fs/tmpfs/tmpfs_subr.c
  stable/10/sys/fs/tmpfs/tmpfs_vfsops.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/fs/tmpfs/tmpfs.h
==============================================================================
--- stable/10/sys/fs/tmpfs/tmpfs.h      Mon Jul 28 01:21:02 2014        
(r269174)
+++ stable/10/sys/fs/tmpfs/tmpfs.h      Mon Jul 28 01:23:59 2014        
(r269175)
@@ -384,7 +384,7 @@ struct tmpfs_fid {
  * Prototypes for tmpfs_subr.c.
  */
 
-int    tmpfs_alloc_node(struct tmpfs_mount *, enum vtype,
+int    tmpfs_alloc_node(struct mount *mp, struct tmpfs_mount *, enum vtype,
            uid_t uid, gid_t gid, mode_t mode, struct tmpfs_node *,
            char *, dev_t, struct tmpfs_node **);
 void   tmpfs_free_node(struct tmpfs_mount *, struct tmpfs_node *);

Modified: stable/10/sys/fs/tmpfs/tmpfs_subr.c
==============================================================================
--- stable/10/sys/fs/tmpfs/tmpfs_subr.c Mon Jul 28 01:21:02 2014        
(r269174)
+++ stable/10/sys/fs/tmpfs/tmpfs_subr.c Mon Jul 28 01:23:59 2014        
(r269175)
@@ -159,7 +159,7 @@ tmpfs_pages_check_avail(struct tmpfs_mou
  * Returns zero on success or an appropriate error code on failure.
  */
 int
-tmpfs_alloc_node(struct tmpfs_mount *tmp, enum vtype type,
+tmpfs_alloc_node(struct mount *mp, struct tmpfs_mount *tmp, enum vtype type,
     uid_t uid, gid_t gid, mode_t mode, struct tmpfs_node *parent,
     char *target, dev_t rdev, struct tmpfs_node **node)
 {
@@ -169,6 +169,8 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp
        /* If the root directory of the 'tmp' file system is not yet
         * allocated, this must be the request to do it. */
        MPASS(IMPLIES(tmp->tm_root == NULL, parent == NULL && type == VDIR));
+       KASSERT(tmp->tm_root == NULL || mp->mnt_writeopcount > 0,
+           ("creating node not under vn_start_write"));
 
        MPASS(IFF(type == VLNK, target != NULL));
        MPASS(IFF(type == VBLK || type == VCHR, rdev != VNOVAL));
@@ -178,6 +180,24 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp
        if (tmpfs_pages_check_avail(tmp, 1) == 0)
                return (ENOSPC);
 
+       if ((mp->mnt_kern_flag & MNTK_UNMOUNT) != 0) {
+               /*
+                * When a new tmpfs node is created for fully
+                * constructed mount point, there must be a parent
+                * node, which vnode is locked exclusively.  As
+                * consequence, if the unmount is executing in
+                * parallel, vflush() cannot reclaim the parent vnode.
+                * Due to this, the check for MNTK_UNMOUNT flag is not
+                * racy: if we did not see MNTK_UNMOUNT flag, then tmp
+                * cannot be destroyed until node construction is
+                * finished and the parent vnode unlocked.
+                *
+                * Tmpfs does not need to instantiate new nodes during
+                * unmount.
+                */
+               return (EBUSY);
+       }
+
        nnode = (struct tmpfs_node *)uma_zalloc_arg(
                                tmp->tm_node_pool, tmp, M_WAITOK);
 
@@ -687,7 +707,8 @@ tmpfs_alloc_file(struct vnode *dvp, stru
                parent = NULL;
 
        /* Allocate a node that represents the new file. */
-       error = tmpfs_alloc_node(tmp, vap->va_type, cnp->cn_cred->cr_uid,
+       error = tmpfs_alloc_node(dvp->v_mount, tmp, vap->va_type,
+           cnp->cn_cred->cr_uid,
            dnode->tn_gid, vap->va_mode, parent, target, vap->va_rdev, &node);
        if (error != 0)
                return (error);

Modified: stable/10/sys/fs/tmpfs/tmpfs_vfsops.c
==============================================================================
--- stable/10/sys/fs/tmpfs/tmpfs_vfsops.c       Mon Jul 28 01:21:02 2014        
(r269174)
+++ stable/10/sys/fs/tmpfs/tmpfs_vfsops.c       Mon Jul 28 01:23:59 2014        
(r269175)
@@ -238,7 +238,7 @@ tmpfs_mount(struct mount *mp)
        tmp->tm_ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
 
        /* Allocate the root node. */
-       error = tmpfs_alloc_node(tmp, VDIR, root_uid,
+       error = tmpfs_alloc_node(mp, tmp, VDIR, root_uid,
            root_gid, root_mode & ALLPERMS, NULL, NULL,
            VNOVAL, &root);
 
@@ -269,38 +269,49 @@ tmpfs_mount(struct mount *mp)
 static int
 tmpfs_unmount(struct mount *mp, int mntflags)
 {
-       int error;
-       int flags = 0;
        struct tmpfs_mount *tmp;
        struct tmpfs_node *node;
+       int error, flags;
 
-       /* Handle forced unmounts. */
-       if (mntflags & MNT_FORCE)
-               flags |= FORCECLOSE;
-
-       /* Finalize all pending I/O. */
-       error = vflush(mp, 0, flags, curthread);
-       if (error != 0)
-               return error;
-
+       flags = (mntflags & MNT_FORCE) != 0 ? FORCECLOSE : 0;
        tmp = VFS_TO_TMPFS(mp);
 
-       /* Free all associated data.  The loop iterates over the linked list
-        * we have containing all used nodes.  For each of them that is
-        * a directory, we free all its directory entries.  Note that after
-        * freeing a node, it will automatically go to the available list,
-        * so we will later have to iterate over it to release its items. */
-       node = LIST_FIRST(&tmp->tm_nodes_used);
-       while (node != NULL) {
-               struct tmpfs_node *next;
+       /* Stop writers */
+       error = vfs_write_suspend_umnt(mp);
+       if (error != 0)
+               return (error);
+       /*
+        * At this point, nodes cannot be destroyed by any other
+        * thread because write suspension is started.
+        */
+
+       for (;;) {
+               error = vflush(mp, 0, flags, curthread);
+               if (error != 0) {
+                       vfs_write_resume(mp, VR_START_WRITE);
+                       return (error);
+               }
+               MNT_ILOCK(mp);
+               if (mp->mnt_nvnodelistsize == 0) {
+                       MNT_IUNLOCK(mp);
+                       break;
+               }
+               MNT_IUNLOCK(mp);
+               if ((mntflags & MNT_FORCE) == 0) {
+                       vfs_write_resume(mp, VR_START_WRITE);
+                       return (EBUSY);
+               }
+       }
 
+       TMPFS_LOCK(tmp);
+       while ((node = LIST_FIRST(&tmp->tm_nodes_used)) != NULL) {
+               TMPFS_UNLOCK(tmp);
                if (node->tn_type == VDIR)
                        tmpfs_dir_destroy(tmp, node);
-
-               next = LIST_NEXT(node, tn_entries);
                tmpfs_free_node(tmp, node);
-               node = next;
+               TMPFS_LOCK(tmp);
        }
+       TMPFS_UNLOCK(tmp);
 
        uma_zdestroy(tmp->tm_dirent_pool);
        uma_zdestroy(tmp->tm_node_pool);
@@ -313,11 +324,13 @@ tmpfs_unmount(struct mount *mp, int mntf
        /* Throw away the tmpfs_mount structure. */
        free(mp->mnt_data, M_TMPFSMNT);
        mp->mnt_data = NULL;
+       vfs_write_resume(mp, VR_START_WRITE);
 
        MNT_ILOCK(mp);
        mp->mnt_flag &= ~MNT_LOCAL;
        MNT_IUNLOCK(mp);
-       return 0;
+
+       return (0);
 }
 
 static int
@@ -401,6 +414,18 @@ tmpfs_statfs(struct mount *mp, struct st
        return 0;
 }
 
+static int
+tmpfs_sync(struct mount *mp, int waitfor)
+{
+
+       if (waitfor == MNT_SUSPEND) {
+               MNT_ILOCK(mp);
+               mp->mnt_kern_flag |= MNTK_SUSPEND2 | MNTK_SUSPENDED;
+               MNT_IUNLOCK(mp);
+       }
+       return (0);
+}
+
 /*
  * tmpfs vfs operations.
  */
@@ -411,5 +436,6 @@ struct vfsops tmpfs_vfsops = {
        .vfs_root =                     tmpfs_root,
        .vfs_statfs =                   tmpfs_statfs,
        .vfs_fhtovp =                   tmpfs_fhtovp,
+       .vfs_sync =                     tmpfs_sync,
 };
 VFS_SET(tmpfs_vfsops, tmpfs, VFCF_JAIL);
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to