summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_init.c
diff options
context:
space:
mode:
authorrmacklem <rmacklem@FreeBSD.org>2011-09-13 21:01:26 +0000
committerrmacklem <rmacklem@FreeBSD.org>2011-09-13 21:01:26 +0000
commit99f390a4e8015ddd72e91fd20840ca3847704ec6 (patch)
tree85cd8ef66ff4280d4897da2da74aae892c01d3fb /sys/kern/vfs_init.c
parentd35d0d3c95dfa04aa8c0a53cc36c0491dd9f4f18 (diff)
downloadFreeBSD-src-99f390a4e8015ddd72e91fd20840ca3847704ec6.zip
FreeBSD-src-99f390a4e8015ddd72e91fd20840ca3847704ec6.tar.gz
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
Diffstat (limited to 'sys/kern/vfs_init.c')
-rw-r--r--sys/kern/vfs_init.c45
1 files changed, 44 insertions, 1 deletions
diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c
index 4367b8c..0165b38 100644
--- a/sys/kern/vfs_init.c
+++ b/sys/kern/vfs_init.c
@@ -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);
/*
OpenPOWER on IntegriCloud