`fsparam_bdev` uses `fs_param_is_blockdev` to parse the option, but it is currently empty. Filesystems like ext4 use the `fsparam_bdev` to parse `journal_path` into the block device. This general logic should be moved to the vfs layer, not the specific filesystem. Therefore, we implement block device parser in `fs_param_is_blockdev`. And the logic is similar with `fs_lookup_param`. Signed-off-by: Hongbo Li <lihongbo22@xxxxxxxxxx> --- fs/fs_parser.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/fs/fs_parser.c b/fs/fs_parser.c index a4d6ca0b8971..48f60ecfcca0 100644 --- a/fs/fs_parser.c +++ b/fs/fs_parser.c @@ -311,7 +311,56 @@ EXPORT_SYMBOL(fs_param_is_fd); int fs_param_is_blockdev(struct p_log *log, const struct fs_parameter_spec *p, struct fs_parameter *param, struct fs_parse_result *result) { - return 0; + int ret; + int dfd; + struct filename *f; + struct inode *dev_inode; + struct path path; + bool put_f; + + switch (param->type) { + case fs_value_is_string: + if (!*param->string) { + if (p->flags & fs_param_can_be_empty) + return 0; + break; + } + f = getname_kernel(param->string); + if (IS_ERR(f)) + return fs_param_bad_value(log, param); + dfd = AT_FDCWD; + put_f = true; + break; + case fs_value_is_filename: + f = param->name; + dfd = param->dirfd; + put_f = false; + break; + default: + return fs_param_bad_value(log, param); + } + + ret = filename_lookup(dfd, f, LOOKUP_FOLLOW, &path, NULL); + if (ret < 0) { + error_plog(log, "%s: Lookup failure for '%s'", param->key, f->name); + goto out_putname; + } + + dev_inode = d_backing_inode(path.dentry); + if (!S_ISBLK(dev_inode->i_mode)) { + error_plog(log, "%s: Non-blockdev passed as '%s'", param->key, f->name); + ret = -1; + goto out_putpath; + } + result->uint_32 = new_encode_dev(dev_inode->i_rdev); + +out_putpath: + path_put(&path); +out_putname: + if (put_f) + putname(f); + + return (ret < 0) ? fs_param_bad_value(log, param) : 0; } EXPORT_SYMBOL(fs_param_is_blockdev); -- 2.34.1