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

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Trond Myklebust and committed by
Linus Torvalds
e89a5a43 36ad4885

+64 -46
+64 -46
fs/nfs/super.c
··· 1303 1303 nfs_initialise_sb(sb); 1304 1304 } 1305 1305 1306 - static 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 - 1318 - static 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 1306 #define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS) 1335 1307 1336 1308 static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags) ··· 1331 1359 goto Ebusy; 1332 1360 if (clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor) 1333 1361 goto Ebusy; 1334 - return 0; 1362 + return 1; 1335 1363 Ebusy: 1336 - return -EBUSY; 1364 + return 0; 1365 + } 1366 + 1367 + struct nfs_sb_mountdata { 1368 + struct nfs_server *server; 1369 + int mntflags; 1370 + }; 1371 + 1372 + static int nfs_set_super(struct super_block *s, void *data) 1373 + { 1374 + struct nfs_sb_mountdata *sb_mntdata = data; 1375 + struct nfs_server *server = sb_mntdata->server; 1376 + int ret; 1377 + 1378 + s->s_flags = sb_mntdata->mntflags; 1379 + s->s_fs_info = server; 1380 + ret = set_anon_super(s, server); 1381 + if (ret == 0) 1382 + server->s_dev = s->s_dev; 1383 + return ret; 1384 + } 1385 + 1386 + static int nfs_compare_super(struct super_block *sb, void *data) 1387 + { 1388 + struct nfs_sb_mountdata *sb_mntdata = data; 1389 + struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb); 1390 + int mntflags = sb_mntdata->mntflags; 1391 + 1392 + if (memcmp(&old->nfs_client->cl_addr, 1393 + &server->nfs_client->cl_addr, 1394 + sizeof(old->nfs_client->cl_addr)) != 0) 1395 + return 0; 1396 + /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */ 1397 + if (old->flags & NFS_MOUNT_UNSHARED) 1398 + return 0; 1399 + if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0) 1400 + return 0; 1401 + return nfs_compare_mount_options(sb, server, mntflags); 1337 1402 } 1338 1403 1339 1404 static int nfs_get_sb(struct file_system_type *fs_type, ··· 1382 1373 struct nfs_mount_data *data = raw_data; 1383 1374 struct dentry *mntroot; 1384 1375 int (*compare_super)(struct super_block *, void *) = nfs_compare_super; 1376 + struct nfs_sb_mountdata sb_mntdata = { 1377 + .mntflags = flags, 1378 + }; 1385 1379 int error; 1386 1380 1387 1381 /* Validate the mount data */ ··· 1398 1386 error = PTR_ERR(server); 1399 1387 goto out; 1400 1388 } 1389 + sb_mntdata.server = server; 1401 1390 1402 1391 if (server->flags & NFS_MOUNT_UNSHARED) 1403 1392 compare_super = NULL; 1404 1393 1405 1394 /* Get a superblock - note that we may end up sharing one that already exists */ 1406 - s = sget(fs_type, compare_super, nfs_set_super, server); 1395 + s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata); 1407 1396 if (IS_ERR(s)) { 1408 1397 error = PTR_ERR(s); 1409 1398 goto out_err_nosb; 1410 1399 } 1411 1400 1412 1401 if (s->s_fs_info != server) { 1413 - error = nfs_compare_mount_options(s, server, flags); 1414 1402 nfs_free_server(server); 1415 1403 server = NULL; 1416 - if (error < 0) 1417 - goto error_splat_super; 1418 1404 } 1419 1405 1420 1406 if (!s->s_root) { 1421 1407 /* initial superblock/root creation */ 1422 - s->s_flags = flags; 1423 1408 nfs_fill_super(s, data); 1424 1409 } 1425 1410 ··· 1469 1460 struct nfs_server *server; 1470 1461 struct dentry *mntroot; 1471 1462 int (*compare_super)(struct super_block *, void *) = nfs_compare_super; 1463 + struct nfs_sb_mountdata sb_mntdata = { 1464 + .mntflags = flags, 1465 + }; 1472 1466 int error; 1473 1467 1474 1468 dprintk("--> nfs_xdev_get_sb()\n"); ··· 1482 1470 error = PTR_ERR(server); 1483 1471 goto out_err_noserver; 1484 1472 } 1473 + sb_mntdata.server = server; 1485 1474 1486 1475 if (server->flags & NFS_MOUNT_UNSHARED) 1487 1476 compare_super = NULL; 1488 1477 1489 1478 /* Get a superblock - note that we may end up sharing one that already exists */ 1490 - s = sget(&nfs_fs_type, compare_super, nfs_set_super, server); 1479 + s = sget(&nfs_fs_type, compare_super, nfs_set_super, &sb_mntdata); 1491 1480 if (IS_ERR(s)) { 1492 1481 error = PTR_ERR(s); 1493 1482 goto out_err_nosb; 1494 1483 } 1495 1484 1496 1485 if (s->s_fs_info != server) { 1497 - error = nfs_compare_mount_options(s, server, flags); 1498 1486 nfs_free_server(server); 1499 1487 server = NULL; 1500 - if (error < 0) 1501 - goto error_splat_super; 1502 1488 } 1503 1489 1504 1490 if (!s->s_root) { 1505 1491 /* initial superblock/root creation */ 1506 - s->s_flags = flags; 1507 1492 nfs_clone_super(s, data->sb); 1508 1493 } 1509 1494 ··· 1738 1729 struct dentry *mntroot; 1739 1730 char *mntpath = NULL, *hostname = NULL, *ip_addr = NULL; 1740 1731 int (*compare_super)(struct super_block *, void *) = nfs_compare_super; 1732 + struct nfs_sb_mountdata sb_mntdata = { 1733 + .mntflags = flags, 1734 + }; 1741 1735 int error; 1742 1736 1743 1737 /* Validate the mount data */ ··· 1756 1744 error = PTR_ERR(server); 1757 1745 goto out; 1758 1746 } 1747 + sb_mntdata.server = server; 1759 1748 1760 1749 if (server->flags & NFS4_MOUNT_UNSHARED) 1761 1750 compare_super = NULL; 1762 1751 1763 1752 /* Get a superblock - note that we may end up sharing one that already exists */ 1764 - s = sget(fs_type, compare_super, nfs_set_super, server); 1753 + s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata); 1765 1754 if (IS_ERR(s)) { 1766 1755 error = PTR_ERR(s); 1767 1756 goto out_free; ··· 1775 1762 1776 1763 if (!s->s_root) { 1777 1764 /* initial superblock/root creation */ 1778 - s->s_flags = flags; 1779 1765 nfs4_fill_super(s); 1780 1766 } 1781 1767 ··· 1828 1816 struct nfs_server *server; 1829 1817 struct dentry *mntroot; 1830 1818 int (*compare_super)(struct super_block *, void *) = nfs_compare_super; 1819 + struct nfs_sb_mountdata sb_mntdata = { 1820 + .mntflags = flags, 1821 + }; 1831 1822 int error; 1832 1823 1833 1824 dprintk("--> nfs4_xdev_get_sb()\n"); ··· 1841 1826 error = PTR_ERR(server); 1842 1827 goto out_err_noserver; 1843 1828 } 1829 + sb_mntdata.server = server; 1844 1830 1845 1831 if (server->flags & NFS4_MOUNT_UNSHARED) 1846 1832 compare_super = NULL; 1847 1833 1848 1834 /* Get a superblock - note that we may end up sharing one that already exists */ 1849 - s = sget(&nfs_fs_type, compare_super, nfs_set_super, server); 1835 + s = sget(&nfs_fs_type, compare_super, nfs_set_super, &sb_mntdata); 1850 1836 if (IS_ERR(s)) { 1851 1837 error = PTR_ERR(s); 1852 1838 goto out_err_nosb; ··· 1860 1844 1861 1845 if (!s->s_root) { 1862 1846 /* initial superblock/root creation */ 1863 - s->s_flags = flags; 1864 1847 nfs4_clone_super(s, data->sb); 1865 1848 } 1866 1849 ··· 1902 1887 struct dentry *mntroot; 1903 1888 struct nfs_fh mntfh; 1904 1889 int (*compare_super)(struct super_block *, void *) = nfs_compare_super; 1890 + struct nfs_sb_mountdata sb_mntdata = { 1891 + .mntflags = flags, 1892 + }; 1905 1893 int error; 1906 1894 1907 1895 dprintk("--> nfs4_referral_get_sb()\n"); ··· 1915 1897 error = PTR_ERR(server); 1916 1898 goto out_err_noserver; 1917 1899 } 1900 + sb_mntdata.server = server; 1918 1901 1919 1902 if (server->flags & NFS4_MOUNT_UNSHARED) 1920 1903 compare_super = NULL; 1921 1904 1922 1905 /* Get a superblock - note that we may end up sharing one that already exists */ 1923 - s = sget(&nfs_fs_type, compare_super, nfs_set_super, server); 1906 + s = sget(&nfs_fs_type, compare_super, nfs_set_super, &sb_mntdata); 1924 1907 if (IS_ERR(s)) { 1925 1908 error = PTR_ERR(s); 1926 1909 goto out_err_nosb; ··· 1934 1915 1935 1916 if (!s->s_root) { 1936 1917 /* initial superblock/root creation */ 1937 - s->s_flags = flags; 1938 1918 nfs4_fill_super(s); 1939 1919 } 1940 1920