Module Name: src Committed By: hannken Date: Tue Jun 15 09:43:37 UTC 2010
Modified Files: src/sys/kern: vfs_syscalls.c Log Message: When mounting a file system re-lookup and lock the directory we mount on after the file system is setup by VFS_MOUNT(). This way recursive vnode locks are no longer needed here and mounts on null mounts no longer fail as described in PR #43439 (mount_null panic: lockdebug_wantlock: locking against myself). Based on a proposal from and Reviewed by: David A. Holland <dholl...@netbsd.org> To generate a diff of this commit: cvs rdiff -u -r1.404 -r1.405 src/sys/kern/vfs_syscalls.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/vfs_syscalls.c diff -u src/sys/kern/vfs_syscalls.c:1.404 src/sys/kern/vfs_syscalls.c:1.405 --- src/sys/kern/vfs_syscalls.c:1.404 Wed Mar 3 00:47:31 2010 +++ src/sys/kern/vfs_syscalls.c Tue Jun 15 09:43:36 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_syscalls.c,v 1.404 2010/03/03 00:47:31 yamt Exp $ */ +/* $NetBSD: vfs_syscalls.c,v 1.405 2010/06/15 09:43:36 hannken Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -66,7 +66,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.404 2010/03/03 00:47:31 yamt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.405 2010/06/15 09:43:36 hannken Exp $"); #ifdef _KERNEL_OPT #include "opt_fileassoc.h" @@ -290,11 +290,12 @@ static int mount_domount(struct lwp *l, struct vnode **vpp, struct vfsops *vfsops, - const char *path, int flags, void *data, size_t *data_len, u_int recurse) + const char *path, int flags, void *data, size_t *data_len) { struct mount *mp; struct vnode *vp = *vpp; struct vattr va; + struct nameidata nd; int error; error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT, @@ -327,19 +328,6 @@ return EINVAL; } - if ((error = vinvalbuf(vp, V_SAVE, l->l_cred, l, 0, 0)) != 0) { - vfs_delref(vfsops); - return error; - } - - /* - * Check if a file-system is not already mounted on this vnode. - */ - if (vp->v_mountedhere != NULL) { - vfs_delref(vfsops); - return EBUSY; - } - if ((mp = vfs_mountalloc(vfsops, vp)) == NULL) { vfs_delref(vfsops); return ENOMEM; @@ -363,30 +351,55 @@ error = VFS_MOUNT(mp, path, data, data_len); mp->mnt_flag &= ~MNT_OP_FLAGS; + if (error != 0) + goto err_unmounted; + /* - * Put the new filesystem on the mount list after root. + * Validate and prepare the mount point. */ - cache_purge(vp); + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, + UIO_USERSPACE, path); + error = namei(&nd); if (error != 0) { - vp->v_mountedhere = NULL; - mutex_exit(&mp->mnt_updating); - vfs_unbusy(mp, false, NULL); - vfs_destroy(mp); - return error; + goto err_mounted; + } + if (nd.ni_vp != vp) { + vput(nd.ni_vp); + error = EINVAL; + goto err_mounted; + } + if (vp->v_mountedhere != NULL) { + vput(nd.ni_vp); + error = EBUSY; + goto err_mounted; + } + error = vinvalbuf(vp, V_SAVE, l->l_cred, l, 0, 0); + if (error != 0) { + vput(nd.ni_vp); + goto err_mounted; } + /* + * Put the new filesystem on the mount list after root. + */ + cache_purge(vp); mp->mnt_iflag &= ~IMNT_WANTRDWR; + mutex_enter(&mountlist_lock); - vp->v_mountedhere = mp; CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); mutex_exit(&mountlist_lock); - vn_restorerecurse(vp, recurse); - VOP_UNLOCK(vp, 0); - checkdirs(vp); if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0) error = vfs_allocate_syncvnode(mp); - /* Hold an additional reference to the mount across VFS_START(). */ + if (error == 0) + vp->v_mountedhere = mp; + vput(nd.ni_vp); + if (error != 0) + goto err_onmountlist; + + checkdirs(vp); mutex_exit(&mp->mnt_updating); + + /* Hold an additional reference to the mount across VFS_START(). */ vfs_unbusy(mp, true, NULL); (void) VFS_STATVFS(mp, &mp->mnt_stat); error = VFS_START(mp, 0); @@ -396,6 +409,24 @@ vfs_destroy(mp); *vpp = NULL; return error; + +err_onmountlist: + mutex_enter(&mountlist_lock); + CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); + mp->mnt_iflag |= IMNT_GONE; + mutex_exit(&mountlist_lock); + +err_mounted: + if (VFS_UNMOUNT(mp, MNT_FORCE) != 0) + panic("Unmounting fresh file system failed"); + +err_unmounted: + vp->v_mountedhere = NULL; + mutex_exit(&mp->mnt_updating); + vfs_unbusy(mp, false, NULL); + vfs_destroy(mp); + + return error; } static int @@ -457,7 +488,6 @@ { struct vnode *vp; void *data_buf = data; - u_int recurse; bool vfsopsrele = false; int error; @@ -470,33 +500,20 @@ */ error = namei_simple_user(path, NSM_FOLLOW_TRYEMULROOT, &vp); if (error != 0) { - /* XXXgcc */ vp = NULL; - recurse = 0; goto done; } - /* - * A lookup in VFS_MOUNT might result in an attempt to - * lock this vnode again, so make the lock recursive. - */ if (vfsops == NULL) { if (flags & (MNT_GETARGS | MNT_UPDATE)) { - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - recurse = vn_setrecurse(vp); vfsops = vp->v_mount->mnt_op; } else { /* 'type' is userspace */ error = mount_get_vfsops(type, &vfsops); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - recurse = vn_setrecurse(vp); if (error != 0) goto done; vfsopsrele = true; } - } else { - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - recurse = vn_setrecurse(vp); } if (data != NULL && data_seg == UIO_USERSPACE) { @@ -540,7 +557,7 @@ /* Locking is handled internally in mount_domount(). */ KASSERT(vfsopsrele == true); error = mount_domount(l, &vp, vfsops, path, flags, data_buf, - &data_len, recurse); + &data_len); vfsopsrele = false; } @@ -548,8 +565,7 @@ if (vfsopsrele) vfs_delref(vfsops); if (vp != NULL) { - vn_restorerecurse(vp, recurse); - vput(vp); + vrele(vp); } if (data_buf != data) kmem_free(data_buf, data_len);