Author: rmacklem
Date: Tue Sep 13 21:01:26 2011
New Revision: 225537
URL: http://svn.freebsd.org/changeset/base/225537

Log:
  Modify vfs_register() to use a hash calculation
  on vfc_name to set vfc_typenum, so that vfc_typenum doesn't
  change when file systems are loaded in different orders. This
  keeps NFS file handles from changing, for file systems that
  use vfc_typenum in their fsid. This change is controlled via
  a loader.conf variable called vfs.typenumhash, since vfc_typenum
  will change once when this is enabled. It defaults to 1 for
  9.0, but will default to 0 when MFC'd to stable/8.
  
  Tested by:    hrs
  Reviewed by:  jhb, pjd (earlier version)
  Approved by:  re (kib)
  MFC after:    1 month

Modified:
  head/UPDATING
  head/sys/kern/vfs_init.c

Modified: head/UPDATING
==============================================================================
--- head/UPDATING       Tue Sep 13 20:35:34 2011        (r225536)
+++ head/UPDATING       Tue Sep 13 21:01:26 2011        (r225537)
@@ -22,6 +22,18 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 9.
        machines to maximize performance.  (To disable malloc debugging, run
        ln -s aj /etc/malloc.conf.)
 
+20110913:
+       This commit modifies vfs_register() so that it uses a hash
+       calculation to set vfc_typenum, which is enabled by default.
+       The first time a system is booted after this change, the
+       vfc_typenum values will change for all file systems. The
+       main effect of this is a change to the NFS server file handles
+       for file systems that use vfc_typenum in their fsid, such as ZFS.
+       It will, however, prevent vfc_typenum from changing when file
+       systems are loaded in a different order for subsequent reboots.
+       To disable this, you can set vfs.typenumhash=0 in /boot/loader.conf
+       until you are ready to remount all NFS clients after a reboot.
+
 20110828:
        Bump the shared library version numbers for libraries that
        do not use symbol versioning, have changed the ABI compared

Modified: head/sys/kern/vfs_init.c
==============================================================================
--- head/sys/kern/vfs_init.c    Tue Sep 13 20:35:34 2011        (r225536)
+++ head/sys/kern/vfs_init.c    Tue Sep 13 21:01:26 2011        (r225537)
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/fnv_hash.h>
 #include <sys/kernel.h>
 #include <sys/linker.h>
 #include <sys/mount.h>
@@ -65,6 +66,18 @@ int maxvfsconf = VFS_GENERIC + 1;
 struct vfsconfhead vfsconf = TAILQ_HEAD_INITIALIZER(vfsconf);
 
 /*
+ * Loader.conf variable vfs.typenumhash enables setting vfc_typenum using a 
hash
+ * calculation on vfc_name, so that it doesn't change when file systems are
+ * loaded in a different order. This will avoid the NFS server file handles 
from
+ * changing for file systems that use vfc_typenum in their fsid.
+ */
+static int     vfs_typenumhash = 1;
+TUNABLE_INT("vfs.typenumhash", &vfs_typenumhash);
+SYSCTL_INT(_vfs, OID_AUTO, typenumhash, CTLFLAG_RDTUN, &vfs_typenumhash, 0,
+    "Set vfc_typenum using a hash calculation on vfc_name, so that it does not"
+    "change when file systems are loaded in a different order.");
+
+/*
  * A Zen vnode attribute structure.
  *
  * Initialized when the first filesystem registers by vfs_register().
@@ -138,6 +151,9 @@ vfs_register(struct vfsconf *vfc)
        struct sysctl_oid *oidp;
        struct vfsops *vfsops;
        static int once;
+       struct vfsconf *tvfc;
+       uint32_t hashval;
+       int secondpass;
 
        if (!once) {
                vattr_null(&va_null);
@@ -152,7 +168,34 @@ vfs_register(struct vfsconf *vfc)
        if (vfs_byname(vfc->vfc_name) != NULL)
                return EEXIST;
 
-       vfc->vfc_typenum = maxvfsconf++;
+       if (vfs_typenumhash != 0) {
+               /*
+                * Calculate a hash on vfc_name to use for vfc_typenum. Unless
+                * all of 1<->255 are assigned, it is limited to 8bits since
+                * that is what ZFS uses from vfc_typenum and is also the
+                * preferred range for vfs_getnewfsid().
+                */
+               hashval = fnv_32_str(vfc->vfc_name, FNV1_32_INIT);
+               hashval &= 0xff;
+               secondpass = 0;
+               do {
+                       /* Look for and fix any collision. */
+                       TAILQ_FOREACH(tvfc, &vfsconf, vfc_list) {
+                               if (hashval == tvfc->vfc_typenum) {
+                                       if (hashval == 255 && secondpass == 0) {
+                                               hashval = 1;
+                                               secondpass = 1;
+                                       } else
+                                               hashval++;
+                                       break;
+                               }
+                       }
+               } while (tvfc != NULL);
+               vfc->vfc_typenum = hashval;
+               if (vfc->vfc_typenum >= maxvfsconf)
+                       maxvfsconf = vfc->vfc_typenum + 1;
+       } else
+               vfc->vfc_typenum = maxvfsconf++;
        TAILQ_INSERT_TAIL(&vfsconf, vfc, vfc_list);
 
        /*
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to