summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_export.c
diff options
context:
space:
mode:
authorbde <bde@FreeBSD.org>2000-03-12 14:23:21 +0000
committerbde <bde@FreeBSD.org>2000-03-12 14:23:21 +0000
commit2af0bce593c23afaabec3f094696e6a79dc50448 (patch)
tree11259a788c35d35d1bdf1c1f13c197771aa4e64f /sys/kern/vfs_export.c
parentfaa77986fd8f89097b47ce4e976e9a5f451f045f (diff)
downloadFreeBSD-src-2af0bce593c23afaabec3f094696e6a79dc50448.zip
FreeBSD-src-2af0bce593c23afaabec3f094696e6a79dc50448.tar.gz
Try harder to make the lower 16 bits of fsids unique. The vfs type
number was packed very wastefully, giving perfect non-uniqeness in the lower 16 bits of fsids for filesystems with the same vfs type. This made linux_stat() return perfectly non-unique (broken) 16-bit st_dev's for nfs mount points, and effectively reduced mntid_base to 8 bits so that the vfs_getnewfsid() looped endlessly when there are already 256 mounted filesystems with the required vfs type. Approved by: jkh
Diffstat (limited to 'sys/kern/vfs_export.c')
-rw-r--r--sys/kern/vfs_export.c40
1 files changed, 25 insertions, 15 deletions
diff --git a/sys/kern/vfs_export.c b/sys/kern/vfs_export.c
index 9120f77..7d61a18 100644
--- a/sys/kern/vfs_export.c
+++ b/sys/kern/vfs_export.c
@@ -328,35 +328,45 @@ vfs_getvfs(fsid)
}
/*
- * Get a new unique fsid
+ * Get a new unique fsid. Try to make its val[0] unique mod 2^16, since
+ * this value may be used to create fake device numbers for stat(), and
+ * some emulators only support 16-bit device numbers.
*
- * Keep in mind that several mounts may be running in parallel,
- * so always increment mntid_base even if lower numbers are available.
+ * Keep in mind that several mounts may be running in parallel. Starting
+ * the search one past where the previous search terminated (mod 0x10) is
+ * both a micro-optimization and (incomplete) defense against returning
+ * the same fsid to different mounts.
*/
-
-static u_short mntid_base;
-
void
vfs_getnewfsid(mp)
struct mount *mp;
{
+ static u_int mntid_base;
fsid_t tfsid;
- int mtype;
-
- simple_lock(&mntid_slock);
+ u_int i;
+ int mtype, mynor;
+ simple_lock(&mntid_slock);
mtype = mp->mnt_vfc->vfc_typenum;
- for (;;) {
- tfsid.val[0] = makeudev(255, mtype + (mntid_base << 16));
- tfsid.val[1] = mtype;
- ++mntid_base;
+ tfsid.val[1] = mtype;
+ for (i = 0; ; i++) {
+ /*
+ * mtype needs to be uniquely encoded in the minor number
+ * so that uniqueness of the full fsid implies uniqueness
+ * of the device number. We are short of bits and only
+ * guarantee uniqueness of the device number mod 2^16 if
+ * mtype is always < 16 and there are never more than
+ * 16 mounts per vfs type.
+ */
+ mynor = ((mntid_base++ & 0xFFFFF) << 4) | (mtype & 0xF);
+ if (i < 0x10)
+ mynor &= 0xFF;
+ tfsid.val[0] = makeudev(255, mynor);
if (vfs_getvfs(&tfsid) == NULL)
break;
}
-
mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];
mp->mnt_stat.f_fsid.val[1] = tfsid.val[1];
-
simple_unlock(&mntid_slock);
}
OpenPOWER on IntegriCloud