#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,
        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,
        {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"},
        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;
                                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;
        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;
 
        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) |
         */
        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))
        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);
 
        /*
 
        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;
 }
 
        /*
         * 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;
        }