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