Commit 08c6a96f authored by Jan Kara's avatar Jan Kara Committed by Linus Torvalds

[PATCH] ext3: fix options parsing

Fix a problem with ext3 mount option parsing.  When remount of a filesystem
fails, old options are now restored.
Signed-off-by: default avatarJan Kara <jack@suse.cz>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 53231250
...@@ -890,7 +890,10 @@ clear_qf_name: ...@@ -890,7 +890,10 @@ clear_qf_name:
"quota turned on.\n"); "quota turned on.\n");
return 0; return 0;
} }
kfree(sbi->s_qf_names[qtype]); /*
* The space will be released later when all options
* are confirmed to be correct
*/
sbi->s_qf_names[qtype] = NULL; sbi->s_qf_names[qtype] = NULL;
break; break;
case Opt_jqfmt_vfsold: case Opt_jqfmt_vfsold:
...@@ -939,7 +942,7 @@ clear_qf_name: ...@@ -939,7 +942,7 @@ clear_qf_name:
case Opt_ignore: case Opt_ignore:
break; break;
case Opt_resize: case Opt_resize:
if (!n_blocks_count) { if (!is_remount) {
printk("EXT3-fs: resize option only available " printk("EXT3-fs: resize option only available "
"for remount\n"); "for remount\n");
return 0; return 0;
...@@ -2109,14 +2112,33 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) ...@@ -2109,14 +2112,33 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
{ {
struct ext3_super_block * es; struct ext3_super_block * es;
struct ext3_sb_info *sbi = EXT3_SB(sb); struct ext3_sb_info *sbi = EXT3_SB(sb);
unsigned long tmp;
unsigned long n_blocks_count = 0; unsigned long n_blocks_count = 0;
unsigned long old_sb_flags;
struct ext3_mount_options old_opts;
int err;
#ifdef CONFIG_QUOTA
int i;
#endif
/* Store the original options */
old_sb_flags = sb->s_flags;
old_opts.s_mount_opt = sbi->s_mount_opt;
old_opts.s_resuid = sbi->s_resuid;
old_opts.s_resgid = sbi->s_resgid;
old_opts.s_commit_interval = sbi->s_commit_interval;
#ifdef CONFIG_QUOTA
old_opts.s_jquota_fmt = sbi->s_jquota_fmt;
for (i = 0; i < MAXQUOTAS; i++)
old_opts.s_qf_names[i] = sbi->s_qf_names[i];
#endif
/* /*
* Allow the "check" option to be passed as a remount option. * Allow the "check" option to be passed as a remount option.
*/ */
if (!parse_options(data, sb, &tmp, &n_blocks_count, 1)) if (!parse_options(data, sb, NULL, &n_blocks_count, 1)) {
return -EINVAL; err = -EINVAL;
goto restore_opts;
}
if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
ext3_abort(sb, __FUNCTION__, "Abort forced by user"); ext3_abort(sb, __FUNCTION__, "Abort forced by user");
...@@ -2130,8 +2152,10 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) ...@@ -2130,8 +2152,10 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) || if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) ||
n_blocks_count > le32_to_cpu(es->s_blocks_count)) { n_blocks_count > le32_to_cpu(es->s_blocks_count)) {
if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) {
return -EROFS; err = -EROFS;
goto restore_opts;
}
if (*flags & MS_RDONLY) { if (*flags & MS_RDONLY) {
/* /*
...@@ -2158,7 +2182,8 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) ...@@ -2158,7 +2182,8 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
"remount RDWR because of unsupported " "remount RDWR because of unsupported "
"optional features (%x).\n", "optional features (%x).\n",
sb->s_id, le32_to_cpu(ret)); sb->s_id, le32_to_cpu(ret));
return -EROFS; err = -EROFS;
goto restore_opts;
} }
/* /*
* Mounting a RDONLY partition read-write, so reread * Mounting a RDONLY partition read-write, so reread
...@@ -2168,13 +2193,38 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) ...@@ -2168,13 +2193,38 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
*/ */
ext3_clear_journal_err(sb, es); ext3_clear_journal_err(sb, es);
sbi->s_mount_state = le16_to_cpu(es->s_state); sbi->s_mount_state = le16_to_cpu(es->s_state);
if ((ret = ext3_group_extend(sb, es, n_blocks_count))) if ((ret = ext3_group_extend(sb, es, n_blocks_count))) {
return ret; err = ret;
goto restore_opts;
}
if (!ext3_setup_super (sb, es, 0)) if (!ext3_setup_super (sb, es, 0))
sb->s_flags &= ~MS_RDONLY; sb->s_flags &= ~MS_RDONLY;
} }
} }
#ifdef CONFIG_QUOTA
/* Release old quota file names */
for (i = 0; i < MAXQUOTAS; i++)
if (old_opts.s_qf_names[i] &&
old_opts.s_qf_names[i] != sbi->s_qf_names[i])
kfree(old_opts.s_qf_names[i]);
#endif
return 0; return 0;
restore_opts:
sb->s_flags = old_sb_flags;
sbi->s_mount_opt = old_opts.s_mount_opt;
sbi->s_resuid = old_opts.s_resuid;
sbi->s_resgid = old_opts.s_resgid;
sbi->s_commit_interval = old_opts.s_commit_interval;
#ifdef CONFIG_QUOTA
sbi->s_jquota_fmt = old_opts.s_jquota_fmt;
for (i = 0; i < MAXQUOTAS; i++) {
if (sbi->s_qf_names[i] &&
old_opts.s_qf_names[i] != sbi->s_qf_names[i])
kfree(sbi->s_qf_names[i]);
sbi->s_qf_names[i] = old_opts.s_qf_names[i];
}
#endif
return err;
} }
static int ext3_statfs (struct super_block * sb, struct kstatfs * buf) static int ext3_statfs (struct super_block * sb, struct kstatfs * buf)
......
...@@ -238,6 +238,20 @@ struct ext3_new_group_data { ...@@ -238,6 +238,20 @@ struct ext3_new_group_data {
#define EXT3_IOC_GETRSVSZ _IOR('f', 5, long) #define EXT3_IOC_GETRSVSZ _IOR('f', 5, long)
#define EXT3_IOC_SETRSVSZ _IOW('f', 6, long) #define EXT3_IOC_SETRSVSZ _IOW('f', 6, long)
/*
* Mount options
*/
struct ext3_mount_options {
unsigned long s_mount_opt;
uid_t s_resuid;
gid_t s_resgid;
unsigned long s_commit_interval;
#ifdef CONFIG_QUOTA
int s_jquota_fmt;
char *s_qf_names[MAXQUOTAS];
#endif
};
/* /*
* Structure of an inode on the disk * Structure of an inode on the disk
*/ */
......
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