mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-13 14:24:11 +08:00
v6.6-vfs.super.fixes.2
-----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCZPBy4AAKCRCRxhvAZXjc ok3jAP9+iZREbmcPgrAUGZOjq7+Gx1kJ297Uw/LKiWmxZeX2NwD/cKyv239YXHBM CB4dCwk3pvBZ8uD4dUonDX3PJYFauAU= =knzN -----END PGP SIGNATURE----- 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()
This commit is contained in:
commit
e7e9423db4
@ -19,38 +19,6 @@
|
||||
#include <linux/fs_context.h>
|
||||
#include "mtdcore.h"
|
||||
|
||||
/*
|
||||
* compare superblocks to see if they're equivalent
|
||||
* - they are if the underlying MTD device is the same
|
||||
*/
|
||||
static int mtd_test_super(struct super_block *sb, struct fs_context *fc)
|
||||
{
|
||||
struct mtd_info *mtd = fc->sget_key;
|
||||
|
||||
if (sb->s_mtd == fc->sget_key) {
|
||||
pr_debug("MTDSB: Match on device %d (\"%s\")\n",
|
||||
mtd->index, mtd->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pr_debug("MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")\n",
|
||||
sb->s_mtd->index, sb->s_mtd->name, mtd->index, mtd->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* mark the superblock by the MTD device it is using
|
||||
* - set the device number to be the correct MTD block device for pesuperstence
|
||||
* of NFS exports
|
||||
*/
|
||||
static int mtd_set_super(struct super_block *sb, struct fs_context *fc)
|
||||
{
|
||||
sb->s_mtd = fc->sget_key;
|
||||
sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, sb->s_mtd->index);
|
||||
sb->s_bdi = bdi_get(mtd_bdi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* get a superblock on an MTD-backed filesystem
|
||||
*/
|
||||
@ -62,8 +30,7 @@ static int mtd_get_sb(struct fs_context *fc,
|
||||
struct super_block *sb;
|
||||
int ret;
|
||||
|
||||
fc->sget_key = mtd;
|
||||
sb = sget_fc(fc, mtd_test_super, mtd_set_super);
|
||||
sb = sget_dev(fc, MKDEV(MTD_BLOCK_MAJOR, mtd->index));
|
||||
if (IS_ERR(sb))
|
||||
return PTR_ERR(sb);
|
||||
|
||||
@ -77,6 +44,16 @@ static int mtd_get_sb(struct fs_context *fc,
|
||||
pr_debug("MTDSB: New superblock for device %d (\"%s\")\n",
|
||||
mtd->index, mtd->name);
|
||||
|
||||
/*
|
||||
* Would usually have been set with @sb_lock held but in
|
||||
* contrast to sb->s_bdev that's checked with only
|
||||
* @sb_lock held, nothing checks sb->s_mtd without also
|
||||
* holding sb->s_umount and we're holding sb->s_umount
|
||||
* here.
|
||||
*/
|
||||
sb->s_mtd = mtd;
|
||||
sb->s_bdi = bdi_get(mtd_bdi);
|
||||
|
||||
ret = fill_super(sb, fc);
|
||||
if (ret < 0)
|
||||
goto error_sb;
|
||||
|
@ -1339,15 +1339,13 @@ error_splat_super:
|
||||
void nfs_kill_super(struct super_block *s)
|
||||
{
|
||||
struct nfs_server *server = NFS_SB(s);
|
||||
dev_t dev = s->s_dev;
|
||||
|
||||
nfs_sysfs_move_sb_to_server(server);
|
||||
generic_shutdown_super(s);
|
||||
kill_anon_super(s);
|
||||
|
||||
nfs_fscache_release_super_cookie(s);
|
||||
|
||||
nfs_free_server(server);
|
||||
free_anon_bdev(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_kill_super);
|
||||
|
||||
|
64
fs/super.c
64
fs/super.c
@ -1373,6 +1373,50 @@ int get_tree_keyed(struct fs_context *fc,
|
||||
}
|
||||
EXPORT_SYMBOL(get_tree_keyed);
|
||||
|
||||
static int set_bdev_super(struct super_block *s, void *data)
|
||||
{
|
||||
s->s_dev = *(dev_t *)data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int super_s_dev_set(struct super_block *s, struct fs_context *fc)
|
||||
{
|
||||
return set_bdev_super(s, fc->sget_key);
|
||||
}
|
||||
|
||||
static int super_s_dev_test(struct super_block *s, struct fs_context *fc)
|
||||
{
|
||||
return !(s->s_iflags & SB_I_RETIRED) &&
|
||||
s->s_dev == *(dev_t *)fc->sget_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* sget_dev - Find or create a superblock by device number
|
||||
* @fc: Filesystem context.
|
||||
* @dev: device number
|
||||
*
|
||||
* Find or create a superblock using the provided device number that
|
||||
* will be stored in fc->sget_key.
|
||||
*
|
||||
* If an extant superblock is matched, then that will be returned with
|
||||
* an elevated reference count that the caller must transfer or discard.
|
||||
*
|
||||
* If no match is made, a new superblock will be allocated and basic
|
||||
* initialisation will be performed (s_type, s_fs_info, s_id, s_dev will
|
||||
* be set). The superblock will be published and it will be returned in
|
||||
* a partially constructed state with SB_BORN and SB_ACTIVE as yet
|
||||
* unset.
|
||||
*
|
||||
* Return: an existing or newly created superblock on success, an error
|
||||
* pointer on failure.
|
||||
*/
|
||||
struct super_block *sget_dev(struct fs_context *fc, dev_t dev)
|
||||
{
|
||||
fc->sget_key = &dev;
|
||||
return sget_fc(fc, super_s_dev_test, super_s_dev_set);
|
||||
}
|
||||
EXPORT_SYMBOL(sget_dev);
|
||||
|
||||
#ifdef CONFIG_BLOCK
|
||||
/*
|
||||
* Lock a super block that the callers holds a reference to.
|
||||
@ -1431,23 +1475,6 @@ const struct blk_holder_ops fs_holder_ops = {
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(fs_holder_ops);
|
||||
|
||||
static int set_bdev_super(struct super_block *s, void *data)
|
||||
{
|
||||
s->s_dev = *(dev_t *)data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_bdev_super_fc(struct super_block *s, struct fs_context *fc)
|
||||
{
|
||||
return set_bdev_super(s, fc->sget_key);
|
||||
}
|
||||
|
||||
static int test_bdev_super_fc(struct super_block *s, struct fs_context *fc)
|
||||
{
|
||||
return !(s->s_iflags & SB_I_RETIRED) &&
|
||||
s->s_dev == *(dev_t *)fc->sget_key;
|
||||
}
|
||||
|
||||
int setup_bdev_super(struct super_block *sb, int sb_flags,
|
||||
struct fs_context *fc)
|
||||
{
|
||||
@ -1525,8 +1552,7 @@ int get_tree_bdev(struct fs_context *fc,
|
||||
}
|
||||
|
||||
fc->sb_flags |= SB_NOSEC;
|
||||
fc->sget_key = &dev;
|
||||
s = sget_fc(fc, test_bdev_super_fc, set_bdev_super_fc);
|
||||
s = sget_dev(fc, dev);
|
||||
if (IS_ERR(s))
|
||||
return PTR_ERR(s);
|
||||
|
||||
|
@ -2397,6 +2397,7 @@ struct super_block *sget(struct file_system_type *type,
|
||||
int (*test)(struct super_block *,void *),
|
||||
int (*set)(struct super_block *,void *),
|
||||
int flags, void *data);
|
||||
struct super_block *sget_dev(struct fs_context *fc, dev_t dev);
|
||||
|
||||
/* Alas, no aliases. Too much hassle with bringing module.h everywhere */
|
||||
#define fops_get(fops) \
|
||||
|
Loading…
Reference in New Issue
Block a user