Hi Christian,
On 2024/10/7 19:35, Christian Brauner wrote:
On Sat, Oct 05, 2024 at 10:41:10PM GMT, Gao Xiang wrote:
...
Hi Christian, if possible, could you give some other
idea to handle this case better? Many thanks!
Thanks for the reply!
(1) Require that the path be qualified like:
fsconfig(<fd>, FSCONFIG_SET_STRING, "source", "file:/home/lis/src/mountcfs/cfs", 0)
and match on it in either erofs_*_get_tree() or by adding a custom
function for the Opt_source/"source" parameter.
IMHO, Users could create names with the prefix `file:`,
it's somewhat strange to define a fixed prefix by the
definition of source path fc->source.
Although there could be some escape character likewise
way, but I'm not sure if it's worthwhile to work out
this in kernel.
(2) Add a erofs specific "source-file" mount option. IOW, check that
either "source-file" or "source" was specified but not both. You
could even set fc->source to "source-file" value and fail if
fc->source is already set. You get the idea.
I once thought to add a new mount option too, yet from
the user perpertive, I think users may not care about
the source type of an arbitary path, and the kernel also
can parse the type of the source path directly... so..
So.. I wonder if it's possible to add a new VFS interface
like get_tree_bdev_by_dev() for filesystems to specify a
device number rather than hardcoded hard-coded source path
way, e.g. I could see the potential benefits other than
the EROFS use case:
- Filesystems can have other ways to get a bdev-based sb
in addition to the current hard-coded source path way;
- Some pseudo fs can use this way to generate a fs from a
bdev.
- Just like get_tree_nodev(), it doesn't strictly tie to
fc->source too.
Also EROFS could lookup_bdev() (this kAPI is already
exported) itself to check if it uses get_tree_bdev_by_dev()
or get_tree_nodev()... Does it sounds good? Many thanks!
Thanks,
Gao Xiang
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));
?