tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
rename locking hacks
The following patches fix some race conditions in rename(). (They do
not fix *all* the races. That will require a complete rewrite. This
patch is meant for pullup to release branches, which will be painful
enough as it is.)
The introduction of a per-fs rename lock is necessary to make the
parent check atomic with the lookups, and is not a hack. The new
relookup() is a hack.
I have not made the new vfsops functions (per ad's recent commit)
because that's for getting locks, and all these ops *do* is get a lock
by transiting data structures that ought to be read-only while their
fs is live. However, I can change this if anyone has a strong opinion.
Thanks to ad and pooka for reviewing an earlier rev of this patch and
catching a couple of my stupid mistakes.
------
diff -r 91bfce55661d sys/coda/coda_vfsops.c
--- a/sys/coda/coda_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/coda/coda_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -73,6 +73,7 @@ __KERNEL_RCSID(0, "$NetBSD: coda_vfsops.
#include <coda/coda_opstats.h>
/* for VN_RDEV */
#include <miscfs/specfs/specdev.h>
+#include <miscfs/genfs/genfs.h>
MALLOC_DEFINE(M_CODA, "coda", "Coda file system structures and tables");
@@ -121,6 +122,8 @@ struct vfsops coda_vfsops = {
(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
coda_vnodeopv_descs,
0, /* vfs_refcount */
{ NULL, NULL }, /* vfs_list */
diff -r 91bfce55661d sys/conf/files
--- a/sys/conf/files Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/conf/files Sun Jan 13 12:18:49 2008 -0500
@@ -1462,6 +1462,7 @@ file miscfs/deadfs/dead_vnops.c
file miscfs/deadfs/dead_vnops.c
file miscfs/fifofs/fifo_vnops.c
file miscfs/genfs/genfs_io.c
+file miscfs/genfs/genfs_vfsops.c
file miscfs/genfs/genfs_vnops.c
file miscfs/genfs/layer_subr.c nullfs | overlay | umapfs | lkm
file miscfs/genfs/layer_vfsops.c nullfs | overlay | umapfs | lkm
diff -r 91bfce55661d sys/fs/adosfs/advfsops.c
--- a/sys/fs/adosfs/advfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/fs/adosfs/advfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -48,6 +48,7 @@ __KERNEL_RCSID(0, "$NetBSD: advfsops.c,v
#include <sys/malloc.h>
#include <sys/pool.h>
#include <sys/disklabel.h>
+#include <miscfs/genfs/genfs.h>
#include <miscfs/specfs/specdev.h> /* XXX */
#include <sys/fcntl.h>
#include <sys/namei.h>
@@ -837,6 +838,8 @@ struct vfsops adosfs_vfsops = {
(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
adosfs_vnodeopv_descs,
0,
{ NULL, NULL },
diff -r 91bfce55661d sys/fs/cd9660/cd9660_vfsops.c
--- a/sys/fs/cd9660/cd9660_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/fs/cd9660/cd9660_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -50,6 +50,7 @@ __KERNEL_RCSID(0, "$NetBSD: cd9660_vfsop
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
+#include <miscfs/genfs/genfs.h>
#include <miscfs/specfs/specdev.h>
#include <sys/mount.h>
#include <sys/buf.h>
@@ -105,6 +106,8 @@ struct vfsops cd9660_vfsops = {
(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
cd9660_vnodeopv_descs,
0, /* refcount */
{ NULL, NULL } /* list */
diff -r 91bfce55661d sys/fs/filecorefs/filecore_vfsops.c
--- a/sys/fs/filecorefs/filecore_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/fs/filecorefs/filecore_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -77,6 +77,7 @@ __KERNEL_RCSID(0, "$NetBSD: filecore_vfs
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/vnode.h>
+#include <miscfs/genfs/genfs.h>
#include <miscfs/specfs/specdev.h>
#include <sys/mount.h>
#include <sys/buf.h>
@@ -126,6 +127,8 @@ struct vfsops filecore_vfsops = {
(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
filecore_vnodeopv_descs,
0,
{ NULL, NULL }
diff -r 91bfce55661d sys/fs/hfs/hfs_vfsops.c
--- a/sys/fs/hfs/hfs_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/fs/hfs/hfs_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -128,6 +128,7 @@ __KERNEL_RCSID(0, "$NetBSD: hfs_vfsops.c
#include <sys/kauth.h>
#include <sys/stat.h>
+#include <miscfs/genfs/genfs.h>
#include <miscfs/specfs/specdev.h>
#include <fs/hfs/hfs.h>
@@ -164,6 +165,8 @@ struct vfsops hfs_vfsops = {
NULL, /* vfs_snapshot */
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
hfs_vnodeopv_descs,
0,
{ NULL, NULL },
diff -r 91bfce55661d sys/fs/msdosfs/msdosfs_vfsops.c
--- a/sys/fs/msdosfs/msdosfs_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/fs/msdosfs/msdosfs_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -62,6 +62,7 @@ __KERNEL_RCSID(0, "$NetBSD: msdosfs_vfso
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
+#include <miscfs/genfs/genfs.h>
#include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */
#include <sys/mount.h>
#include <sys/buf.h>
@@ -132,6 +133,8 @@ struct vfsops msdosfs_vfsops = {
(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
msdosfs_vnodeopv_descs,
0,
{ NULL, NULL },
diff -r 91bfce55661d sys/fs/ntfs/ntfs_vfsops.c
--- a/sys/fs/ntfs/ntfs_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/fs/ntfs/ntfs_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -52,6 +52,7 @@ __KERNEL_RCSID(0, "$NetBSD: ntfs_vfsops.
#include <vm/vm.h>
#endif
+#include <miscfs/genfs/genfs.h>
#include <miscfs/specfs/specdev.h>
#include <fs/ntfs/ntfs.h>
@@ -1015,6 +1016,8 @@ struct vfsops ntfs_vfsops = {
(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
ntfs_vnodeopv_descs,
0,
{ NULL, NULL },
diff -r 91bfce55661d sys/fs/ptyfs/ptyfs_vfsops.c
--- a/sys/fs/ptyfs/ptyfs_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/fs/ptyfs/ptyfs_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -59,6 +59,7 @@ __KERNEL_RCSID(0, "$NetBSD: ptyfs_vfsops
#include <sys/kauth.h>
#include <fs/ptyfs/ptyfs.h>
+#include <miscfs/genfs/genfs.h>
#include <miscfs/specfs/specdev.h>
MALLOC_JUSTDEFINE(M_PTYFSMNT, "ptyfs mount", "ptyfs mount structures");
@@ -393,6 +394,8 @@ struct vfsops ptyfs_vfsops = {
(void *)eopnotsupp,
(void *)eopnotsupp,
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
ptyfs_vnodeopv_descs,
0,
{ NULL, NULL },
diff -r 91bfce55661d sys/fs/puffs/puffs_vfsops.c
--- a/sys/fs/puffs/puffs_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/fs/puffs/puffs_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -44,6 +44,8 @@ __KERNEL_RCSID(0, "$NetBSD: puffs_vfsops
#include <sys/proc.h>
#include <dev/putter/putter_sys.h>
+
+#include <miscfs/genfs/genfs.h>
#include <fs/puffs/puffs_msgif.h>
#include <fs/puffs/puffs_sys.h>
@@ -828,6 +830,8 @@ struct vfsops puffs_vfsops = {
puffs_vfsop_snapshot, /* snapshot */
vfs_stdextattrctl, /* extattrctl */
puffs_vfsop_suspendctl, /* suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
puffs_vnodeopv_descs, /* vnodeops */
0, /* refcount */
{ NULL, NULL }
diff -r 91bfce55661d sys/fs/smbfs/smbfs_vfsops.c
--- a/sys/fs/smbfs/smbfs_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/fs/smbfs/smbfs_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -53,6 +53,7 @@ __KERNEL_RCSID(0, "$NetBSD: smbfs_vfsops
#include <sys/stat.h>
#include <sys/malloc.h>
#include <sys/kauth.h>
+#include <miscfs/genfs/genfs.h>
#include <netsmb/smb.h>
@@ -128,6 +129,8 @@ struct vfsops smbfs_vfsops = {
(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
smbfs_vnodeopv_descs,
0, /* vfs_refcount */
{ NULL, NULL },
diff -r 91bfce55661d sys/fs/sysvbfs/sysvbfs.c
--- a/sys/fs/sysvbfs/sysvbfs.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/fs/sysvbfs/sysvbfs.c Sun Jan 13 12:18:49 2008 -0500
@@ -134,6 +134,8 @@ struct vfsops sysvbfs_vfsops = {
eopnotsupp, /* snapshot */
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
sysvbfs_vnodeopv_descs,
0,
{ NULL, NULL }
diff -r 91bfce55661d sys/fs/tmpfs/tmpfs_vfsops.c
--- a/sys/fs/tmpfs/tmpfs_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/fs/tmpfs/tmpfs_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -60,6 +60,7 @@ __KERNEL_RCSID(0, "$NetBSD: tmpfs_vfsops
#include <sys/vnode.h>
#include <sys/proc.h>
+#include <miscfs/genfs/genfs.h>
#include <fs/tmpfs/tmpfs.h>
/* --------------------------------------------------------------------- */
@@ -440,6 +441,8 @@ struct vfsops tmpfs_vfsops = {
tmpfs_snapshot, /* vfs_snapshot */
vfs_stdextattrctl, /* vfs_extattrctl */
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
tmpfs_vnodeopv_descs,
0, /* vfs_refcount */
{ NULL, NULL },
diff -r 91bfce55661d sys/fs/udf/udf_vfsops.c
--- a/sys/fs/udf/udf_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/fs/udf/udf_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -52,6 +52,7 @@ __KERNEL_RCSID(0, "$NetBSD: udf_vfsops.c
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
+#include <miscfs/genfs/genfs.h>
#include <miscfs/specfs/specdev.h>
#include <sys/mount.h>
#include <sys/buf.h>
@@ -129,6 +130,8 @@ struct vfsops udf_vfsops = {
udf_snapshot,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
udf_vnodeopv_descs,
0, /* int vfs_refcount */
{ NULL, NULL, }, /* LIST_ENTRY(vfsops) */
diff -r 91bfce55661d sys/fs/union/union_vfsops.c
--- a/sys/fs/union/union_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/fs/union/union_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -481,6 +481,23 @@ union_vget(struct mount *mp, ino_t ino,
return (EOPNOTSUPP);
}
+static int
+union_renamelock_enter(struct mount *mp)
+{
+ struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
+
+ /* Lock just the upper fs, where the action happens. */
+ return VFS_RENAMELOCK_ENTER(um->um_uppervp->v_mount);
+}
+
+static void
+union_renamelock_exit(struct mount *mp)
+{
+ struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
+
+ VFS_RENAMELOCK_EXIT(um->um_uppervp->v_mount);
+}
+
SYSCTL_SETUP(sysctl_vfs_union_setup, "sysctl vfs.union subtree setup")
{
@@ -529,6 +546,8 @@ struct vfsops union_vfsops = {
(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ union_renamelock_enter,
+ union_renamelock_exit,
union_vnodeopv_descs,
0, /* vfs_refcount */
{ NULL, NULL },
diff -r 91bfce55661d sys/kern/vfs_subr2.c
--- a/sys/kern/vfs_subr2.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/kern/vfs_subr2.c Sun Jan 13 12:18:49 2008 -0500
@@ -198,6 +198,7 @@ vfs_destroy(struct mount *mp)
{
specificdata_fini(mount_specificdata_domain, &mp->mnt_specdataref);
+ mutex_destroy(&mp->mnt_renamelock);
mutex_destroy(&mp->mnt_mutex);
lockdestroy(&mp->mnt_lock);
free(mp, M_MOUNT);
diff -r 91bfce55661d sys/kern/vfs_syscalls.c
--- a/sys/kern/vfs_syscalls.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/kern/vfs_syscalls.c Sun Jan 13 12:18:49 2008 -0500
@@ -306,6 +306,7 @@ mount_domount(struct lwp *l, struct vnod
TAILQ_INIT(&mp->mnt_vnodelist);
lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
mutex_init(&mp->mnt_mutex, MUTEX_DEFAULT, IPL_NONE);
+ mutex_init(&mp->mnt_renamelock, MUTEX_DEFAULT, IPL_NONE);
(void)vfs_busy(mp, LK_NOWAIT, 0);
mp->mnt_vnodecovered = vp;
@@ -3291,8 +3292,10 @@ do_sys_rename(const char *from, const ch
{
struct vnode *tvp, *fvp, *tdvp;
struct nameidata fromnd, tond;
+ struct mount *fs;
struct lwp *l = curlwp;
struct proc *p;
+ uint32_t saveflag;
int error;
NDINIT(&fromnd, DELETE, LOCKPARENT | SAVESTART | TRYEMULROOT,
@@ -3302,11 +3305,57 @@ do_sys_rename(const char *from, const ch
if (fromnd.ni_dvp != fromnd.ni_vp)
VOP_UNLOCK(fromnd.ni_dvp, 0);
fvp = fromnd.ni_vp;
+
+ fs = fvp->v_mount;
+ error = VFS_RENAMELOCK_ENTER(fs);
+ if (error) {
+ VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
+ vrele(fromnd.ni_dvp);
+ vrele(fvp);
+ goto out1;
+ }
+
+ /*
+ * close, partially, yet another race - ideally we should only
+ * go as far as getting fromnd.ni_dvp before getting the per-fs
+ * lock, and then continue to get fromnd.ni_vp, but we can't do
+ * that with namei as it stands.
+ *
+ * This still won't prevent rmdir from nuking fromnd.ni_vp
+ * under us. The real fix is to get the locks in the right
+ * order and do the lookups in the right places, but that's a
+ * major rototill.
+ *
+ * Preserve the SAVESTART in cn_flags, because who knows what
+ * might happen if we don't.
+ *
+ * Note: this logic (as well as this whole function) is cloned
+ * in nfs_serv.c. Proceed accordingly.
+ */
+ vrele(fvp);
+ saveflag = fromnd.ni_cnd.cn_flags & SAVESTART;
+ fromnd.ni_cnd.cn_flags &= ~SAVESTART;
+ vn_lock(fromnd.ni_dvp, LK_EXCLUSIVE | LK_RETRY);
+ error = relookup(fromnd.ni_dvp, &fromnd.ni_vp, &fromnd.ni_cnd);
+ fromnd.ni_cnd.cn_flags |= saveflag;
+ if (error) {
+ VOP_UNLOCK(fromnd.ni_dvp, 0);
+ VFS_RENAMELOCK_EXIT(fs);
+ VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
+ vrele(fromnd.ni_dvp);
+ goto out1;
+ }
+ VOP_UNLOCK(fromnd.ni_vp, 0);
+ if (fromnd.ni_dvp != fromnd.ni_vp)
+ VOP_UNLOCK(fromnd.ni_dvp, 0);
+ fvp = fromnd.ni_vp;
+
NDINIT(&tond, RENAME,
LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | TRYEMULROOT
| (fvp->v_type == VDIR ? CREATEDIR : 0),
seg, to);
if ((error = namei(&tond)) != 0) {
+ VFS_RENAMELOCK_EXIT(fs);
VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
vrele(fromnd.ni_dvp);
vrele(fvp);
@@ -3370,6 +3419,7 @@ out:
}
error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
+ VFS_RENAMELOCK_EXIT(fs);
} else {
VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
if (tdvp == tvp)
@@ -3378,6 +3428,7 @@ out:
vput(tdvp);
if (tvp)
vput(tvp);
+ VFS_RENAMELOCK_EXIT(fs);
VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
vrele(fromnd.ni_dvp);
vrele(fvp);
diff -r 91bfce55661d sys/miscfs/fdesc/fdesc_vfsops.c
--- a/sys/miscfs/fdesc/fdesc_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/miscfs/fdesc/fdesc_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -61,6 +61,7 @@ __KERNEL_RCSID(0, "$NetBSD: fdesc_vfsops
#include <sys/malloc.h>
#include <sys/kauth.h>
+#include <miscfs/genfs/genfs.h>
#include <miscfs/fdesc/fdesc.h>
VFS_PROTOS(fdesc);
@@ -277,6 +278,8 @@ struct vfsops fdesc_vfsops = {
(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
fdesc_vnodeopv_descs,
0,
{ NULL, NULL},
diff -r 91bfce55661d sys/miscfs/genfs/genfs.h
--- a/sys/miscfs/genfs/genfs.h Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/miscfs/genfs/genfs.h Sun Jan 13 12:18:49 2008 -0500
@@ -28,3 +28,6 @@ int genfs_compat_getpages(void *);
int genfs_compat_getpages(void *);
int genfs_do_putpages(struct vnode *, off_t, off_t, int, struct vm_page **);
+
+int genfs_renamelock_enter(struct mount *);
+void genfs_renamelock_exit(struct mount *);
diff -r 91bfce55661d sys/miscfs/genfs/genfs_vfsops.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/miscfs/genfs/genfs_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -0,0 +1,63 @@
+/* $NetBSD: foo $ */
+
+/*-
+ * Copyright (c) 2008 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by David A. Holland.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: foo $");
+
+#include <sys/types.h>
+#include <sys/mount.h>
+
+/* required by genfs.h */
+#include <uvm/uvm.h>
+
+#include <miscfs/genfs/genfs.h>
+#include <miscfs/genfs/genfs_node.h>
+
+int
+genfs_renamelock_enter(struct mount *mp)
+{
+ mutex_enter(&mp->mnt_renamelock);
+ /* Preserve possible error return in case we become interruptible. */
+ return 0;
+}
+
+void
+genfs_renamelock_exit(struct mount *mp)
+{
+ mutex_exit(&mp->mnt_renamelock);
+}
diff -r 91bfce55661d sys/miscfs/genfs/layer_extern.h
--- a/sys/miscfs/genfs/layer_extern.h Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/miscfs/genfs/layer_extern.h Sun Jan 13 12:18:49 2008 -0500
@@ -92,6 +92,8 @@ int layerfs_vptofh(struct vnode *, struc
int layerfs_vptofh(struct vnode *, struct fid *, size_t *);
int layerfs_snapshot(struct mount *, struct vnode *,
struct timespec *);
+int layerfs_renamelock_enter(struct mount *);
+void layerfs_renamelock_exit(struct mount *);
/* VOP routines */
int layer_bypass(void *);
diff -r 91bfce55661d sys/miscfs/genfs/layer_vfsops.c
--- a/sys/miscfs/genfs/layer_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/miscfs/genfs/layer_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -307,3 +307,15 @@ SYSCTL_SETUP(sysctl_vfs_layerfs_setup, "
* can't do that...not easily. not yet. :-)
*/
}
+
+int
+layerfs_renamelock_enter(struct mount *mp)
+{
+ return VFS_RENAMELOCK_ENTER(MOUNTTOLAYERMOUNT(mp)->layerm_vfs);
+}
+
+void
+layerfs_renamelock_exit(struct mount *mp)
+{
+ VFS_RENAMELOCK_EXIT(MOUNTTOLAYERMOUNT(mp)->layerm_vfs);
+}
diff -r 91bfce55661d sys/miscfs/kernfs/kernfs_vfsops.c
--- a/sys/miscfs/kernfs/kernfs_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/miscfs/kernfs/kernfs_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -58,6 +58,7 @@ __KERNEL_RCSID(0, "$NetBSD: kernfs_vfsop
#include <sys/syslog.h>
#include <sys/kauth.h>
+#include <miscfs/genfs/genfs.h>
#include <miscfs/specfs/specdev.h>
#include <miscfs/kernfs/kernfs.h>
@@ -281,6 +282,8 @@ struct vfsops kernfs_vfsops = {
(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
kernfs_vnodeopv_descs,
0,
{ NULL, NULL },
diff -r 91bfce55661d sys/miscfs/nullfs/null_vfsops.c
--- a/sys/miscfs/nullfs/null_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/miscfs/nullfs/null_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -296,6 +296,8 @@ struct vfsops nullfs_vfsops = {
layerfs_snapshot,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ layerfs_renamelock_enter,
+ layerfs_renamelock_exit,
nullfs_vnodeopv_descs,
0,
{ NULL, NULL },
diff -r 91bfce55661d sys/miscfs/overlay/overlay_vfsops.c
--- a/sys/miscfs/overlay/overlay_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/miscfs/overlay/overlay_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -273,6 +273,8 @@ struct vfsops overlay_vfsops = {
layerfs_snapshot,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ layerfs_renamelock_enter,
+ layerfs_renamelock_exit,
ov_vnodeopv_descs,
0,
{ NULL, NULL },
diff -r 91bfce55661d sys/miscfs/portal/portal_vfsops.c
--- a/sys/miscfs/portal/portal_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/miscfs/portal/portal_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -65,6 +65,8 @@ __KERNEL_RCSID(0, "$NetBSD: portal_vfsop
#include <sys/dirent.h>
#include <sys/un.h>
#include <sys/kauth.h>
+
+#include <miscfs/genfs/genfs.h>
#include <miscfs/portal/portal.h>
@@ -304,6 +306,8 @@ struct vfsops portal_vfsops = {
(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
portal_vnodeopv_descs,
0,
{ NULL, NULL },
diff -r 91bfce55661d sys/miscfs/procfs/procfs_vfsops.c
--- a/sys/miscfs/procfs/procfs_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/miscfs/procfs/procfs_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -96,6 +96,8 @@ __KERNEL_RCSID(0, "$NetBSD: procfs_vfsop
#include <sys/vnode.h>
#include <sys/malloc.h>
#include <sys/kauth.h>
+
+#include <miscfs/genfs/genfs.h>
#include <miscfs/procfs/procfs.h>
@@ -312,6 +314,8 @@ struct vfsops procfs_vfsops = {
(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
procfs_vnodeopv_descs,
0,
{ NULL, NULL },
diff -r 91bfce55661d sys/miscfs/umapfs/umap_vfsops.c
--- a/sys/miscfs/umapfs/umap_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/miscfs/umapfs/umap_vfsops.c Sun Jan 13 12:18:49 2008 -0500
@@ -316,6 +316,8 @@ struct vfsops umapfs_vfsops = {
layerfs_snapshot,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ layerfs_renamelock_enter,
+ layerfs_renamelock_exit,
umapfs_vnodeopv_descs,
0, /* vfs_refcount */
{ NULL, NULL },
diff -r 91bfce55661d sys/nfs/nfs_serv.c
--- a/sys/nfs/nfs_serv.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/nfs/nfs_serv.c Sun Jan 13 12:18:49 2008 -0500
@@ -1824,10 +1824,12 @@ nfsrv_rename(nfsd, slp, lwp, mrq)
struct nameidata fromnd, tond;
struct vnode *fvp, *tvp, *tdvp;
struct vnode *fdirp = NULL, *tdirp = NULL;
+ struct mount *localfs = NULL;
struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
nfsrvfh_t fnsfh, tnsfh;
u_quad_t frev;
uid_t saved_uid;
+ uint32_t saveflag;
#ifndef nolint
fvp = (struct vnode *)0;
@@ -1861,6 +1863,35 @@ nfsrv_rename(nfsd, slp, lwp, mrq)
VOP_UNLOCK(fromnd.ni_dvp, 0);
}
fvp = fromnd.ni_vp;
+
+ localfs = fvp->v_mount;
+ error = VFS_RENAMELOCK_ENTER(localfs);
+ if (error) {
+ VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
+ vrele(fromnd.ni_dvp);
+ vrele(fvp);
+ goto out1;
+ }
+
+ /* Copied, regrettably, from vfs_syscalls.c (q.v.) */
+ vrele(fvp);
+ saveflag = fromnd.ni_cnd.cn_flags & SAVESTART;
+ fromnd.ni_cnd.cn_flags &= ~SAVESTART;
+ vn_lock(fromnd.ni_dvp, LK_EXCLUSIVE | LK_RETRY);
+ error = relookup(fromnd.ni_dvp, &fromnd.ni_vp, &fromnd.ni_cnd);
+ fromnd.ni_cnd.cn_flags |= saveflag;
+ if (error) {
+ VOP_UNLOCK(fromnd.ni_dvp, 0);
+ VFS_RENAMELOCK_EXIT(localfs);
+ VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
+ vrele(fromnd.ni_dvp);
+ goto out1;
+ }
+ VOP_UNLOCK(fromnd.ni_vp, 0);
+ if (fromnd.ni_dvp != fromnd.ni_vp)
+ VOP_UNLOCK(fromnd.ni_dvp, 0);
+ fvp = fromnd.ni_vp;
+
nfsm_srvmtofh(&tnsfh);
if (v3) {
nfsm_dissect(tl, uint32_t *, NFSX_UNSIGNED);
@@ -1881,6 +1912,7 @@ nfsrv_rename(nfsd, slp, lwp, mrq)
tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred);
}
if (error) {
+ VFS_RENAMELOCK_EXIT(localfs);
VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
vrele(fromnd.ni_dvp);
vrele(fvp);
@@ -1949,6 +1981,7 @@ out:
}
error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
+ VFS_RENAMELOCK_EXIT(localfs);
} else {
VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
if (tdvp == tvp)
@@ -1957,6 +1990,7 @@ out:
vput(tdvp);
if (tvp)
vput(tvp);
+ VFS_RENAMELOCK_EXIT(localfs);
VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
vrele(fromnd.ni_dvp);
vrele(fvp);
@@ -1997,6 +2031,9 @@ nfsmout:
if (tond.ni_cnd.cn_nameiop) {
vrele(tond.ni_startdir);
PNBUF_PUT(tond.ni_cnd.cn_pnbuf);
+ }
+ if (localfs) {
+ VFS_RENAMELOCK_EXIT(localfs);
}
if (fromnd.ni_cnd.cn_nameiop) {
vrele(fromnd.ni_startdir);
diff -r 91bfce55661d sys/nfs/nfs_vfsops.c
--- a/sys/nfs/nfs_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/nfs/nfs_vfsops.c Sun Jan 13 12:18:50 2008 -0500
@@ -119,6 +119,8 @@ struct vfsops nfs_vfsops = {
(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
nfs_vnodeopv_descs,
0,
{ NULL, NULL },
diff -r 91bfce55661d sys/sys/mount.h
--- a/sys/sys/mount.h Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/sys/mount.h Sun Jan 13 12:18:50 2008 -0500
@@ -115,6 +115,7 @@ struct mount {
int mnt_wcnt; /* count of vfs_busy waiters */
struct lwp *mnt_unmounter; /* who is unmounting */
kmutex_t mnt_mutex; /* mutex for wcnt */
+ kmutex_t mnt_renamelock; /* per-fs rename lock */
void *mnt_transinfo; /* for FS-internal use */
specificdata_reference
mnt_specdataref; /* subsystem specific data */
@@ -210,6 +211,8 @@ struct vfsops {
int (*vfs_extattrctl) (struct mount *, int,
struct vnode *, int, const char *);
int (*vfs_suspendctl) (struct mount *, int);
+ int (*vfs_renamelock_enter)(struct mount *);
+ void (*vfs_renamelock_exit)(struct mount *);
const struct vnodeopv_desc * const *vfs_opv_descs;
int vfs_refcount;
LIST_ENTRY(vfsops) vfs_list;
@@ -217,6 +220,8 @@ struct vfsops {
/* XXX Actually file system internal. */
#define VFS_VGET(MP, INO, VPP) (*(MP)->mnt_op->vfs_vget)(MP, INO, VPP)
+#define VFS_RENAMELOCK_ENTER(MP) (*(MP)->mnt_op->vfs_renamelock_enter)(MP)
+#define VFS_RENAMELOCK_EXIT(MP) (*(MP)->mnt_op->vfs_renamelock_exit)(MP)
int VFS_MOUNT(struct mount *, const char *, void *, size_t *);
int VFS_START(struct mount *, int);
diff -r 91bfce55661d sys/ufs/ext2fs/ext2fs_vfsops.c
--- a/sys/ufs/ext2fs/ext2fs_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/ufs/ext2fs/ext2fs_vfsops.c Sun Jan 13 12:18:50 2008 -0500
@@ -93,6 +93,7 @@ __KERNEL_RCSID(0, "$NetBSD: ext2fs_vfsop
#include <sys/conf.h>
#include <sys/kauth.h>
+#include <miscfs/genfs/genfs.h>
#include <miscfs/specfs/specdev.h>
#include <ufs/ufs/quota.h>
@@ -141,6 +142,8 @@ struct vfsops ext2fs_vfsops = {
(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
ext2fs_vnodeopv_descs,
0,
{ NULL, NULL },
diff -r 91bfce55661d sys/ufs/ffs/ffs_vfsops.c
--- a/sys/ufs/ffs/ffs_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/ufs/ffs/ffs_vfsops.c Sun Jan 13 12:18:50 2008 -0500
@@ -63,6 +63,7 @@ __KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c
#include <sys/kauth.h>
#include <sys/fstrans.h>
+#include <miscfs/genfs/genfs.h>
#include <miscfs/specfs/specdev.h>
#include <ufs/ufs/quota.h>
@@ -111,6 +112,8 @@ struct vfsops ffs_vfsops = {
ffs_snapshot,
ffs_extattrctl,
ffs_suspendctl,
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
ffs_vnodeopv_descs,
0,
{ NULL, NULL },
diff -r 91bfce55661d sys/ufs/lfs/lfs_vfsops.c
--- a/sys/ufs/lfs/lfs_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/ufs/lfs/lfs_vfsops.c Sun Jan 13 12:18:50 2008 -0500
@@ -159,6 +159,8 @@ struct vfsops lfs_vfsops = {
(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
lfs_vnodeopv_descs,
0,
{ NULL, NULL },
diff -r 91bfce55661d sys/ufs/mfs/mfs_vfsops.c
--- a/sys/ufs/mfs/mfs_vfsops.c Sun Jan 13 12:17:59 2008 -0500
+++ b/sys/ufs/mfs/mfs_vfsops.c Sun Jan 13 12:18:50 2008 -0500
@@ -51,6 +51,7 @@ __KERNEL_RCSID(0, "$NetBSD: mfs_vfsops.c
#include <sys/vnode.h>
#include <sys/malloc.h>
+#include <miscfs/genfs/genfs.h>
#include <miscfs/syncfs/syncfs.h>
#include <ufs/ufs/quota.h>
@@ -104,6 +105,8 @@ struct vfsops mfs_vfsops = {
(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
vfs_stdextattrctl,
(void *)eopnotsupp, /* vfs_suspendctl */
+ genfs_renamelock_enter,
+ genfs_renamelock_exit,
mfs_vnodeopv_descs,
0,
{ NULL, NULL },
--
David A. Holland
dholland%netbsd.org@localhost
Home |
Main Index |
Thread Index |
Old Index