As Allison reported [1], currently get_tree_bdev() will store "Can't lookup blockdev" error message. Although it makes sense for pure bdev-based fses, this message may mislead users who try to use EROFS file-backed mounts since get_tree_nodev() is used as a fallback then. Add get_tree_bdev_by_dev() to specify a device number explicitly instead of the hardcoded fc->source as mentioned in [2], there are other benefits like: - Filesystems can have other ways to get a bdev-based sb in addition to the current hard-coded source path; - Pseudo-filesystems can utilize this method to generate a filesystem from given device numbers too. - Like get_tree_nodev(), it doesn't strictly tie to fc->source either. [1] https://lore.kernel.org/r/CAOYeF9VQ8jKVmpy5Zy9DNhO6xmWSKMB-DO8yvBB0XvBE7=3Ugg@xxxxxxxxxxxxxx [2] https://lore.kernel.org/r/b9565874-7018-46ef-b123-b524a1dffb21@xxxxxxxxxxxxxxxxx Signed-off-by: Gao Xiang <hsiangkao@xxxxxxxxxxxxxxxxx> --- fs/super.c | 41 ++++++++++++++++++++++++++------------ include/linux/fs_context.h | 3 +++ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/fs/super.c b/fs/super.c index 1db230432960..8cc8350b9ba6 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1596,26 +1596,17 @@ int setup_bdev_super(struct super_block *sb, int sb_flags, EXPORT_SYMBOL_GPL(setup_bdev_super); /** - * get_tree_bdev - Get a superblock based on a single block device + * get_tree_bdev_by_dev - Get a bdev-based superblock with a given device number * @fc: The filesystem context holding the parameters * @fill_super: Helper to initialise a new superblock + * @dev: The device number indicating the target block device */ -int get_tree_bdev(struct fs_context *fc, +int get_tree_bdev_by_dev(struct fs_context *fc, int (*fill_super)(struct super_block *, - struct fs_context *)) + struct fs_context *), dev_t dev) { struct super_block *s; int error = 0; - dev_t dev; - - if (!fc->source) - return invalf(fc, "No source specified"); - - error = lookup_bdev(fc->source, &dev); - if (error) { - errorf(fc, "%s: Can't lookup blockdev", fc->source); - return error; - } fc->sb_flags |= SB_NOSEC; s = sget_dev(fc, dev); @@ -1644,6 +1635,30 @@ int get_tree_bdev(struct fs_context *fc, fc->root = dget(s->s_root); return 0; } +EXPORT_SYMBOL_GPL(get_tree_bdev_by_dev); + +/** + * get_tree_bdev - Get a superblock based on a single block device + * @fc: The filesystem context holding the parameters + * @fill_super: Helper to initialise a new superblock + */ +int get_tree_bdev(struct fs_context *fc, + int (*fill_super)(struct super_block *, + struct fs_context *)) +{ + int error; + dev_t dev; + + if (!fc->source) + return invalf(fc, "No source specified"); + + error = lookup_bdev(fc->source, &dev); + if (error) { + errorf(fc, "%s: Can't lookup blockdev", fc->source); + return error; + } + return get_tree_bdev_by_dev(fc, fill_super, dev); +} EXPORT_SYMBOL(get_tree_bdev); static int test_bdev_super(struct super_block *s, void *data) diff --git a/include/linux/fs_context.h b/include/linux/fs_context.h index c13e99cbbf81..54f23589ad5b 100644 --- a/include/linux/fs_context.h +++ b/include/linux/fs_context.h @@ -160,6 +160,9 @@ extern int get_tree_keyed(struct fs_context *fc, int setup_bdev_super(struct super_block *sb, int sb_flags, struct fs_context *fc); +int get_tree_bdev_by_dev(struct fs_context *fc, + int (*fill_super)(struct super_block *sb, + struct fs_context *fc), dev_t dev); extern int get_tree_bdev(struct fs_context *fc, int (*fill_super)(struct super_block *sb, struct fs_context *fc)); -- 2.43.5