summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/ext3.txt5
-rw-r--r--fs/ext3/super.c54
2 files changed, 49 insertions, 10 deletions
diff --git a/Documentation/filesystems/ext3.txt b/Documentation/filesystems/ext3.txt
index 9840d5b8d5b9..22e4040564d5 100644
--- a/Documentation/filesystems/ext3.txt
+++ b/Documentation/filesystems/ext3.txt
@@ -22,6 +22,11 @@ journal=inum When a journal already exists, this option is
the inode which will represent the ext3 file
system's journal file.
+journal_dev=devnum When the external journal device's major/minor numbers
+ have changed, this option allows to specify the new
+ journal location. The journal device is identified
+ through its new major/minor numbers encoded in devnum.
+
noload Don't load the journal on mounting.
data=journal All data are committed into the journal prior
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 4e6730622d90..7c45acf94589 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -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;
}