Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

NFS: Add the mount option "nosharecache"

Prior to David Howell's mount changes in 2.6.18, users who mounted
different directories which happened to be from the same filesystem on the
server would get different super blocks, and hence could choose different
mount options. As long as there were no hard linked files that crossed from
one subtree to another, this was quite safe.
Post the changes, if the two directories are on the same filesystem (have
the same 'fsid'), they will share the same super block, and hence the same
mount options.

Add a flag to allow users to elect not to share the NFS super block with
another mount point, even if the fsids are the same. This will allow
users to set different mount options for the two different super blocks, as
was previously possible. It is still up to the user to ensure that there
are no cache coherency issues when doing this, however the default
behaviour will be to share super blocks whenever two paths result in
the same fsid.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

+41 -6
+38 -5
fs/nfs/super.c
··· 100 100 Opt_udp, Opt_tcp, 101 101 Opt_acl, Opt_noacl, 102 102 Opt_rdirplus, Opt_nordirplus, 103 + Opt_sharecache, Opt_nosharecache, 103 104 104 105 /* Mount options that take integer arguments */ 105 106 Opt_port, ··· 147 146 { Opt_noacl, "noacl" }, 148 147 { Opt_rdirplus, "rdirplus" }, 149 148 { Opt_nordirplus, "nordirplus" }, 149 + { Opt_sharecache, "sharecache" }, 150 + { Opt_nosharecache, "nosharecache" }, 150 151 151 152 { Opt_port, "port=%u" }, 152 153 { Opt_rsize, "rsize=%u" }, ··· 453 450 { NFS_MOUNT_NONLM, ",nolock", "" }, 454 451 { NFS_MOUNT_NOACL, ",noacl", "" }, 455 452 { NFS_MOUNT_NORDIRPLUS, ",nordirplus", "" }, 453 + { NFS_MOUNT_UNSHARED, ",nosharecache", ""}, 456 454 { 0, NULL, NULL } 457 455 }; 458 456 const struct proc_nfs_info *nfs_infop; ··· 717 713 break; 718 714 case Opt_nordirplus: 719 715 mnt->flags |= NFS_MOUNT_NORDIRPLUS; 716 + break; 717 + case Opt_sharecache: 718 + mnt->flags &= ~NFS_MOUNT_UNSHARED; 719 + break; 720 + case Opt_nosharecache: 721 + mnt->flags |= NFS_MOUNT_UNSHARED; 720 722 break; 721 723 722 724 case Opt_port: ··· 1319 1309 1320 1310 if (old->nfs_client != server->nfs_client) 1321 1311 return 0; 1312 + /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */ 1313 + if (old->flags & NFS_MOUNT_UNSHARED) 1314 + return 0; 1322 1315 if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0) 1323 1316 return 0; 1324 1317 return 1; ··· 1335 1322 struct nfs_fh mntfh; 1336 1323 struct nfs_mount_data *data = raw_data; 1337 1324 struct dentry *mntroot; 1325 + int (*compare_super)(struct super_block *, void *) = nfs_compare_super; 1338 1326 int error; 1339 1327 1340 1328 /* Validate the mount data */ ··· 1350 1336 goto out; 1351 1337 } 1352 1338 1339 + if (server->flags & NFS_MOUNT_UNSHARED) 1340 + compare_super = NULL; 1341 + 1353 1342 /* Get a superblock - note that we may end up sharing one that already exists */ 1354 - s = sget(fs_type, nfs_compare_super, nfs_set_super, server); 1343 + s = sget(fs_type, compare_super, nfs_set_super, server); 1355 1344 if (IS_ERR(s)) { 1356 1345 error = PTR_ERR(s); 1357 1346 goto out_err_nosb; ··· 1419 1402 struct super_block *s; 1420 1403 struct nfs_server *server; 1421 1404 struct dentry *mntroot; 1405 + int (*compare_super)(struct super_block *, void *) = nfs_compare_super; 1422 1406 int error; 1423 1407 1424 1408 dprintk("--> nfs_xdev_get_sb()\n"); ··· 1431 1413 goto out_err_noserver; 1432 1414 } 1433 1415 1416 + if (server->flags & NFS_MOUNT_UNSHARED) 1417 + compare_super = NULL; 1418 + 1434 1419 /* Get a superblock - note that we may end up sharing one that already exists */ 1435 - s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server); 1420 + s = sget(&nfs_fs_type, compare_super, nfs_set_super, server); 1436 1421 if (IS_ERR(s)) { 1437 1422 error = PTR_ERR(s); 1438 1423 goto out_err_nosb; ··· 1678 1657 struct nfs_fh mntfh; 1679 1658 struct dentry *mntroot; 1680 1659 char *mntpath = NULL, *hostname = NULL, *ip_addr = NULL; 1660 + int (*compare_super)(struct super_block *, void *) = nfs_compare_super; 1681 1661 int error; 1682 1662 1683 1663 /* Validate the mount data */ ··· 1695 1673 goto out; 1696 1674 } 1697 1675 1676 + if (server->flags & NFS4_MOUNT_UNSHARED) 1677 + compare_super = NULL; 1678 + 1698 1679 /* Get a superblock - note that we may end up sharing one that already exists */ 1699 - s = sget(fs_type, nfs_compare_super, nfs_set_super, server); 1680 + s = sget(fs_type, compare_super, nfs_set_super, server); 1700 1681 if (IS_ERR(s)) { 1701 1682 error = PTR_ERR(s); 1702 1683 goto out_free; ··· 1765 1740 struct super_block *s; 1766 1741 struct nfs_server *server; 1767 1742 struct dentry *mntroot; 1743 + int (*compare_super)(struct super_block *, void *) = nfs_compare_super; 1768 1744 int error; 1769 1745 1770 1746 dprintk("--> nfs4_xdev_get_sb()\n"); ··· 1777 1751 goto out_err_noserver; 1778 1752 } 1779 1753 1754 + if (server->flags & NFS4_MOUNT_UNSHARED) 1755 + compare_super = NULL; 1756 + 1780 1757 /* Get a superblock - note that we may end up sharing one that already exists */ 1781 - s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server); 1758 + s = sget(&nfs_fs_type, compare_super, nfs_set_super, server); 1782 1759 if (IS_ERR(s)) { 1783 1760 error = PTR_ERR(s); 1784 1761 goto out_err_nosb; ··· 1836 1807 struct nfs_server *server; 1837 1808 struct dentry *mntroot; 1838 1809 struct nfs_fh mntfh; 1810 + int (*compare_super)(struct super_block *, void *) = nfs_compare_super; 1839 1811 int error; 1840 1812 1841 1813 dprintk("--> nfs4_referral_get_sb()\n"); ··· 1848 1818 goto out_err_noserver; 1849 1819 } 1850 1820 1821 + if (server->flags & NFS4_MOUNT_UNSHARED) 1822 + compare_super = NULL; 1823 + 1851 1824 /* Get a superblock - note that we may end up sharing one that already exists */ 1852 - s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server); 1825 + s = sget(&nfs_fs_type, compare_super, nfs_set_super, server); 1853 1826 if (IS_ERR(s)) { 1854 1827 error = PTR_ERR(s); 1855 1828 goto out_err_nosb;
+2 -1
include/linux/nfs4_mount.h
··· 65 65 #define NFS4_MOUNT_NOCTO 0x0010 /* 1 */ 66 66 #define NFS4_MOUNT_NOAC 0x0020 /* 1 */ 67 67 #define NFS4_MOUNT_STRICTLOCK 0x1000 /* 1 */ 68 - #define NFS4_MOUNT_FLAGMASK 0x1033 68 + #define NFS4_MOUNT_UNSHARED 0x8000 /* 1 */ 69 + #define NFS4_MOUNT_FLAGMASK 0x9033 69 70 70 71 #endif
+1
include/linux/nfs_mount.h
··· 62 62 #define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */ 63 63 #define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */ 64 64 #define NFS_MOUNT_NORDIRPLUS 0x4000 /* 5 */ 65 + #define NFS_MOUNT_UNSHARED 0x8000 /* 5 */ 65 66 #define NFS_MOUNT_FLAGMASK 0xFFFF 66 67 67 68 #endif