|
@@ -43,7 +43,8 @@
|
|
|
#include "acl.h"
|
|
|
#include "namei.h"
|
|
|
|
|
|
-static int ext3_load_journal(struct super_block *, struct ext3_super_block *);
|
|
|
+static int ext3_load_journal(struct super_block *, struct ext3_super_block *,
|
|
|
+ unsigned long journal_devnum);
|
|
|
static int ext3_create_journal(struct super_block *, struct ext3_super_block *,
|
|
|
int);
|
|
|
static void ext3_commit_super (struct super_block * sb,
|
|
@@ -628,7 +629,7 @@ enum {
|
|
|
Opt_nouid32, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
|
|
|
Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
|
|
|
Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh,
|
|
|
- Opt_commit, Opt_journal_update, Opt_journal_inum,
|
|
|
+ Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev,
|
|
|
Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
|
|
|
Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
|
|
|
Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
|
|
@@ -666,6 +667,7 @@ static match_table_t tokens = {
|
|
|
{Opt_commit, "commit=%u"},
|
|
|
{Opt_journal_update, "journal=update"},
|
|
|
{Opt_journal_inum, "journal=%u"},
|
|
|
+ {Opt_journal_dev, "journal_dev=%u"},
|
|
|
{Opt_abort, "abort"},
|
|
|
{Opt_data_journal, "data=journal"},
|
|
|
{Opt_data_ordered, "data=ordered"},
|
|
@@ -705,8 +707,9 @@ static unsigned long get_sb_block(void **data)
|
|
|
return sb_block;
|
|
|
}
|
|
|
|
|
|
-static int parse_options (char * options, struct super_block *sb,
|
|
|
- unsigned long * inum, unsigned long *n_blocks_count, int is_remount)
|
|
|
+static int parse_options (char *options, struct super_block *sb,
|
|
|
+ unsigned long *inum, unsigned long *journal_devnum,
|
|
|
+ unsigned long *n_blocks_count, int is_remount)
|
|
|
{
|
|
|
struct ext3_sb_info *sbi = EXT3_SB(sb);
|
|
|
char * p;
|
|
@@ -839,6 +842,16 @@ static int parse_options (char * options, struct super_block *sb,
|
|
|
return 0;
|
|
|
*inum = option;
|
|
|
break;
|
|
|
+ case Opt_journal_dev:
|
|
|
+ if (is_remount) {
|
|
|
+ printk(KERN_ERR "EXT3-fs: cannot specify "
|
|
|
+ "journal on remount\n");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ if (match_int(&args[0], &option))
|
|
|
+ return 0;
|
|
|
+ *journal_devnum = option;
|
|
|
+ break;
|
|
|
case Opt_noload:
|
|
|
set_opt (sbi->s_mount_opt, NOLOAD);
|
|
|
break;
|
|
@@ -1331,6 +1344,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
|
|
|
unsigned long logic_sb_block;
|
|
|
unsigned long offset = 0;
|
|
|
unsigned long journal_inum = 0;
|
|
|
+ unsigned long journal_devnum = 0;
|
|
|
unsigned long def_mount_opts;
|
|
|
struct inode *root;
|
|
|
int blocksize;
|
|
@@ -1411,7 +1425,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
|
|
|
|
|
|
set_opt(sbi->s_mount_opt, RESERVATION);
|
|
|
|
|
|
- if (!parse_options ((char *) data, sb, &journal_inum, NULL, 0))
|
|
|
+ if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum,
|
|
|
+ NULL, 0))
|
|
|
goto failed_mount;
|
|
|
|
|
|
sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
|
|
@@ -1622,7 +1637,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
|
|
|
*/
|
|
|
if (!test_opt(sb, NOLOAD) &&
|
|
|
EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
|
|
|
- if (ext3_load_journal(sb, es))
|
|
|
+ if (ext3_load_journal(sb, es, journal_devnum))
|
|
|
goto failed_mount2;
|
|
|
} else if (journal_inum) {
|
|
|
if (ext3_create_journal(sb, es, journal_inum))
|
|
@@ -1902,15 +1917,24 @@ out_bdev:
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
-static int ext3_load_journal(struct super_block * sb,
|
|
|
- struct ext3_super_block * es)
|
|
|
+static int ext3_load_journal(struct super_block *sb,
|
|
|
+ struct ext3_super_block *es,
|
|
|
+ unsigned long journal_devnum)
|
|
|
{
|
|
|
journal_t *journal;
|
|
|
int journal_inum = le32_to_cpu(es->s_journal_inum);
|
|
|
- dev_t journal_dev = new_decode_dev(le32_to_cpu(es->s_journal_dev));
|
|
|
+ dev_t journal_dev;
|
|
|
int err = 0;
|
|
|
int really_read_only;
|
|
|
|
|
|
+ if (journal_devnum &&
|
|
|
+ journal_devnum != le32_to_cpu(es->s_journal_dev)) {
|
|
|
+ printk(KERN_INFO "EXT3-fs: external journal device major/minor "
|
|
|
+ "numbers have changed\n");
|
|
|
+ journal_dev = new_decode_dev(journal_devnum);
|
|
|
+ } else
|
|
|
+ journal_dev = new_decode_dev(le32_to_cpu(es->s_journal_dev));
|
|
|
+
|
|
|
really_read_only = bdev_read_only(sb->s_bdev);
|
|
|
|
|
|
/*
|
|
@@ -1969,6 +1993,16 @@ static int ext3_load_journal(struct super_block * sb,
|
|
|
|
|
|
EXT3_SB(sb)->s_journal = journal;
|
|
|
ext3_clear_journal_err(sb, es);
|
|
|
+
|
|
|
+ if (journal_devnum &&
|
|
|
+ journal_devnum != le32_to_cpu(es->s_journal_dev)) {
|
|
|
+ es->s_journal_dev = cpu_to_le32(journal_devnum);
|
|
|
+ sb->s_dirt = 1;
|
|
|
+
|
|
|
+ /* Make sure we flush the recovery flag to disk. */
|
|
|
+ ext3_commit_super(sb, es, 1);
|
|
|
+ }
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -2197,7 +2231,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
|
|
|
/*
|
|
|
* Allow the "check" option to be passed as a remount option.
|
|
|
*/
|
|
|
- if (!parse_options(data, sb, NULL, &n_blocks_count, 1)) {
|
|
|
+ if (!parse_options(data, sb, NULL, NULL, &n_blocks_count, 1)) {
|
|
|
err = -EINVAL;
|
|
|
goto restore_opts;
|
|
|
}
|