From owner-svn-src-all@FreeBSD.ORG Mon Jul 28 01:24:00 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id C6EE5D78; Mon, 28 Jul 2014 01:24:00 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id B41522E29; Mon, 28 Jul 2014 01:24:00 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s6S1O0CJ019650; Mon, 28 Jul 2014 01:24:00 GMT (envelope-from kib@svn.freebsd.org) Received: (from kib@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s6S1O043019640; Mon, 28 Jul 2014 01:24:00 GMT (envelope-from kib@svn.freebsd.org) Message-Id: <201407280124.s6S1O043019640@svn.freebsd.org> From: Konstantin Belousov Date: Mon, 28 Jul 2014 01:24:00 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r269175 - stable/10/sys/fs/tmpfs X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 28 Jul 2014 01:24:01 -0000 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);