mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 09:16:33 +00:00
ext4: Change handle_mount_opt() to use fs_parameter
Use the new mount option specifications to parse the options in handle_mount_opt(). However we're still using the old API to get the options string. Signed-off-by: Lukas Czerner <lczerner@redhat.com> Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com> Link: https://lore.kernel.org/r/20211027141857.33657-5-lczerner@redhat.com Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
parent
4c94bff967
commit
461c3af045
250
fs/ext4/super.c
250
fs/ext4/super.c
@ -1981,7 +1981,8 @@ static const char deprecated_msg[] =
|
||||
"Contact linux-ext4@vger.kernel.org if you think we should keep it.\n";
|
||||
|
||||
#ifdef CONFIG_QUOTA
|
||||
static int set_qf_name(struct super_block *sb, int qtype, substring_t *args)
|
||||
static int set_qf_name(struct super_block *sb, int qtype,
|
||||
struct fs_parameter *param)
|
||||
{
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
char *qname, *old_qname = get_qf_name(sb, sbi, qtype);
|
||||
@ -1998,7 +1999,7 @@ static int set_qf_name(struct super_block *sb, int qtype, substring_t *args)
|
||||
"ignored when QUOTA feature is enabled");
|
||||
return 1;
|
||||
}
|
||||
qname = match_strdup(args);
|
||||
qname = kmemdup_nul(param->string, param->size, GFP_KERNEL);
|
||||
if (!qname) {
|
||||
ext4_msg(sb, KERN_ERR,
|
||||
"Not enough memory for storing quotafile name");
|
||||
@ -2204,8 +2205,7 @@ static int ext4_sb_read_encoding(const struct ext4_super_block *es,
|
||||
#endif
|
||||
|
||||
static int ext4_set_test_dummy_encryption(struct super_block *sb,
|
||||
const char *opt,
|
||||
const substring_t *arg,
|
||||
struct fs_parameter *param,
|
||||
bool is_remount)
|
||||
{
|
||||
#ifdef CONFIG_FS_ENCRYPTION
|
||||
@ -2223,7 +2223,7 @@ static int ext4_set_test_dummy_encryption(struct super_block *sb,
|
||||
"Can't set test_dummy_encryption on remount");
|
||||
return -1;
|
||||
}
|
||||
err = fscrypt_set_test_dummy_encryption(sb, arg->from,
|
||||
err = fscrypt_set_test_dummy_encryption(sb, param->string,
|
||||
&sbi->s_dummy_enc_policy);
|
||||
if (err) {
|
||||
if (err == -EEXIST)
|
||||
@ -2231,11 +2231,12 @@ static int ext4_set_test_dummy_encryption(struct super_block *sb,
|
||||
"Can't change test_dummy_encryption on remount");
|
||||
else if (err == -EINVAL)
|
||||
ext4_msg(sb, KERN_WARNING,
|
||||
"Value of option \"%s\" is unrecognized", opt);
|
||||
"Value of option \"%s\" is unrecognized",
|
||||
param->key);
|
||||
else
|
||||
ext4_msg(sb, KERN_WARNING,
|
||||
"Error processing option \"%s\" [%d]",
|
||||
opt, err);
|
||||
param->key, err);
|
||||
return -1;
|
||||
}
|
||||
ext4_msg(sb, KERN_WARNING, "Test dummy encryption mode enabled");
|
||||
@ -2246,41 +2247,52 @@ static int ext4_set_test_dummy_encryption(struct super_block *sb,
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ext4_parsed_options {
|
||||
struct ext4_fs_context {
|
||||
unsigned long journal_devnum;
|
||||
unsigned int journal_ioprio;
|
||||
int mb_optimize_scan;
|
||||
};
|
||||
|
||||
static int handle_mount_opt(struct super_block *sb, char *opt, int token,
|
||||
substring_t *args, struct ext4_parsed_options *parsed_opts,
|
||||
int is_remount)
|
||||
static int handle_mount_opt(struct fs_context *fc, struct fs_parameter *param)
|
||||
{
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
struct ext4_fs_context *ctx = fc->fs_private;
|
||||
struct ext4_sb_info *sbi = fc->s_fs_info;
|
||||
struct super_block *sb = sbi->s_sb;
|
||||
struct fs_parse_result result;
|
||||
const struct mount_opts *m;
|
||||
int is_remount;
|
||||
kuid_t uid;
|
||||
kgid_t gid;
|
||||
int arg = 0;
|
||||
int token;
|
||||
|
||||
token = fs_parse(fc, ext4_param_specs, param, &result);
|
||||
if (token < 0)
|
||||
return token;
|
||||
is_remount = fc->purpose == FS_CONTEXT_FOR_RECONFIGURE;
|
||||
|
||||
#ifdef CONFIG_QUOTA
|
||||
if (token == Opt_usrjquota)
|
||||
return set_qf_name(sb, USRQUOTA, &args[0]);
|
||||
else if (token == Opt_grpjquota)
|
||||
return set_qf_name(sb, GRPQUOTA, &args[0]);
|
||||
else if (token == Opt_offusrjquota)
|
||||
return clear_qf_name(sb, USRQUOTA);
|
||||
else if (token == Opt_offgrpjquota)
|
||||
return clear_qf_name(sb, GRPQUOTA);
|
||||
if (token == Opt_usrjquota) {
|
||||
if (!*param->string)
|
||||
return clear_qf_name(sb, USRQUOTA);
|
||||
else
|
||||
return set_qf_name(sb, USRQUOTA, param);
|
||||
} else if (token == Opt_grpjquota) {
|
||||
if (!*param->string)
|
||||
return clear_qf_name(sb, GRPQUOTA);
|
||||
else
|
||||
return set_qf_name(sb, GRPQUOTA, param);
|
||||
}
|
||||
#endif
|
||||
switch (token) {
|
||||
case Opt_noacl:
|
||||
case Opt_nouser_xattr:
|
||||
ext4_msg(sb, KERN_WARNING, deprecated_msg, opt, "3.5");
|
||||
ext4_msg(sb, KERN_WARNING, deprecated_msg, param->key, "3.5");
|
||||
break;
|
||||
case Opt_sb:
|
||||
return 1; /* handled by get_sb_block() */
|
||||
case Opt_removed:
|
||||
ext4_msg(sb, KERN_WARNING, "Ignoring removed %s option", opt);
|
||||
ext4_msg(sb, KERN_WARNING, "Ignoring removed %s option",
|
||||
param->key);
|
||||
return 1;
|
||||
case Opt_abort:
|
||||
ext4_set_mount_flag(sb, EXT4_MF_FS_ABORTED);
|
||||
@ -2301,6 +2313,12 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
|
||||
ext4_msg(sb, KERN_ERR, "inline encryption not supported");
|
||||
#endif
|
||||
return 1;
|
||||
case Opt_errors:
|
||||
case Opt_data:
|
||||
case Opt_data_err:
|
||||
case Opt_jqfmt:
|
||||
case Opt_dax_type:
|
||||
token = result.uint_32;
|
||||
}
|
||||
|
||||
for (m = ext4_mount_opts; m->token != Opt_err; m++)
|
||||
@ -2309,25 +2327,23 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
|
||||
|
||||
if (m->token == Opt_err) {
|
||||
ext4_msg(sb, KERN_ERR, "Unrecognized mount option \"%s\" "
|
||||
"or missing value", opt);
|
||||
"or missing value", param->key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((m->flags & MOPT_NO_EXT2) && IS_EXT2_SB(sb)) {
|
||||
ext4_msg(sb, KERN_ERR,
|
||||
"Mount option \"%s\" incompatible with ext2", opt);
|
||||
"Mount option \"%s\" incompatible with ext2",
|
||||
param->key);
|
||||
return -1;
|
||||
}
|
||||
if ((m->flags & MOPT_NO_EXT3) && IS_EXT3_SB(sb)) {
|
||||
ext4_msg(sb, KERN_ERR,
|
||||
"Mount option \"%s\" incompatible with ext3", opt);
|
||||
"Mount option \"%s\" incompatible with ext3",
|
||||
param->key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (args->from && !(m->flags & MOPT_STRING) && match_int(args, &arg))
|
||||
return -1;
|
||||
if (args->from && (m->flags & MOPT_GTE0) && (arg < 0))
|
||||
return -1;
|
||||
if (m->flags & MOPT_EXPLICIT) {
|
||||
if (m->mount_opt & EXT4_MOUNT_DELALLOC) {
|
||||
set_opt2(sb, EXPLICIT_DELALLOC);
|
||||
@ -2345,63 +2361,69 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
|
||||
}
|
||||
|
||||
if (m->flags & MOPT_NOSUPPORT) {
|
||||
ext4_msg(sb, KERN_ERR, "%s option not supported", opt);
|
||||
ext4_msg(sb, KERN_ERR, "%s option not supported",
|
||||
param->key);
|
||||
} else if (token == Opt_commit) {
|
||||
if (arg == 0)
|
||||
arg = JBD2_DEFAULT_MAX_COMMIT_AGE;
|
||||
else if (arg > INT_MAX / HZ) {
|
||||
if (result.uint_32 == 0)
|
||||
sbi->s_commit_interval = JBD2_DEFAULT_MAX_COMMIT_AGE;
|
||||
else if (result.uint_32 > INT_MAX / HZ) {
|
||||
ext4_msg(sb, KERN_ERR,
|
||||
"Invalid commit interval %d, "
|
||||
"must be smaller than %d",
|
||||
arg, INT_MAX / HZ);
|
||||
result.uint_32, INT_MAX / HZ);
|
||||
return -1;
|
||||
}
|
||||
sbi->s_commit_interval = HZ * arg;
|
||||
sbi->s_commit_interval = HZ * result.uint_32;
|
||||
} else if (token == Opt_debug_want_extra_isize) {
|
||||
if ((arg & 1) ||
|
||||
(arg < 4) ||
|
||||
(arg > (sbi->s_inode_size - EXT4_GOOD_OLD_INODE_SIZE))) {
|
||||
if ((result.uint_32 & 1) ||
|
||||
(result.uint_32 < 4) ||
|
||||
(result.uint_32 >
|
||||
(sbi->s_inode_size - EXT4_GOOD_OLD_INODE_SIZE))) {
|
||||
ext4_msg(sb, KERN_ERR,
|
||||
"Invalid want_extra_isize %d", arg);
|
||||
"Invalid want_extra_isize %d", result.uint_32);
|
||||
return -1;
|
||||
}
|
||||
sbi->s_want_extra_isize = arg;
|
||||
sbi->s_want_extra_isize = result.uint_32;
|
||||
} else if (token == Opt_max_batch_time) {
|
||||
sbi->s_max_batch_time = arg;
|
||||
sbi->s_max_batch_time = result.uint_32;
|
||||
} else if (token == Opt_min_batch_time) {
|
||||
sbi->s_min_batch_time = arg;
|
||||
sbi->s_min_batch_time = result.uint_32;
|
||||
} else if (token == Opt_inode_readahead_blks) {
|
||||
if (arg && (arg > (1 << 30) || !is_power_of_2(arg))) {
|
||||
if (result.uint_32 &&
|
||||
(result.uint_32 > (1 << 30) ||
|
||||
!is_power_of_2(result.uint_32))) {
|
||||
ext4_msg(sb, KERN_ERR,
|
||||
"EXT4-fs: inode_readahead_blks must be "
|
||||
"0 or a power of 2 smaller than 2^31");
|
||||
return -1;
|
||||
}
|
||||
sbi->s_inode_readahead_blks = arg;
|
||||
sbi->s_inode_readahead_blks = result.uint_32;
|
||||
} else if (token == Opt_init_itable) {
|
||||
set_opt(sb, INIT_INODE_TABLE);
|
||||
if (!args->from)
|
||||
arg = EXT4_DEF_LI_WAIT_MULT;
|
||||
sbi->s_li_wait_mult = arg;
|
||||
sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT;
|
||||
if (param->type == fs_value_is_string)
|
||||
sbi->s_li_wait_mult = result.uint_32;
|
||||
} else if (token == Opt_max_dir_size_kb) {
|
||||
sbi->s_max_dir_size_kb = arg;
|
||||
sbi->s_max_dir_size_kb = result.uint_32;
|
||||
#ifdef CONFIG_EXT4_DEBUG
|
||||
} else if (token == Opt_fc_debug_max_replay) {
|
||||
sbi->s_fc_debug_max_replay = arg;
|
||||
sbi->s_fc_debug_max_replay = result.uint_32;
|
||||
#endif
|
||||
} else if (token == Opt_stripe) {
|
||||
sbi->s_stripe = arg;
|
||||
sbi->s_stripe = result.uint_32;
|
||||
} else if (token == Opt_resuid) {
|
||||
uid = make_kuid(current_user_ns(), arg);
|
||||
uid = make_kuid(current_user_ns(), result.uint_32);
|
||||
if (!uid_valid(uid)) {
|
||||
ext4_msg(sb, KERN_ERR, "Invalid uid value %d", arg);
|
||||
ext4_msg(sb, KERN_ERR, "Invalid uid value %d",
|
||||
result.uint_32);
|
||||
return -1;
|
||||
}
|
||||
sbi->s_resuid = uid;
|
||||
} else if (token == Opt_resgid) {
|
||||
gid = make_kgid(current_user_ns(), arg);
|
||||
gid = make_kgid(current_user_ns(), result.uint_32);
|
||||
if (!gid_valid(gid)) {
|
||||
ext4_msg(sb, KERN_ERR, "Invalid gid value %d", arg);
|
||||
ext4_msg(sb, KERN_ERR, "Invalid gid value %d",
|
||||
result.uint_32);
|
||||
return -1;
|
||||
}
|
||||
sbi->s_resgid = gid;
|
||||
@ -2411,9 +2433,8 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
|
||||
"Cannot specify journal on remount");
|
||||
return -1;
|
||||
}
|
||||
parsed_opts->journal_devnum = arg;
|
||||
ctx->journal_devnum = result.uint_32;
|
||||
} else if (token == Opt_journal_path) {
|
||||
char *journal_path;
|
||||
struct inode *journal_inode;
|
||||
struct path path;
|
||||
int error;
|
||||
@ -2423,44 +2444,27 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
|
||||
"Cannot specify journal on remount");
|
||||
return -1;
|
||||
}
|
||||
journal_path = match_strdup(&args[0]);
|
||||
if (!journal_path) {
|
||||
ext4_msg(sb, KERN_ERR, "error: could not dup "
|
||||
"journal device string");
|
||||
return -1;
|
||||
}
|
||||
|
||||
error = kern_path(journal_path, LOOKUP_FOLLOW, &path);
|
||||
error = fs_lookup_param(fc, param, 1, &path);
|
||||
if (error) {
|
||||
ext4_msg(sb, KERN_ERR, "error: could not find "
|
||||
"journal device path: error %d", error);
|
||||
kfree(journal_path);
|
||||
"journal device path");
|
||||
return -1;
|
||||
}
|
||||
|
||||
journal_inode = d_inode(path.dentry);
|
||||
if (!S_ISBLK(journal_inode->i_mode)) {
|
||||
ext4_msg(sb, KERN_ERR, "error: journal path %s "
|
||||
"is not a block device", journal_path);
|
||||
path_put(&path);
|
||||
kfree(journal_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
parsed_opts->journal_devnum = new_encode_dev(journal_inode->i_rdev);
|
||||
ctx->journal_devnum = new_encode_dev(journal_inode->i_rdev);
|
||||
path_put(&path);
|
||||
kfree(journal_path);
|
||||
} else if (token == Opt_journal_ioprio) {
|
||||
if (arg > 7) {
|
||||
if (result.uint_32 > 7) {
|
||||
ext4_msg(sb, KERN_ERR, "Invalid journal IO priority"
|
||||
" (must be 0-7)");
|
||||
return -1;
|
||||
}
|
||||
parsed_opts->journal_ioprio =
|
||||
IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, arg);
|
||||
ctx->journal_ioprio =
|
||||
IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, result.uint_32);
|
||||
} else if (token == Opt_test_dummy_encryption) {
|
||||
return ext4_set_test_dummy_encryption(sb, opt, &args[0],
|
||||
is_remount);
|
||||
return ext4_set_test_dummy_encryption(sb, param, is_remount);
|
||||
} else if (m->flags & MOPT_DATAJ) {
|
||||
if (is_remount) {
|
||||
if (!sbi->s_journal)
|
||||
@ -2547,30 +2551,35 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
|
||||
} else if (token == Opt_data_err_ignore) {
|
||||
sbi->s_mount_opt &= ~m->mount_opt;
|
||||
} else if (token == Opt_mb_optimize_scan) {
|
||||
if (arg != 0 && arg != 1) {
|
||||
if (result.int_32 != 0 && result.int_32 != 1) {
|
||||
ext4_msg(sb, KERN_WARNING,
|
||||
"mb_optimize_scan should be set to 0 or 1.");
|
||||
return -1;
|
||||
}
|
||||
parsed_opts->mb_optimize_scan = arg;
|
||||
ctx->mb_optimize_scan = result.int_32;
|
||||
} else {
|
||||
if (!args->from)
|
||||
arg = 1;
|
||||
unsigned int set = 0;
|
||||
|
||||
if ((param->type == fs_value_is_flag) ||
|
||||
result.uint_32 > 0)
|
||||
set = 1;
|
||||
|
||||
if (m->flags & MOPT_CLEAR)
|
||||
arg = !arg;
|
||||
set = !set;
|
||||
else if (unlikely(!(m->flags & MOPT_SET))) {
|
||||
ext4_msg(sb, KERN_WARNING,
|
||||
"buggy handling of option %s", opt);
|
||||
"buggy handling of option %s",
|
||||
param->key);
|
||||
WARN_ON(1);
|
||||
return -1;
|
||||
}
|
||||
if (m->flags & MOPT_2) {
|
||||
if (arg != 0)
|
||||
if (set != 0)
|
||||
sbi->s_mount_opt2 |= m->mount_opt;
|
||||
else
|
||||
sbi->s_mount_opt2 &= ~m->mount_opt;
|
||||
} else {
|
||||
if (arg != 0)
|
||||
if (set != 0)
|
||||
sbi->s_mount_opt |= m->mount_opt;
|
||||
else
|
||||
sbi->s_mount_opt &= ~m->mount_opt;
|
||||
@ -2580,29 +2589,56 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
|
||||
}
|
||||
|
||||
static int parse_options(char *options, struct super_block *sb,
|
||||
struct ext4_parsed_options *ret_opts,
|
||||
struct ext4_fs_context *ret_opts,
|
||||
int is_remount)
|
||||
{
|
||||
substring_t args[MAX_OPT_ARGS];
|
||||
int token;
|
||||
char *p;
|
||||
struct fs_parameter param;
|
||||
struct fs_context fc;
|
||||
int ret;
|
||||
char *key;
|
||||
|
||||
if (!options)
|
||||
return 1;
|
||||
|
||||
while ((p = strsep(&options, ",")) != NULL) {
|
||||
if (!*p)
|
||||
continue;
|
||||
/*
|
||||
* Initialize args struct so we know whether arg was
|
||||
* found; some options take optional arguments.
|
||||
*/
|
||||
args[0].to = args[0].from = NULL;
|
||||
token = match_token(p, tokens, args);
|
||||
if (handle_mount_opt(sb, p, token, args, ret_opts,
|
||||
is_remount) < 0)
|
||||
return 0;
|
||||
memset(&fc, 0, sizeof(fc));
|
||||
fc.fs_private = ret_opts;
|
||||
fc.s_fs_info = EXT4_SB(sb);
|
||||
|
||||
if (is_remount)
|
||||
fc.purpose = FS_CONTEXT_FOR_RECONFIGURE;
|
||||
|
||||
while ((key = strsep(&options, ",")) != NULL) {
|
||||
if (*key) {
|
||||
size_t v_len = 0;
|
||||
char *value = strchr(key, '=');
|
||||
|
||||
param.type = fs_value_is_flag;
|
||||
param.string = NULL;
|
||||
|
||||
if (value) {
|
||||
if (value == key)
|
||||
continue;
|
||||
|
||||
*value++ = 0;
|
||||
v_len = strlen(value);
|
||||
param.string = kmemdup_nul(value, v_len,
|
||||
GFP_KERNEL);
|
||||
if (!param.string)
|
||||
return 0;
|
||||
param.type = fs_value_is_string;
|
||||
}
|
||||
|
||||
param.key = key;
|
||||
param.size = v_len;
|
||||
|
||||
ret = handle_mount_opt(&fc, ¶m);
|
||||
if (param.string)
|
||||
kfree(param.string);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ext4_validate_options(sb);
|
||||
}
|
||||
|
||||
@ -4057,7 +4093,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||
__u64 blocks_count;
|
||||
int err = 0;
|
||||
ext4_group_t first_not_zeroed;
|
||||
struct ext4_parsed_options parsed_opts;
|
||||
struct ext4_fs_context parsed_opts;
|
||||
|
||||
/* Set defaults for the variables that will be set during parsing */
|
||||
parsed_opts.journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
|
||||
@ -5899,7 +5935,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
||||
char *to_free[EXT4_MAXQUOTAS];
|
||||
#endif
|
||||
char *orig_data = kstrdup(data, GFP_KERNEL);
|
||||
struct ext4_parsed_options parsed_opts;
|
||||
struct ext4_fs_context parsed_opts;
|
||||
|
||||
parsed_opts.journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
|
||||
parsed_opts.journal_devnum = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user