Commit c0123ade authored by Tiger Yang's avatar Tiger Yang Committed by Mark Fasheh

[PATCH] ocfs2: fix mount option parsing

For some mount option types, ocfs2_parse_options() will try to access
sb->s_fs_info to get at the ocfs2 private superblock. Unfortunately, that
hasn't been allocated yet and will cause a kernel crash.

Fix this by storing options in a struct which can then get pushed into the
ocfs2_super once it's been allocated later. If we need more options which
store to the ocfs2_super in the future, we can just fields to this struct.
Signed-off-by: default avatarTiger Yang <tiger.yang@oracle.com>
Signed-off-by: default avatarMark Fasheh <mark.fasheh@oracle.com>
parent 10b0845b
...@@ -81,8 +81,15 @@ static struct dentry *ocfs2_debugfs_root = NULL; ...@@ -81,8 +81,15 @@ static struct dentry *ocfs2_debugfs_root = NULL;
MODULE_AUTHOR("Oracle"); MODULE_AUTHOR("Oracle");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
struct mount_options
{
unsigned long mount_opt;
unsigned int atime_quantum;
signed short slot;
};
static int ocfs2_parse_options(struct super_block *sb, char *options, static int ocfs2_parse_options(struct super_block *sb, char *options,
unsigned long *mount_opt, s16 *slot, struct mount_options *mopt,
int is_remount); int is_remount);
static void ocfs2_put_super(struct super_block *sb); static void ocfs2_put_super(struct super_block *sb);
static int ocfs2_mount_volume(struct super_block *sb); static int ocfs2_mount_volume(struct super_block *sb);
...@@ -367,24 +374,23 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data) ...@@ -367,24 +374,23 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
{ {
int incompat_features; int incompat_features;
int ret = 0; int ret = 0;
unsigned long parsed_options; struct mount_options parsed_options;
s16 slot;
struct ocfs2_super *osb = OCFS2_SB(sb); struct ocfs2_super *osb = OCFS2_SB(sb);
if (!ocfs2_parse_options(sb, data, &parsed_options, &slot, 1)) { if (!ocfs2_parse_options(sb, data, &parsed_options, 1)) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
if ((osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL) != if ((osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL) !=
(parsed_options & OCFS2_MOUNT_HB_LOCAL)) { (parsed_options.mount_opt & OCFS2_MOUNT_HB_LOCAL)) {
ret = -EINVAL; ret = -EINVAL;
mlog(ML_ERROR, "Cannot change heartbeat mode on remount\n"); mlog(ML_ERROR, "Cannot change heartbeat mode on remount\n");
goto out; goto out;
} }
if ((osb->s_mount_opt & OCFS2_MOUNT_DATA_WRITEBACK) != if ((osb->s_mount_opt & OCFS2_MOUNT_DATA_WRITEBACK) !=
(parsed_options & OCFS2_MOUNT_DATA_WRITEBACK)) { (parsed_options.mount_opt & OCFS2_MOUNT_DATA_WRITEBACK)) {
ret = -EINVAL; ret = -EINVAL;
mlog(ML_ERROR, "Cannot change data mode on remount\n"); mlog(ML_ERROR, "Cannot change data mode on remount\n");
goto out; goto out;
...@@ -435,7 +441,9 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data) ...@@ -435,7 +441,9 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
/* Only save off the new mount options in case of a successful /* Only save off the new mount options in case of a successful
* remount. */ * remount. */
osb->s_mount_opt = parsed_options; osb->s_mount_opt = parsed_options.mount_opt;
osb->s_atime_quantum = parsed_options.atime_quantum;
osb->preferred_slot = parsed_options.slot;
} }
out: out:
return ret; return ret;
...@@ -547,8 +555,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) ...@@ -547,8 +555,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
{ {
struct dentry *root; struct dentry *root;
int status, sector_size; int status, sector_size;
unsigned long parsed_opt; struct mount_options parsed_options;
s16 slot;
struct inode *inode = NULL; struct inode *inode = NULL;
struct ocfs2_super *osb = NULL; struct ocfs2_super *osb = NULL;
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
...@@ -556,14 +563,14 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) ...@@ -556,14 +563,14 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
mlog_entry("%p, %p, %i", sb, data, silent); mlog_entry("%p, %p, %i", sb, data, silent);
if (!ocfs2_parse_options(sb, data, &parsed_opt, &slot, 0)) { if (!ocfs2_parse_options(sb, data, &parsed_options, 0)) {
status = -EINVAL; status = -EINVAL;
goto read_super_error; goto read_super_error;
} }
/* for now we only have one cluster/node, make sure we see it /* for now we only have one cluster/node, make sure we see it
* in the heartbeat universe */ * in the heartbeat universe */
if (parsed_opt & OCFS2_MOUNT_HB_LOCAL) { if (parsed_options.mount_opt & OCFS2_MOUNT_HB_LOCAL) {
if (!o2hb_check_local_node_heartbeating()) { if (!o2hb_check_local_node_heartbeating()) {
status = -EINVAL; status = -EINVAL;
goto read_super_error; goto read_super_error;
...@@ -585,8 +592,9 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) ...@@ -585,8 +592,9 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
} }
brelse(bh); brelse(bh);
bh = NULL; bh = NULL;
osb->s_mount_opt = parsed_opt; osb->s_mount_opt = parsed_options.mount_opt;
osb->preferred_slot = slot; osb->s_atime_quantum = parsed_options.atime_quantum;
osb->preferred_slot = parsed_options.slot;
sb->s_magic = OCFS2_SUPER_MAGIC; sb->s_magic = OCFS2_SUPER_MAGIC;
...@@ -728,8 +736,7 @@ static struct file_system_type ocfs2_fs_type = { ...@@ -728,8 +736,7 @@ static struct file_system_type ocfs2_fs_type = {
static int ocfs2_parse_options(struct super_block *sb, static int ocfs2_parse_options(struct super_block *sb,
char *options, char *options,
unsigned long *mount_opt, struct mount_options *mopt,
s16 *slot,
int is_remount) int is_remount)
{ {
int status; int status;
...@@ -738,8 +745,9 @@ static int ocfs2_parse_options(struct super_block *sb, ...@@ -738,8 +745,9 @@ static int ocfs2_parse_options(struct super_block *sb,
mlog_entry("remount: %d, options: \"%s\"\n", is_remount, mlog_entry("remount: %d, options: \"%s\"\n", is_remount,
options ? options : "(none)"); options ? options : "(none)");
*mount_opt = 0; mopt->mount_opt = 0;
*slot = OCFS2_INVALID_SLOT; mopt->atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM;
mopt->slot = OCFS2_INVALID_SLOT;
if (!options) { if (!options) {
status = 1; status = 1;
...@@ -749,7 +757,6 @@ static int ocfs2_parse_options(struct super_block *sb, ...@@ -749,7 +757,6 @@ static int ocfs2_parse_options(struct super_block *sb,
while ((p = strsep(&options, ",")) != NULL) { while ((p = strsep(&options, ",")) != NULL) {
int token, option; int token, option;
substring_t args[MAX_OPT_ARGS]; substring_t args[MAX_OPT_ARGS];
struct ocfs2_super * osb = OCFS2_SB(sb);
if (!*p) if (!*p)
continue; continue;
...@@ -757,10 +764,10 @@ static int ocfs2_parse_options(struct super_block *sb, ...@@ -757,10 +764,10 @@ static int ocfs2_parse_options(struct super_block *sb,
token = match_token(p, tokens, args); token = match_token(p, tokens, args);
switch (token) { switch (token) {
case Opt_hb_local: case Opt_hb_local:
*mount_opt |= OCFS2_MOUNT_HB_LOCAL; mopt->mount_opt |= OCFS2_MOUNT_HB_LOCAL;
break; break;
case Opt_hb_none: case Opt_hb_none:
*mount_opt &= ~OCFS2_MOUNT_HB_LOCAL; mopt->mount_opt &= ~OCFS2_MOUNT_HB_LOCAL;
break; break;
case Opt_barrier: case Opt_barrier:
if (match_int(&args[0], &option)) { if (match_int(&args[0], &option)) {
...@@ -768,27 +775,27 @@ static int ocfs2_parse_options(struct super_block *sb, ...@@ -768,27 +775,27 @@ static int ocfs2_parse_options(struct super_block *sb,
goto bail; goto bail;
} }
if (option) if (option)
*mount_opt |= OCFS2_MOUNT_BARRIER; mopt->mount_opt |= OCFS2_MOUNT_BARRIER;
else else
*mount_opt &= ~OCFS2_MOUNT_BARRIER; mopt->mount_opt &= ~OCFS2_MOUNT_BARRIER;
break; break;
case Opt_intr: case Opt_intr:
*mount_opt &= ~OCFS2_MOUNT_NOINTR; mopt->mount_opt &= ~OCFS2_MOUNT_NOINTR;
break; break;
case Opt_nointr: case Opt_nointr:
*mount_opt |= OCFS2_MOUNT_NOINTR; mopt->mount_opt |= OCFS2_MOUNT_NOINTR;
break; break;
case Opt_err_panic: case Opt_err_panic:
*mount_opt |= OCFS2_MOUNT_ERRORS_PANIC; mopt->mount_opt |= OCFS2_MOUNT_ERRORS_PANIC;
break; break;
case Opt_err_ro: case Opt_err_ro:
*mount_opt &= ~OCFS2_MOUNT_ERRORS_PANIC; mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_PANIC;
break; break;
case Opt_data_ordered: case Opt_data_ordered:
*mount_opt &= ~OCFS2_MOUNT_DATA_WRITEBACK; mopt->mount_opt &= ~OCFS2_MOUNT_DATA_WRITEBACK;
break; break;
case Opt_data_writeback: case Opt_data_writeback:
*mount_opt |= OCFS2_MOUNT_DATA_WRITEBACK; mopt->mount_opt |= OCFS2_MOUNT_DATA_WRITEBACK;
break; break;
case Opt_atime_quantum: case Opt_atime_quantum:
if (match_int(&args[0], &option)) { if (match_int(&args[0], &option)) {
...@@ -796,9 +803,7 @@ static int ocfs2_parse_options(struct super_block *sb, ...@@ -796,9 +803,7 @@ static int ocfs2_parse_options(struct super_block *sb,
goto bail; goto bail;
} }
if (option >= 0) if (option >= 0)
osb->s_atime_quantum = option; mopt->atime_quantum = option;
else
osb->s_atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM;
break; break;
case Opt_slot: case Opt_slot:
option = 0; option = 0;
...@@ -807,7 +812,7 @@ static int ocfs2_parse_options(struct super_block *sb, ...@@ -807,7 +812,7 @@ static int ocfs2_parse_options(struct super_block *sb,
goto bail; goto bail;
} }
if (option) if (option)
*slot = (s16)option; mopt->slot = (s16)option;
break; break;
default: default:
mlog(ML_ERROR, mlog(ML_ERROR,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment