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.

Merge tag 'v6.6-vfs.super.fixes.2' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull more superblock follow-on fixes from Christian Brauner:
"This contains two more small follow-up fixes for the super work this
cycle. I went through all filesystems once more and detected two minor
issues that still needed fixing:

- Some filesystems support mtd devices (e.g., mount -t jffs2 mtd2
/mnt). The mtd infrastructure uses the sb->s_mtd pointer to find an
existing superblock. When the mtd device is put and sb->s_mtd
cleared the superblock can still be found fs_supers and so this
risks a use-after-free.

Add a small patch that aligns mtd with what we did for regular
block devices and switch keying to rely on sb->s_dev.

(This was tested with mtd devices and jffs2 as xfstests doesn't
support mtd devices.)

- Switch nfs back to rely on kill_anon_super() so the superblock is
removed from the list of active supers before sb->s_fs_info is
freed"

* tag 'v6.6-vfs.super.fixes.2' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
NFS: switch back to using kill_anon_super
mtd: key superblock by device number
fs: export sget_dev()

+58 -56
+11 -34
drivers/mtd/mtdsuper.c
··· 20 20 #include "mtdcore.h" 21 21 22 22 /* 23 - * compare superblocks to see if they're equivalent 24 - * - they are if the underlying MTD device is the same 25 - */ 26 - static int mtd_test_super(struct super_block *sb, struct fs_context *fc) 27 - { 28 - struct mtd_info *mtd = fc->sget_key; 29 - 30 - if (sb->s_mtd == fc->sget_key) { 31 - pr_debug("MTDSB: Match on device %d (\"%s\")\n", 32 - mtd->index, mtd->name); 33 - return 1; 34 - } 35 - 36 - pr_debug("MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")\n", 37 - sb->s_mtd->index, sb->s_mtd->name, mtd->index, mtd->name); 38 - return 0; 39 - } 40 - 41 - /* 42 - * mark the superblock by the MTD device it is using 43 - * - set the device number to be the correct MTD block device for pesuperstence 44 - * of NFS exports 45 - */ 46 - static int mtd_set_super(struct super_block *sb, struct fs_context *fc) 47 - { 48 - sb->s_mtd = fc->sget_key; 49 - sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, sb->s_mtd->index); 50 - sb->s_bdi = bdi_get(mtd_bdi); 51 - return 0; 52 - } 53 - 54 - /* 55 23 * get a superblock on an MTD-backed filesystem 56 24 */ 57 25 static int mtd_get_sb(struct fs_context *fc, ··· 30 62 struct super_block *sb; 31 63 int ret; 32 64 33 - fc->sget_key = mtd; 34 - sb = sget_fc(fc, mtd_test_super, mtd_set_super); 65 + sb = sget_dev(fc, MKDEV(MTD_BLOCK_MAJOR, mtd->index)); 35 66 if (IS_ERR(sb)) 36 67 return PTR_ERR(sb); 37 68 ··· 43 76 /* fresh new superblock */ 44 77 pr_debug("MTDSB: New superblock for device %d (\"%s\")\n", 45 78 mtd->index, mtd->name); 79 + 80 + /* 81 + * Would usually have been set with @sb_lock held but in 82 + * contrast to sb->s_bdev that's checked with only 83 + * @sb_lock held, nothing checks sb->s_mtd without also 84 + * holding sb->s_umount and we're holding sb->s_umount 85 + * here. 86 + */ 87 + sb->s_mtd = mtd; 88 + sb->s_bdi = bdi_get(mtd_bdi); 46 89 47 90 ret = fill_super(sb, fc); 48 91 if (ret < 0)
+1 -3
fs/nfs/super.c
··· 1339 1339 void nfs_kill_super(struct super_block *s) 1340 1340 { 1341 1341 struct nfs_server *server = NFS_SB(s); 1342 - dev_t dev = s->s_dev; 1343 1342 1344 1343 nfs_sysfs_move_sb_to_server(server); 1345 - generic_shutdown_super(s); 1344 + kill_anon_super(s); 1346 1345 1347 1346 nfs_fscache_release_super_cookie(s); 1348 1347 1349 1348 nfs_free_server(server); 1350 - free_anon_bdev(dev); 1351 1349 } 1352 1350 EXPORT_SYMBOL_GPL(nfs_kill_super); 1353 1351
+45 -19
fs/super.c
··· 1373 1373 } 1374 1374 EXPORT_SYMBOL(get_tree_keyed); 1375 1375 1376 + static int set_bdev_super(struct super_block *s, void *data) 1377 + { 1378 + s->s_dev = *(dev_t *)data; 1379 + return 0; 1380 + } 1381 + 1382 + static int super_s_dev_set(struct super_block *s, struct fs_context *fc) 1383 + { 1384 + return set_bdev_super(s, fc->sget_key); 1385 + } 1386 + 1387 + static int super_s_dev_test(struct super_block *s, struct fs_context *fc) 1388 + { 1389 + return !(s->s_iflags & SB_I_RETIRED) && 1390 + s->s_dev == *(dev_t *)fc->sget_key; 1391 + } 1392 + 1393 + /** 1394 + * sget_dev - Find or create a superblock by device number 1395 + * @fc: Filesystem context. 1396 + * @dev: device number 1397 + * 1398 + * Find or create a superblock using the provided device number that 1399 + * will be stored in fc->sget_key. 1400 + * 1401 + * If an extant superblock is matched, then that will be returned with 1402 + * an elevated reference count that the caller must transfer or discard. 1403 + * 1404 + * If no match is made, a new superblock will be allocated and basic 1405 + * initialisation will be performed (s_type, s_fs_info, s_id, s_dev will 1406 + * be set). The superblock will be published and it will be returned in 1407 + * a partially constructed state with SB_BORN and SB_ACTIVE as yet 1408 + * unset. 1409 + * 1410 + * Return: an existing or newly created superblock on success, an error 1411 + * pointer on failure. 1412 + */ 1413 + struct super_block *sget_dev(struct fs_context *fc, dev_t dev) 1414 + { 1415 + fc->sget_key = &dev; 1416 + return sget_fc(fc, super_s_dev_test, super_s_dev_set); 1417 + } 1418 + EXPORT_SYMBOL(sget_dev); 1419 + 1376 1420 #ifdef CONFIG_BLOCK 1377 1421 /* 1378 1422 * Lock a super block that the callers holds a reference to. ··· 1474 1430 .sync = fs_bdev_sync, 1475 1431 }; 1476 1432 EXPORT_SYMBOL_GPL(fs_holder_ops); 1477 - 1478 - static int set_bdev_super(struct super_block *s, void *data) 1479 - { 1480 - s->s_dev = *(dev_t *)data; 1481 - return 0; 1482 - } 1483 - 1484 - static int set_bdev_super_fc(struct super_block *s, struct fs_context *fc) 1485 - { 1486 - return set_bdev_super(s, fc->sget_key); 1487 - } 1488 - 1489 - static int test_bdev_super_fc(struct super_block *s, struct fs_context *fc) 1490 - { 1491 - return !(s->s_iflags & SB_I_RETIRED) && 1492 - s->s_dev == *(dev_t *)fc->sget_key; 1493 - } 1494 1433 1495 1434 int setup_bdev_super(struct super_block *sb, int sb_flags, 1496 1435 struct fs_context *fc) ··· 1552 1525 } 1553 1526 1554 1527 fc->sb_flags |= SB_NOSEC; 1555 - fc->sget_key = &dev; 1556 - s = sget_fc(fc, test_bdev_super_fc, set_bdev_super_fc); 1528 + s = sget_dev(fc, dev); 1557 1529 if (IS_ERR(s)) 1558 1530 return PTR_ERR(s); 1559 1531
+1
include/linux/fs.h
··· 2397 2397 int (*test)(struct super_block *,void *), 2398 2398 int (*set)(struct super_block *,void *), 2399 2399 int flags, void *data); 2400 + struct super_block *sget_dev(struct fs_context *fc, dev_t dev); 2400 2401 2401 2402 /* Alas, no aliases. Too much hassle with bringing module.h everywhere */ 2402 2403 #define fops_get(fops) \