aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-08-31 10:45:17 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-08-31 23:26:45 -0400
commite89a5a43b95cdc4305b7c8e8121a380f02476636 (patch)
treeba286205f1ad11119a06b77fb6671ce9aacac13a /fs/nfs
parent36ad4885c47c2187822f2783fb46fde2d36bf200 (diff)
NFS: Fix the mount regression
This avoids the recent NFS mount regression (returning EBUSY when mounting the same filesystem twice with different parameters). The best I can do given the constraints appears to be to have the kernel first look for a superblock that matches both the fsid and the user-specified mount options, and then spawn off a new superblock if that search fails. Note that this is not the same as specifying nosharecache everywhere since nosharecache will never attempt to match an existing superblock. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Tested-by: Hua Zhong <hzhong@gmail.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/super.c110
1 files changed, 64 insertions, 46 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index b2a851c1b8c..46139003ea0 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1303,34 +1303,6 @@ static void nfs_clone_super(struct super_block *sb,
1303 nfs_initialise_sb(sb); 1303 nfs_initialise_sb(sb);
1304} 1304}
1305 1305
1306static int nfs_set_super(struct super_block *s, void *_server)
1307{
1308 struct nfs_server *server = _server;
1309 int ret;
1310
1311 s->s_fs_info = server;
1312 ret = set_anon_super(s, server);
1313 if (ret == 0)
1314 server->s_dev = s->s_dev;
1315 return ret;
1316}
1317
1318static int nfs_compare_super(struct super_block *sb, void *data)
1319{
1320 struct nfs_server *server = data, *old = NFS_SB(sb);
1321
1322 if (memcmp(&old->nfs_client->cl_addr,
1323 &server->nfs_client->cl_addr,
1324 sizeof(old->nfs_client->cl_addr)) != 0)
1325 return 0;
1326 /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */
1327 if (old->flags & NFS_MOUNT_UNSHARED)
1328 return 0;
1329 if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0)
1330 return 0;
1331 return 1;
1332}
1333
1334#define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS) 1306#define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)
1335 1307
1336static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags) 1308static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags)
@@ -1359,9 +1331,46 @@ static int nfs_compare_mount_options(const struct super_block *s, const struct n
1359 goto Ebusy; 1331 goto Ebusy;
1360 if (clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor) 1332 if (clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor)
1361 goto Ebusy; 1333 goto Ebusy;
1362 return 0; 1334 return 1;
1363Ebusy: 1335Ebusy:
1364 return -EBUSY; 1336 return 0;
1337}
1338
1339struct nfs_sb_mountdata {
1340 struct nfs_server *server;
1341 int mntflags;
1342};
1343
1344static int nfs_set_super(struct super_block *s, void *data)
1345{
1346 struct nfs_sb_mountdata *sb_mntdata = data;
1347 struct nfs_server *server = sb_mntdata->server;
1348 int ret;
1349
1350 s->s_flags = sb_mntdata->mntflags;
1351 s->s_fs_info = server;
1352 ret = set_anon_super(s, server);
1353 if (ret == 0)
1354 server->s_dev = s->s_dev;
1355 return ret;
1356}
1357
1358static int nfs_compare_super(struct super_block *sb, void *data)
1359{
1360 struct nfs_sb_mountdata *sb_mntdata = data;
1361 struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb);
1362 int mntflags = sb_mntdata->mntflags;
1363
1364 if (memcmp(&old->nfs_client->cl_addr,
1365 &server->nfs_client->cl_addr,
1366 sizeof(old->nfs_client->cl_addr)) != 0)
1367 return 0;
1368 /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */
1369 if (old->flags & NFS_MOUNT_UNSHARED)
1370 return 0;
1371 if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0)
1372 return 0;
1373 return nfs_compare_mount_options(sb, server, mntflags);
1365} 1374}
1366 1375
1367static int nfs_get_sb(struct file_system_type *fs_type, 1376static int nfs_get_sb(struct file_system_type *fs_type,
@@ -1373,6 +1382,9 @@ static int nfs_get_sb(struct file_system_type *fs_type,
1373 struct nfs_mount_data *data = raw_data; 1382 struct nfs_mount_data *data = raw_data;
1374 struct dentry *mntroot; 1383 struct dentry *mntroot;
1375 int (*compare_super)(struct super_block *, void *) = nfs_compare_super; 1384 int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
1385 struct nfs_sb_mountdata sb_mntdata = {
1386 .mntflags = flags,
1387 };
1376 int error; 1388 int error;
1377 1389
1378 /* Validate the mount data */ 1390 /* Validate the mount data */
@@ -1386,28 +1398,25 @@ static int nfs_get_sb(struct file_system_type *fs_type,
1386 error = PTR_ERR(server); 1398 error = PTR_ERR(server);
1387 goto out; 1399 goto out;
1388 } 1400 }
1401 sb_mntdata.server = server;
1389 1402
1390 if (server->flags & NFS_MOUNT_UNSHARED) 1403 if (server->flags & NFS_MOUNT_UNSHARED)
1391 compare_super = NULL; 1404 compare_super = NULL;
1392 1405
1393 /* Get a superblock - note that we may end up sharing one that already exists */ 1406 /* Get a superblock - note that we may end up sharing one that already exists */
1394 s = sget(fs_type, compare_super, nfs_set_super, server); 1407 s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata);
1395 if (IS_ERR(s)) { 1408 if (IS_ERR(s)) {
1396 error = PTR_ERR(s); 1409 error = PTR_ERR(s);
1397 goto out_err_nosb; 1410 goto out_err_nosb;
1398 } 1411 }
1399 1412
1400 if (s->s_fs_info != server) { 1413 if (s->s_fs_info != server) {
1401 error = nfs_compare_mount_options(s, server, flags);
1402 nfs_free_server(server); 1414 nfs_free_server(server);
1403 server = NULL; 1415 server = NULL;
1404 if (error < 0)
1405 goto error_splat_super;
1406 } 1416 }
1407 1417
1408 if (!s->s_root) { 1418 if (!s->s_root) {
1409 /* initial superblock/root creation */ 1419 /* initial superblock/root creation */
1410 s->s_flags = flags;
1411 nfs_fill_super(s, data); 1420 nfs_fill_super(s, data);
1412 } 1421 }
1413 1422
@@ -1460,6 +1469,9 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags,
1460 struct nfs_server *server; 1469 struct nfs_server *server;
1461 struct dentry *mntroot; 1470 struct dentry *mntroot;
1462 int (*compare_super)(struct super_block *, void *) = nfs_compare_super; 1471 int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
1472 struct nfs_sb_mountdata sb_mntdata = {
1473 .mntflags = flags,
1474 };
1463 int error; 1475 int error;
1464 1476
1465 dprintk("--> nfs_xdev_get_sb()\n"); 1477 dprintk("--> nfs_xdev_get_sb()\n");
@@ -1470,28 +1482,25 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags,
1470 error = PTR_ERR(server); 1482 error = PTR_ERR(server);
1471 goto out_err_noserver; 1483 goto out_err_noserver;
1472 } 1484 }
1485 sb_mntdata.server = server;
1473 1486
1474 if (server->flags & NFS_MOUNT_UNSHARED) 1487 if (server->flags & NFS_MOUNT_UNSHARED)
1475 compare_super = NULL; 1488 compare_super = NULL;
1476 1489
1477 /* Get a superblock - note that we may end up sharing one that already exists */ 1490 /* Get a superblock - note that we may end up sharing one that already exists */
1478 s = sget(&nfs_fs_type, compare_super, nfs_set_super, server); 1491 s = sget(&nfs_fs_type, compare_super, nfs_set_super, &sb_mntdata);
1479 if (IS_ERR(s)) { 1492 if (IS_ERR(s)) {
1480 error = PTR_ERR(s); 1493 error = PTR_ERR(s);
1481 goto out_err_nosb; 1494 goto out_err_nosb;
1482 } 1495 }
1483 1496
1484 if (s->s_fs_info != server) { 1497 if (s->s_fs_info != server) {
1485 error = nfs_compare_mount_options(s, server, flags);
1486 nfs_free_server(server); 1498 nfs_free_server(server);
1487 server = NULL; 1499 server = NULL;
1488 if (error < 0)
1489 goto error_splat_super;
1490 } 1500 }
1491 1501
1492 if (!s->s_root) { 1502 if (!s->s_root) {
1493 /* initial superblock/root creation */ 1503 /* initial superblock/root creation */
1494 s->s_flags = flags;
1495 nfs_clone_super(s, data->sb); 1504 nfs_clone_super(s, data->sb);
1496 } 1505 }
1497 1506
@@ -1729,6 +1738,9 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
1729 struct dentry *mntroot; 1738 struct dentry *mntroot;
1730 char *mntpath = NULL, *hostname = NULL, *ip_addr = NULL; 1739 char *mntpath = NULL, *hostname = NULL, *ip_addr = NULL;
1731 int (*compare_super)(struct super_block *, void *) = nfs_compare_super; 1740 int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
1741 struct nfs_sb_mountdata sb_mntdata = {
1742 .mntflags = flags,
1743 };
1732 int error; 1744 int error;
1733 1745
1734 /* Validate the mount data */ 1746 /* Validate the mount data */
@@ -1744,12 +1756,13 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
1744 error = PTR_ERR(server); 1756 error = PTR_ERR(server);
1745 goto out; 1757 goto out;
1746 } 1758 }
1759 sb_mntdata.server = server;
1747 1760
1748 if (server->flags & NFS4_MOUNT_UNSHARED) 1761 if (server->flags & NFS4_MOUNT_UNSHARED)
1749 compare_super = NULL; 1762 compare_super = NULL;
1750 1763
1751 /* Get a superblock - note that we may end up sharing one that already exists */ 1764 /* Get a superblock - note that we may end up sharing one that already exists */
1752 s = sget(fs_type, compare_super, nfs_set_super, server); 1765 s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata);
1753 if (IS_ERR(s)) { 1766 if (IS_ERR(s)) {
1754 error = PTR_ERR(s); 1767 error = PTR_ERR(s);
1755 goto out_free; 1768 goto out_free;
@@ -1762,7 +1775,6 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
1762 1775
1763 if (!s->s_root) { 1776 if (!s->s_root) {
1764 /* initial superblock/root creation */ 1777 /* initial superblock/root creation */
1765 s->s_flags = flags;
1766 nfs4_fill_super(s); 1778 nfs4_fill_super(s);
1767 } 1779 }
1768 1780
@@ -1816,6 +1828,9 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags,
1816 struct nfs_server *server; 1828 struct nfs_server *server;
1817 struct dentry *mntroot; 1829 struct dentry *mntroot;
1818 int (*compare_super)(struct super_block *, void *) = nfs_compare_super; 1830 int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
1831 struct nfs_sb_mountdata sb_mntdata = {
1832 .mntflags = flags,
1833 };
1819 int error; 1834 int error;
1820 1835
1821 dprintk("--> nfs4_xdev_get_sb()\n"); 1836 dprintk("--> nfs4_xdev_get_sb()\n");
@@ -1826,12 +1841,13 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags,
1826 error = PTR_ERR(server); 1841 error = PTR_ERR(server);
1827 goto out_err_noserver; 1842 goto out_err_noserver;
1828 } 1843 }
1844 sb_mntdata.server = server;
1829 1845
1830 if (server->flags & NFS4_MOUNT_UNSHARED) 1846 if (server->flags & NFS4_MOUNT_UNSHARED)
1831 compare_super = NULL; 1847 compare_super = NULL;
1832 1848
1833 /* Get a superblock - note that we may end up sharing one that already exists */ 1849 /* Get a superblock - note that we may end up sharing one that already exists */
1834 s = sget(&nfs_fs_type, compare_super, nfs_set_super, server); 1850 s = sget(&nfs_fs_type, compare_super, nfs_set_super, &sb_mntdata);
1835 if (IS_ERR(s)) { 1851 if (IS_ERR(s)) {
1836 error = PTR_ERR(s); 1852 error = PTR_ERR(s);
1837 goto out_err_nosb; 1853 goto out_err_nosb;
@@ -1844,7 +1860,6 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags,
1844 1860
1845 if (!s->s_root) { 1861 if (!s->s_root) {
1846 /* initial superblock/root creation */ 1862 /* initial superblock/root creation */
1847 s->s_flags = flags;
1848 nfs4_clone_super(s, data->sb); 1863 nfs4_clone_super(s, data->sb);
1849 } 1864 }
1850 1865
@@ -1887,6 +1902,9 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags,
1887 struct dentry *mntroot; 1902 struct dentry *mntroot;
1888 struct nfs_fh mntfh; 1903 struct nfs_fh mntfh;
1889 int (*compare_super)(struct super_block *, void *) = nfs_compare_super; 1904 int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
1905 struct nfs_sb_mountdata sb_mntdata = {
1906 .mntflags = flags,
1907 };
1890 int error; 1908 int error;
1891 1909
1892 dprintk("--> nfs4_referral_get_sb()\n"); 1910 dprintk("--> nfs4_referral_get_sb()\n");
@@ -1897,12 +1915,13 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags,
1897 error = PTR_ERR(server); 1915 error = PTR_ERR(server);
1898 goto out_err_noserver; 1916 goto out_err_noserver;
1899 } 1917 }
1918 sb_mntdata.server = server;
1900 1919
1901 if (server->flags & NFS4_MOUNT_UNSHARED) 1920 if (server->flags & NFS4_MOUNT_UNSHARED)
1902 compare_super = NULL; 1921 compare_super = NULL;
1903 1922
1904 /* Get a superblock - note that we may end up sharing one that already exists */ 1923 /* Get a superblock - note that we may end up sharing one that already exists */
1905 s = sget(&nfs_fs_type, compare_super, nfs_set_super, server); 1924 s = sget(&nfs_fs_type, compare_super, nfs_set_super, &sb_mntdata);
1906 if (IS_ERR(s)) { 1925 if (IS_ERR(s)) {
1907 error = PTR_ERR(s); 1926 error = PTR_ERR(s);
1908 goto out_err_nosb; 1927 goto out_err_nosb;
@@ -1915,7 +1934,6 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags,
1915 1934
1916 if (!s->s_root) { 1935 if (!s->s_root) {
1917 /* initial superblock/root creation */ 1936 /* initial superblock/root creation */
1918 s->s_flags = flags;
1919 nfs4_fill_super(s); 1937 nfs4_fill_super(s);
1920 } 1938 }
1921 1939