Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso...
[~shefty/rdma-dev.git] / fs / ext4 / super.c
index 933900909ed0facb352e8d2c86c19a456a4fbb49..ceebaf853beb74c7e139e63f46bf44975696566b 100644 (file)
@@ -62,6 +62,7 @@ static struct ext4_features *ext4_feat;
 
 static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
                             unsigned long journal_devnum);
+static int ext4_show_options(struct seq_file *seq, struct dentry *root);
 static int ext4_commit_super(struct super_block *sb, int sync);
 static void ext4_mark_recovery_complete(struct super_block *sb,
                                        struct ext4_super_block *es);
@@ -375,7 +376,7 @@ void ext4_journal_abort_handle(const char *caller, unsigned int line,
        if (is_handle_aborted(handle))
                return;
 
-       printk(KERN_ERR "%s:%d: aborting transaction: %s in %s\n",
+       printk(KERN_ERR "EXT4-fs: %s:%d: aborting transaction: %s in %s\n",
               caller, line, errstr, err_fn);
 
        jbd2_journal_abort_handle(handle);
@@ -431,6 +432,22 @@ static int block_device_ejected(struct super_block *sb)
        return bdi->dev == NULL;
 }
 
+static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn)
+{
+       struct super_block              *sb = journal->j_private;
+       struct ext4_sb_info             *sbi = EXT4_SB(sb);
+       int                             error = is_journal_aborted(journal);
+       struct ext4_journal_cb_entry    *jce, *tmp;
+
+       spin_lock(&sbi->s_md_lock);
+       list_for_each_entry_safe(jce, tmp, &txn->t_private_list, jce_list) {
+               list_del_init(&jce->jce_list);
+               spin_unlock(&sbi->s_md_lock);
+               jce->jce_func(sb, jce, error);
+               spin_lock(&sbi->s_md_lock);
+       }
+       spin_unlock(&sbi->s_md_lock);
+}
 
 /* Deal with the reporting of failure conditions on a filesystem such as
  * inconsistencies detected or read IO failures.
@@ -498,11 +515,16 @@ void ext4_error_inode(struct inode *inode, const char *function,
        va_start(args, fmt);
        vaf.fmt = fmt;
        vaf.va = &args;
-       printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: inode #%lu: ",
-              inode->i_sb->s_id, function, line, inode->i_ino);
        if (block)
-               printk(KERN_CONT "block %llu: ", block);
-       printk(KERN_CONT "comm %s: %pV\n", current->comm, &vaf);
+               printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: "
+                      "inode #%lu: block %llu: comm %s: %pV\n",
+                      inode->i_sb->s_id, function, line, inode->i_ino,
+                      block, current->comm, &vaf);
+       else
+               printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: "
+                      "inode #%lu: comm %s: %pV\n",
+                      inode->i_sb->s_id, function, line, inode->i_ino,
+                      current->comm, &vaf);
        va_end(args);
 
        ext4_handle_error(inode->i_sb);
@@ -524,15 +546,21 @@ void ext4_error_file(struct file *file, const char *function,
        path = d_path(&(file->f_path), pathname, sizeof(pathname));
        if (IS_ERR(path))
                path = "(unknown)";
-       printk(KERN_CRIT
-              "EXT4-fs error (device %s): %s:%d: inode #%lu: ",
-              inode->i_sb->s_id, function, line, inode->i_ino);
-       if (block)
-               printk(KERN_CONT "block %llu: ", block);
        va_start(args, fmt);
        vaf.fmt = fmt;
        vaf.va = &args;
-       printk(KERN_CONT "comm %s: path %s: %pV\n", current->comm, path, &vaf);
+       if (block)
+               printk(KERN_CRIT
+                      "EXT4-fs error (device %s): %s:%d: inode #%lu: "
+                      "block %llu: comm %s: path %s: %pV\n",
+                      inode->i_sb->s_id, function, line, inode->i_ino,
+                      block, current->comm, path, &vaf);
+       else
+               printk(KERN_CRIT
+                      "EXT4-fs error (device %s): %s:%d: inode #%lu: "
+                      "comm %s: path %s: %pV\n",
+                      inode->i_sb->s_id, function, line, inode->i_ino,
+                      current->comm, path, &vaf);
        va_end(args);
 
        ext4_handle_error(inode->i_sb);
@@ -808,9 +836,6 @@ static void ext4_put_super(struct super_block *sb)
        destroy_workqueue(sbi->dio_unwritten_wq);
 
        lock_super(sb);
-       if (sb->s_dirt)
-               ext4_commit_super(sb, 1);
-
        if (sbi->s_journal) {
                err = jbd2_journal_destroy(sbi->s_journal);
                sbi->s_journal = NULL;
@@ -827,9 +852,12 @@ static void ext4_put_super(struct super_block *sb)
        if (!(sb->s_flags & MS_RDONLY)) {
                EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
                es->s_state = cpu_to_le16(sbi->s_mount_state);
-               ext4_commit_super(sb, 1);
        }
+       if (sb->s_dirt || !(sb->s_flags & MS_RDONLY))
+               ext4_commit_super(sb, 1);
+
        if (sbi->s_proc) {
+               remove_proc_entry("options", sbi->s_proc);
                remove_proc_entry(sb->s_id, ext4_proc_root);
        }
        kobject_del(&sbi->s_kobj);
@@ -990,180 +1018,6 @@ void ext4_clear_inode(struct inode *inode)
        }
 }
 
-static inline void ext4_show_quota_options(struct seq_file *seq,
-                                          struct super_block *sb)
-{
-#if defined(CONFIG_QUOTA)
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
-
-       if (sbi->s_jquota_fmt) {
-               char *fmtname = "";
-
-               switch (sbi->s_jquota_fmt) {
-               case QFMT_VFS_OLD:
-                       fmtname = "vfsold";
-                       break;
-               case QFMT_VFS_V0:
-                       fmtname = "vfsv0";
-                       break;
-               case QFMT_VFS_V1:
-                       fmtname = "vfsv1";
-                       break;
-               }
-               seq_printf(seq, ",jqfmt=%s", fmtname);
-       }
-
-       if (sbi->s_qf_names[USRQUOTA])
-               seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]);
-
-       if (sbi->s_qf_names[GRPQUOTA])
-               seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]);
-
-       if (test_opt(sb, USRQUOTA))
-               seq_puts(seq, ",usrquota");
-
-       if (test_opt(sb, GRPQUOTA))
-               seq_puts(seq, ",grpquota");
-#endif
-}
-
-/*
- * Show an option if
- *  - it's set to a non-default value OR
- *  - if the per-sb default is different from the global default
- */
-static int ext4_show_options(struct seq_file *seq, struct dentry *root)
-{
-       int def_errors;
-       unsigned long def_mount_opts;
-       struct super_block *sb = root->d_sb;
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
-       struct ext4_super_block *es = sbi->s_es;
-
-       def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
-       def_errors     = le16_to_cpu(es->s_errors);
-
-       if (sbi->s_sb_block != 1)
-               seq_printf(seq, ",sb=%llu", sbi->s_sb_block);
-       if (test_opt(sb, MINIX_DF))
-               seq_puts(seq, ",minixdf");
-       if (test_opt(sb, GRPID) && !(def_mount_opts & EXT4_DEFM_BSDGROUPS))
-               seq_puts(seq, ",grpid");
-       if (!test_opt(sb, GRPID) && (def_mount_opts & EXT4_DEFM_BSDGROUPS))
-               seq_puts(seq, ",nogrpid");
-       if (sbi->s_resuid != EXT4_DEF_RESUID ||
-           le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID) {
-               seq_printf(seq, ",resuid=%u", sbi->s_resuid);
-       }
-       if (sbi->s_resgid != EXT4_DEF_RESGID ||
-           le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID) {
-               seq_printf(seq, ",resgid=%u", sbi->s_resgid);
-       }
-       if (test_opt(sb, ERRORS_RO)) {
-               if (def_errors == EXT4_ERRORS_PANIC ||
-                   def_errors == EXT4_ERRORS_CONTINUE) {
-                       seq_puts(seq, ",errors=remount-ro");
-               }
-       }
-       if (test_opt(sb, ERRORS_CONT) && def_errors != EXT4_ERRORS_CONTINUE)
-               seq_puts(seq, ",errors=continue");
-       if (test_opt(sb, ERRORS_PANIC) && def_errors != EXT4_ERRORS_PANIC)
-               seq_puts(seq, ",errors=panic");
-       if (test_opt(sb, NO_UID32) && !(def_mount_opts & EXT4_DEFM_UID16))
-               seq_puts(seq, ",nouid32");
-       if (test_opt(sb, DEBUG) && !(def_mount_opts & EXT4_DEFM_DEBUG))
-               seq_puts(seq, ",debug");
-#ifdef CONFIG_EXT4_FS_XATTR
-       if (test_opt(sb, XATTR_USER))
-               seq_puts(seq, ",user_xattr");
-       if (!test_opt(sb, XATTR_USER))
-               seq_puts(seq, ",nouser_xattr");
-#endif
-#ifdef CONFIG_EXT4_FS_POSIX_ACL
-       if (test_opt(sb, POSIX_ACL) && !(def_mount_opts & EXT4_DEFM_ACL))
-               seq_puts(seq, ",acl");
-       if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT4_DEFM_ACL))
-               seq_puts(seq, ",noacl");
-#endif
-       if (sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) {
-               seq_printf(seq, ",commit=%u",
-                          (unsigned) (sbi->s_commit_interval / HZ));
-       }
-       if (sbi->s_min_batch_time != EXT4_DEF_MIN_BATCH_TIME) {
-               seq_printf(seq, ",min_batch_time=%u",
-                          (unsigned) sbi->s_min_batch_time);
-       }
-       if (sbi->s_max_batch_time != EXT4_DEF_MAX_BATCH_TIME) {
-               seq_printf(seq, ",max_batch_time=%u",
-                          (unsigned) sbi->s_max_batch_time);
-       }
-
-       /*
-        * We're changing the default of barrier mount option, so
-        * let's always display its mount state so it's clear what its
-        * status is.
-        */
-       seq_puts(seq, ",barrier=");
-       seq_puts(seq, test_opt(sb, BARRIER) ? "1" : "0");
-       if (test_opt(sb, JOURNAL_ASYNC_COMMIT))
-               seq_puts(seq, ",journal_async_commit");
-       else if (test_opt(sb, JOURNAL_CHECKSUM))
-               seq_puts(seq, ",journal_checksum");
-       if (test_opt(sb, I_VERSION))
-               seq_puts(seq, ",i_version");
-       if (!test_opt(sb, DELALLOC) &&
-           !(def_mount_opts & EXT4_DEFM_NODELALLOC))
-               seq_puts(seq, ",nodelalloc");
-
-       if (!test_opt(sb, MBLK_IO_SUBMIT))
-               seq_puts(seq, ",nomblk_io_submit");
-       if (sbi->s_stripe)
-               seq_printf(seq, ",stripe=%lu", sbi->s_stripe);
-       /*
-        * journal mode get enabled in different ways
-        * So just print the value even if we didn't specify it
-        */
-       if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
-               seq_puts(seq, ",data=journal");
-       else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
-               seq_puts(seq, ",data=ordered");
-       else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
-               seq_puts(seq, ",data=writeback");
-
-       if (sbi->s_inode_readahead_blks != EXT4_DEF_INODE_READAHEAD_BLKS)
-               seq_printf(seq, ",inode_readahead_blks=%u",
-                          sbi->s_inode_readahead_blks);
-
-       if (test_opt(sb, DATA_ERR_ABORT))
-               seq_puts(seq, ",data_err=abort");
-
-       if (test_opt(sb, NO_AUTO_DA_ALLOC))
-               seq_puts(seq, ",noauto_da_alloc");
-
-       if (test_opt(sb, DISCARD) && !(def_mount_opts & EXT4_DEFM_DISCARD))
-               seq_puts(seq, ",discard");
-
-       if (test_opt(sb, NOLOAD))
-               seq_puts(seq, ",norecovery");
-
-       if (test_opt(sb, DIOREAD_NOLOCK))
-               seq_puts(seq, ",dioread_nolock");
-
-       if (test_opt(sb, BLOCK_VALIDITY) &&
-           !(def_mount_opts & EXT4_DEFM_BLOCK_VALIDITY))
-               seq_puts(seq, ",block_validity");
-
-       if (!test_opt(sb, INIT_INODE_TABLE))
-               seq_puts(seq, ",noinit_itable");
-       else if (sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT)
-               seq_printf(seq, ",init_itable=%u",
-                          (unsigned) sbi->s_li_wait_mult);
-
-       ext4_show_quota_options(seq, sb);
-
-       return 0;
-}
-
 static struct inode *ext4_nfs_get_inode(struct super_block *sb,
                                        u64 ino, u32 generation)
 {
@@ -1316,18 +1170,17 @@ static const struct export_operations ext4_export_ops = {
 enum {
        Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
        Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
-       Opt_nouid32, Opt_debug, Opt_oldalloc, Opt_orlov,
+       Opt_nouid32, Opt_debug, Opt_removed,
        Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
-       Opt_auto_da_alloc, Opt_noauto_da_alloc, Opt_noload, Opt_nobh, Opt_bh,
+       Opt_auto_da_alloc, Opt_noauto_da_alloc, Opt_noload,
        Opt_commit, Opt_min_batch_time, Opt_max_batch_time,
-       Opt_journal_update, Opt_journal_dev,
-       Opt_journal_checksum, Opt_journal_async_commit,
+       Opt_journal_dev, Opt_journal_checksum, Opt_journal_async_commit,
        Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
        Opt_data_err_abort, Opt_data_err_ignore,
        Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
        Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
-       Opt_noquota, Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err,
-       Opt_resize, Opt_usrquota, Opt_grpquota, Opt_i_version,
+       Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err,
+       Opt_usrquota, Opt_grpquota, Opt_i_version,
        Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_mblk_io_submit,
        Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity,
        Opt_inode_readahead_blks, Opt_journal_ioprio,
@@ -1350,20 +1203,19 @@ static const match_table_t tokens = {
        {Opt_err_ro, "errors=remount-ro"},
        {Opt_nouid32, "nouid32"},
        {Opt_debug, "debug"},
-       {Opt_oldalloc, "oldalloc"},
-       {Opt_orlov, "orlov"},
+       {Opt_removed, "oldalloc"},
+       {Opt_removed, "orlov"},
        {Opt_user_xattr, "user_xattr"},
        {Opt_nouser_xattr, "nouser_xattr"},
        {Opt_acl, "acl"},
        {Opt_noacl, "noacl"},
-       {Opt_noload, "noload"},
        {Opt_noload, "norecovery"},
-       {Opt_nobh, "nobh"},
-       {Opt_bh, "bh"},
+       {Opt_noload, "noload"},
+       {Opt_removed, "nobh"},
+       {Opt_removed, "bh"},
        {Opt_commit, "commit=%u"},
        {Opt_min_batch_time, "min_batch_time=%u"},
        {Opt_max_batch_time, "max_batch_time=%u"},
-       {Opt_journal_update, "journal=update"},
        {Opt_journal_dev, "journal_dev=%u"},
        {Opt_journal_checksum, "journal_checksum"},
        {Opt_journal_async_commit, "journal_async_commit"},
@@ -1389,7 +1241,6 @@ static const match_table_t tokens = {
        {Opt_nobarrier, "nobarrier"},
        {Opt_i_version, "i_version"},
        {Opt_stripe, "stripe=%u"},
-       {Opt_resize, "resize"},
        {Opt_delalloc, "delalloc"},
        {Opt_nodelalloc, "nodelalloc"},
        {Opt_mblk_io_submit, "mblk_io_submit"},
@@ -1408,6 +1259,11 @@ static const match_table_t tokens = {
        {Opt_init_itable, "init_itable=%u"},
        {Opt_init_itable, "init_itable"},
        {Opt_noinit_itable, "noinit_itable"},
+       {Opt_removed, "check=none"},    /* mount option from ext2/3 */
+       {Opt_removed, "nocheck"},       /* mount option from ext2/3 */
+       {Opt_removed, "reservation"},   /* mount option from ext2/3 */
+       {Opt_removed, "noreservation"}, /* mount option from ext2/3 */
+       {Opt_removed, "journal=%u"},    /* mount option from ext2/3 */
        {Opt_err, NULL},
 };
 
@@ -1496,420 +1352,273 @@ static int clear_qf_name(struct super_block *sb, int qtype)
 }
 #endif
 
-static int parse_options(char *options, struct super_block *sb,
-                        unsigned long *journal_devnum,
-                        unsigned int *journal_ioprio,
-                        ext4_fsblk_t *n_blocks_count, int is_remount)
-{
-       struct ext4_sb_info *sbi = EXT4_SB(sb);
-       char *p;
-       substring_t args[MAX_OPT_ARGS];
-       int data_opt = 0;
-       int option;
+#define MOPT_SET       0x0001
+#define MOPT_CLEAR     0x0002
+#define MOPT_NOSUPPORT 0x0004
+#define MOPT_EXPLICIT  0x0008
+#define MOPT_CLEAR_ERR 0x0010
+#define MOPT_GTE0      0x0020
 #ifdef CONFIG_QUOTA
-       int qfmt;
+#define MOPT_Q         0
+#define MOPT_QFMT      0x0040
+#else
+#define MOPT_Q         MOPT_NOSUPPORT
+#define MOPT_QFMT      MOPT_NOSUPPORT
 #endif
-
-       if (!options)
-               return 1;
-
-       while ((p = strsep(&options, ",")) != NULL) {
-               int token;
-               if (!*p)
-                       continue;
-
-               /*
-                * Initialize args struct so we know whether arg was
-                * found; some options take optional arguments.
-                */
-               args[0].to = args[0].from = NULL;
-               token = match_token(p, tokens, args);
-               switch (token) {
-               case Opt_bsd_df:
-                       ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38");
-                       clear_opt(sb, MINIX_DF);
-                       break;
-               case Opt_minix_df:
-                       ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38");
-                       set_opt(sb, MINIX_DF);
-
-                       break;
-               case Opt_grpid:
-                       ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38");
-                       set_opt(sb, GRPID);
-
-                       break;
-               case Opt_nogrpid:
-                       ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38");
-                       clear_opt(sb, GRPID);
-
-                       break;
-               case Opt_resuid:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       sbi->s_resuid = option;
-                       break;
-               case Opt_resgid:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       sbi->s_resgid = option;
-                       break;
-               case Opt_sb:
-                       /* handled by get_sb_block() instead of here */
-                       /* *sb_block = match_int(&args[0]); */
-                       break;
-               case Opt_err_panic:
-                       clear_opt(sb, ERRORS_CONT);
-                       clear_opt(sb, ERRORS_RO);
-                       set_opt(sb, ERRORS_PANIC);
-                       break;
-               case Opt_err_ro:
-                       clear_opt(sb, ERRORS_CONT);
-                       clear_opt(sb, ERRORS_PANIC);
-                       set_opt(sb, ERRORS_RO);
-                       break;
-               case Opt_err_cont:
-                       clear_opt(sb, ERRORS_RO);
-                       clear_opt(sb, ERRORS_PANIC);
-                       set_opt(sb, ERRORS_CONT);
-                       break;
-               case Opt_nouid32:
-                       set_opt(sb, NO_UID32);
-                       break;
-               case Opt_debug:
-                       set_opt(sb, DEBUG);
-                       break;
-               case Opt_oldalloc:
-                       ext4_msg(sb, KERN_WARNING,
-                                "Ignoring deprecated oldalloc option");
-                       break;
-               case Opt_orlov:
-                       ext4_msg(sb, KERN_WARNING,
-                                "Ignoring deprecated orlov option");
-                       break;
+#define MOPT_DATAJ     0x0080
+
+static const struct mount_opts {
+       int     token;
+       int     mount_opt;
+       int     flags;
+} ext4_mount_opts[] = {
+       {Opt_minix_df, EXT4_MOUNT_MINIX_DF, MOPT_SET},
+       {Opt_bsd_df, EXT4_MOUNT_MINIX_DF, MOPT_CLEAR},
+       {Opt_grpid, EXT4_MOUNT_GRPID, MOPT_SET},
+       {Opt_nogrpid, EXT4_MOUNT_GRPID, MOPT_CLEAR},
+       {Opt_mblk_io_submit, EXT4_MOUNT_MBLK_IO_SUBMIT, MOPT_SET},
+       {Opt_nomblk_io_submit, EXT4_MOUNT_MBLK_IO_SUBMIT, MOPT_CLEAR},
+       {Opt_block_validity, EXT4_MOUNT_BLOCK_VALIDITY, MOPT_SET},
+       {Opt_noblock_validity, EXT4_MOUNT_BLOCK_VALIDITY, MOPT_CLEAR},
+       {Opt_dioread_nolock, EXT4_MOUNT_DIOREAD_NOLOCK, MOPT_SET},
+       {Opt_dioread_lock, EXT4_MOUNT_DIOREAD_NOLOCK, MOPT_CLEAR},
+       {Opt_discard, EXT4_MOUNT_DISCARD, MOPT_SET},
+       {Opt_nodiscard, EXT4_MOUNT_DISCARD, MOPT_CLEAR},
+       {Opt_delalloc, EXT4_MOUNT_DELALLOC, MOPT_SET | MOPT_EXPLICIT},
+       {Opt_nodelalloc, EXT4_MOUNT_DELALLOC, MOPT_CLEAR | MOPT_EXPLICIT},
+       {Opt_journal_checksum, EXT4_MOUNT_JOURNAL_CHECKSUM, MOPT_SET},
+       {Opt_journal_async_commit, (EXT4_MOUNT_JOURNAL_ASYNC_COMMIT |
+                                   EXT4_MOUNT_JOURNAL_CHECKSUM), MOPT_SET},
+       {Opt_noload, EXT4_MOUNT_NOLOAD, MOPT_SET},
+       {Opt_err_panic, EXT4_MOUNT_ERRORS_PANIC, MOPT_SET | MOPT_CLEAR_ERR},
+       {Opt_err_ro, EXT4_MOUNT_ERRORS_RO, MOPT_SET | MOPT_CLEAR_ERR},
+       {Opt_err_cont, EXT4_MOUNT_ERRORS_CONT, MOPT_SET | MOPT_CLEAR_ERR},
+       {Opt_data_err_abort, EXT4_MOUNT_DATA_ERR_ABORT, MOPT_SET},
+       {Opt_data_err_ignore, EXT4_MOUNT_DATA_ERR_ABORT, MOPT_CLEAR},
+       {Opt_barrier, EXT4_MOUNT_BARRIER, MOPT_SET},
+       {Opt_nobarrier, EXT4_MOUNT_BARRIER, MOPT_CLEAR},
+       {Opt_noauto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_SET},
+       {Opt_auto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_CLEAR},
+       {Opt_noinit_itable, EXT4_MOUNT_INIT_INODE_TABLE, MOPT_CLEAR},
+       {Opt_commit, 0, MOPT_GTE0},
+       {Opt_max_batch_time, 0, MOPT_GTE0},
+       {Opt_min_batch_time, 0, MOPT_GTE0},
+       {Opt_inode_readahead_blks, 0, MOPT_GTE0},
+       {Opt_init_itable, 0, MOPT_GTE0},
+       {Opt_stripe, 0, MOPT_GTE0},
+       {Opt_data_journal, EXT4_MOUNT_JOURNAL_DATA, MOPT_DATAJ},
+       {Opt_data_ordered, EXT4_MOUNT_ORDERED_DATA, MOPT_DATAJ},
+       {Opt_data_writeback, EXT4_MOUNT_WRITEBACK_DATA, MOPT_DATAJ},
 #ifdef CONFIG_EXT4_FS_XATTR
-               case Opt_user_xattr:
-                       set_opt(sb, XATTR_USER);
-                       break;
-               case Opt_nouser_xattr:
-                       clear_opt(sb, XATTR_USER);
-                       break;
+       {Opt_user_xattr, EXT4_MOUNT_XATTR_USER, MOPT_SET},
+       {Opt_nouser_xattr, EXT4_MOUNT_XATTR_USER, MOPT_CLEAR},
 #else
-               case Opt_user_xattr:
-               case Opt_nouser_xattr:
-                       ext4_msg(sb, KERN_ERR, "(no)user_xattr options not supported");
-                       break;
+       {Opt_user_xattr, 0, MOPT_NOSUPPORT},
+       {Opt_nouser_xattr, 0, MOPT_NOSUPPORT},
 #endif
 #ifdef CONFIG_EXT4_FS_POSIX_ACL
-               case Opt_acl:
-                       set_opt(sb, POSIX_ACL);
-                       break;
-               case Opt_noacl:
-                       clear_opt(sb, POSIX_ACL);
-                       break;
+       {Opt_acl, EXT4_MOUNT_POSIX_ACL, MOPT_SET},
+       {Opt_noacl, EXT4_MOUNT_POSIX_ACL, MOPT_CLEAR},
 #else
-               case Opt_acl:
-               case Opt_noacl:
-                       ext4_msg(sb, KERN_ERR, "(no)acl options not supported");
-                       break;
+       {Opt_acl, 0, MOPT_NOSUPPORT},
+       {Opt_noacl, 0, MOPT_NOSUPPORT},
 #endif
-               case Opt_journal_update:
-                       /* @@@ FIXME */
-                       /* Eventually we will want to be able to create
-                          a journal file here.  For now, only allow the
-                          user to specify an existing inode to be the
-                          journal file. */
-                       if (is_remount) {
-                               ext4_msg(sb, KERN_ERR,
-                                        "Cannot specify journal on remount");
-                               return 0;
-                       }
-                       set_opt(sb, UPDATE_JOURNAL);
-                       break;
-               case Opt_journal_dev:
-                       if (is_remount) {
+       {Opt_nouid32, EXT4_MOUNT_NO_UID32, MOPT_SET},
+       {Opt_debug, EXT4_MOUNT_DEBUG, MOPT_SET},
+       {Opt_quota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA, MOPT_SET | MOPT_Q},
+       {Opt_usrquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA,
+                                                       MOPT_SET | MOPT_Q},
+       {Opt_grpquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_GRPQUOTA,
+                                                       MOPT_SET | MOPT_Q},
+       {Opt_noquota, (EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA |
+                      EXT4_MOUNT_GRPQUOTA), MOPT_CLEAR | MOPT_Q},
+       {Opt_usrjquota, 0, MOPT_Q},
+       {Opt_grpjquota, 0, MOPT_Q},
+       {Opt_offusrjquota, 0, MOPT_Q},
+       {Opt_offgrpjquota, 0, MOPT_Q},
+       {Opt_jqfmt_vfsold, QFMT_VFS_OLD, MOPT_QFMT},
+       {Opt_jqfmt_vfsv0, QFMT_VFS_V0, MOPT_QFMT},
+       {Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT},
+       {Opt_err, 0, 0}
+};
+
+static int handle_mount_opt(struct super_block *sb, char *opt, int token,
+                           substring_t *args, unsigned long *journal_devnum,
+                           unsigned int *journal_ioprio, int is_remount)
+{
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       const struct mount_opts *m;
+       int arg = 0;
+
+       if (args->from && match_int(args, &arg))
+               return -1;
+       switch (token) {
+       case Opt_noacl:
+       case Opt_nouser_xattr:
+               ext4_msg(sb, KERN_WARNING, deprecated_msg, opt, "3.5");
+               break;
+       case Opt_sb:
+               return 1;       /* handled by get_sb_block() */
+       case Opt_removed:
+               ext4_msg(sb, KERN_WARNING,
+                        "Ignoring removed %s option", opt);
+               return 1;
+       case Opt_resuid:
+               sbi->s_resuid = arg;
+               return 1;
+       case Opt_resgid:
+               sbi->s_resgid = arg;
+               return 1;
+       case Opt_abort:
+               sbi->s_mount_flags |= EXT4_MF_FS_ABORTED;
+               return 1;
+       case Opt_i_version:
+               sb->s_flags |= MS_I_VERSION;
+               return 1;
+       case Opt_journal_dev:
+               if (is_remount) {
+                       ext4_msg(sb, KERN_ERR,
+                                "Cannot specify journal on remount");
+                       return -1;
+               }
+               *journal_devnum = arg;
+               return 1;
+       case Opt_journal_ioprio:
+               if (arg < 0 || arg > 7)
+                       return -1;
+               *journal_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, arg);
+               return 1;
+       }
+
+       for (m = ext4_mount_opts; m->token != Opt_err; m++) {
+               if (token != m->token)
+                       continue;
+               if (args->from && (m->flags & MOPT_GTE0) && (arg < 0))
+                       return -1;
+               if (m->flags & MOPT_EXPLICIT)
+                       set_opt2(sb, EXPLICIT_DELALLOC);
+               if (m->flags & MOPT_CLEAR_ERR)
+                       clear_opt(sb, ERRORS_MASK);
+               if (token == Opt_noquota && sb_any_quota_loaded(sb)) {
+                       ext4_msg(sb, KERN_ERR, "Cannot change quota "
+                                "options when quota turned on");
+                       return -1;
+               }
+
+               if (m->flags & MOPT_NOSUPPORT) {
+                       ext4_msg(sb, KERN_ERR, "%s option not supported", opt);
+               } else if (token == Opt_commit) {
+                       if (arg == 0)
+                               arg = JBD2_DEFAULT_MAX_COMMIT_AGE;
+                       sbi->s_commit_interval = HZ * arg;
+               } else if (token == Opt_max_batch_time) {
+                       if (arg == 0)
+                               arg = EXT4_DEF_MAX_BATCH_TIME;
+                       sbi->s_max_batch_time = arg;
+               } else if (token == Opt_min_batch_time) {
+                       sbi->s_min_batch_time = arg;
+               } else if (token == Opt_inode_readahead_blks) {
+                       if (arg > (1 << 30))
+                               return -1;
+                       if (arg && !is_power_of_2(arg)) {
                                ext4_msg(sb, KERN_ERR,
-                                       "Cannot specify journal on remount");
-                               return 0;
+                                        "EXT4-fs: inode_readahead_blks"
+                                        " must be a power of 2");
+                               return -1;
                        }
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       *journal_devnum = option;
-                       break;
-               case Opt_journal_checksum:
-                       set_opt(sb, JOURNAL_CHECKSUM);
-                       break;
-               case Opt_journal_async_commit:
-                       set_opt(sb, JOURNAL_ASYNC_COMMIT);
-                       set_opt(sb, JOURNAL_CHECKSUM);
-                       break;
-               case Opt_noload:
-                       set_opt(sb, NOLOAD);
-                       break;
-               case Opt_commit:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       if (option < 0)
-                               return 0;
-                       if (option == 0)
-                               option = JBD2_DEFAULT_MAX_COMMIT_AGE;
-                       sbi->s_commit_interval = HZ * option;
-                       break;
-               case Opt_max_batch_time:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       if (option < 0)
-                               return 0;
-                       if (option == 0)
-                               option = EXT4_DEF_MAX_BATCH_TIME;
-                       sbi->s_max_batch_time = option;
-                       break;
-               case Opt_min_batch_time:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       if (option < 0)
-                               return 0;
-                       sbi->s_min_batch_time = option;
-                       break;
-               case Opt_data_journal:
-                       data_opt = EXT4_MOUNT_JOURNAL_DATA;
-                       goto datacheck;
-               case Opt_data_ordered:
-                       data_opt = EXT4_MOUNT_ORDERED_DATA;
-                       goto datacheck;
-               case Opt_data_writeback:
-                       data_opt = EXT4_MOUNT_WRITEBACK_DATA;
-               datacheck:
+                       sbi->s_inode_readahead_blks = arg;
+               } else if (token == Opt_init_itable) {
+                       set_opt(sb, INIT_INODE_TABLE);
+                       if (!args->from)
+                               arg = EXT4_DEF_LI_WAIT_MULT;
+                       sbi->s_li_wait_mult = arg;
+               } else if (token == Opt_stripe) {
+                       sbi->s_stripe = arg;
+               } else if (m->flags & MOPT_DATAJ) {
                        if (is_remount) {
                                if (!sbi->s_journal)
                                        ext4_msg(sb, KERN_WARNING, "Remounting file system with no journal so ignoring journalled data option");
-                               else if (test_opt(sb, DATA_FLAGS) != data_opt) {
+                               else if (test_opt(sb, DATA_FLAGS) !=
+                                        m->mount_opt) {
                                        ext4_msg(sb, KERN_ERR,
-                                               "Cannot change data mode on remount");
-                                       return 0;
+                                        "Cannot change data mode on remount");
+                                       return -1;
                                }
                        } else {
                                clear_opt(sb, DATA_FLAGS);
-                               sbi->s_mount_opt |= data_opt;
+                               sbi->s_mount_opt |= m->mount_opt;
                        }
-                       break;
-               case Opt_data_err_abort:
-                       set_opt(sb, DATA_ERR_ABORT);
-                       break;
-               case Opt_data_err_ignore:
-                       clear_opt(sb, DATA_ERR_ABORT);
-                       break;
 #ifdef CONFIG_QUOTA
-               case Opt_usrjquota:
+               } else if (token == Opt_usrjquota) {
                        if (!set_qf_name(sb, USRQUOTA, &args[0]))
-                               return 0;
-                       break;
-               case Opt_grpjquota:
+                               return -1;
+               } else if (token == Opt_grpjquota) {
                        if (!set_qf_name(sb, GRPQUOTA, &args[0]))
-                               return 0;
-                       break;
-               case Opt_offusrjquota:
+                               return -1;
+               } else if (token == Opt_offusrjquota) {
                        if (!clear_qf_name(sb, USRQUOTA))
-                               return 0;
-                       break;
-               case Opt_offgrpjquota:
+                               return -1;
+               } else if (token == Opt_offgrpjquota) {
                        if (!clear_qf_name(sb, GRPQUOTA))
-                               return 0;
-                       break;
-
-               case Opt_jqfmt_vfsold:
-                       qfmt = QFMT_VFS_OLD;
-                       goto set_qf_format;
-               case Opt_jqfmt_vfsv0:
-                       qfmt = QFMT_VFS_V0;
-                       goto set_qf_format;
-               case Opt_jqfmt_vfsv1:
-                       qfmt = QFMT_VFS_V1;
-set_qf_format:
+                               return -1;
+               } else if (m->flags & MOPT_QFMT) {
                        if (sb_any_quota_loaded(sb) &&
-                           sbi->s_jquota_fmt != qfmt) {
-                               ext4_msg(sb, KERN_ERR, "Cannot change "
-                                       "journaled quota options when "
-                                       "quota turned on");
-                               return 0;
-                       }
-                       sbi->s_jquota_fmt = qfmt;
-                       break;
-               case Opt_quota:
-               case Opt_usrquota:
-                       set_opt(sb, QUOTA);
-                       set_opt(sb, USRQUOTA);
-                       break;
-               case Opt_grpquota:
-                       set_opt(sb, QUOTA);
-                       set_opt(sb, GRPQUOTA);
-                       break;
-               case Opt_noquota:
-                       if (sb_any_quota_loaded(sb)) {
-                               ext4_msg(sb, KERN_ERR, "Cannot change quota "
-                                       "options when quota turned on");
-                               return 0;
+                           sbi->s_jquota_fmt != m->mount_opt) {
+                               ext4_msg(sb, KERN_ERR, "Cannot "
+                                        "change journaled quota options "
+                                        "when quota turned on");
+                               return -1;
                        }
-                       clear_opt(sb, QUOTA);
-                       clear_opt(sb, USRQUOTA);
-                       clear_opt(sb, GRPQUOTA);
-                       break;
-#else
-               case Opt_quota:
-               case Opt_usrquota:
-               case Opt_grpquota:
-                       ext4_msg(sb, KERN_ERR,
-                               "quota options not supported");
-                       break;
-               case Opt_usrjquota:
-               case Opt_grpjquota:
-               case Opt_offusrjquota:
-               case Opt_offgrpjquota:
-               case Opt_jqfmt_vfsold:
-               case Opt_jqfmt_vfsv0:
-               case Opt_jqfmt_vfsv1:
-                       ext4_msg(sb, KERN_ERR,
-                               "journaled quota options not supported");
-                       break;
-               case Opt_noquota:
-                       break;
+                       sbi->s_jquota_fmt = m->mount_opt;
 #endif
-               case Opt_abort:
-                       sbi->s_mount_flags |= EXT4_MF_FS_ABORTED;
-                       break;
-               case Opt_nobarrier:
-                       clear_opt(sb, BARRIER);
-                       break;
-               case Opt_barrier:
-                       if (args[0].from) {
-                               if (match_int(&args[0], &option))
-                                       return 0;
-                       } else
-                               option = 1;     /* No argument, default to 1 */
-                       if (option)
-                               set_opt(sb, BARRIER);
-                       else
-                               clear_opt(sb, BARRIER);
-                       break;
-               case Opt_ignore:
-                       break;
-               case Opt_resize:
-                       if (!is_remount) {
-                               ext4_msg(sb, KERN_ERR,
-                                       "resize option only available "
-                                       "for remount");
-                               return 0;
-                       }
-                       if (match_int(&args[0], &option) != 0)
-                               return 0;
-                       *n_blocks_count = option;
-                       break;
-               case Opt_nobh:
-                       ext4_msg(sb, KERN_WARNING,
-                                "Ignoring deprecated nobh option");
-                       break;
-               case Opt_bh:
-                       ext4_msg(sb, KERN_WARNING,
-                                "Ignoring deprecated bh option");
-                       break;
-               case Opt_i_version:
-                       set_opt(sb, I_VERSION);
-                       sb->s_flags |= MS_I_VERSION;
-                       break;
-               case Opt_nodelalloc:
-                       clear_opt(sb, DELALLOC);
-                       clear_opt2(sb, EXPLICIT_DELALLOC);
-                       break;
-               case Opt_mblk_io_submit:
-                       set_opt(sb, MBLK_IO_SUBMIT);
-                       break;
-               case Opt_nomblk_io_submit:
-                       clear_opt(sb, MBLK_IO_SUBMIT);
-                       break;
-               case Opt_stripe:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       if (option < 0)
-                               return 0;
-                       sbi->s_stripe = option;
-                       break;
-               case Opt_delalloc:
-                       set_opt(sb, DELALLOC);
-                       set_opt2(sb, EXPLICIT_DELALLOC);
-                       break;
-               case Opt_block_validity:
-                       set_opt(sb, BLOCK_VALIDITY);
-                       break;
-               case Opt_noblock_validity:
-                       clear_opt(sb, BLOCK_VALIDITY);
-                       break;
-               case Opt_inode_readahead_blks:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       if (option < 0 || option > (1 << 30))
-                               return 0;
-                       if (option && !is_power_of_2(option)) {
-                               ext4_msg(sb, KERN_ERR,
-                                        "EXT4-fs: inode_readahead_blks"
-                                        " must be a power of 2");
-                               return 0;
+               } else {
+                       if (!args->from)
+                               arg = 1;
+                       if (m->flags & MOPT_CLEAR)
+                               arg = !arg;
+                       else if (unlikely(!(m->flags & MOPT_SET))) {
+                               ext4_msg(sb, KERN_WARNING,
+                                        "buggy handling of option %s", opt);
+                               WARN_ON(1);
+                               return -1;
                        }
-                       sbi->s_inode_readahead_blks = option;
-                       break;
-               case Opt_journal_ioprio:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       if (option < 0 || option > 7)
-                               break;
-                       *journal_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE,
-                                                           option);
-                       break;
-               case Opt_noauto_da_alloc:
-                       set_opt(sb, NO_AUTO_DA_ALLOC);
-                       break;
-               case Opt_auto_da_alloc:
-                       if (args[0].from) {
-                               if (match_int(&args[0], &option))
-                                       return 0;
-                       } else
-                               option = 1;     /* No argument, default to 1 */
-                       if (option)
-                               clear_opt(sb, NO_AUTO_DA_ALLOC);
+                       if (arg != 0)
+                               sbi->s_mount_opt |= m->mount_opt;
                        else
-                               set_opt(sb,NO_AUTO_DA_ALLOC);
-                       break;
-               case Opt_discard:
-                       set_opt(sb, DISCARD);
-                       break;
-               case Opt_nodiscard:
-                       clear_opt(sb, DISCARD);
-                       break;
-               case Opt_dioread_nolock:
-                       set_opt(sb, DIOREAD_NOLOCK);
-                       break;
-               case Opt_dioread_lock:
-                       clear_opt(sb, DIOREAD_NOLOCK);
-                       break;
-               case Opt_init_itable:
-                       set_opt(sb, INIT_INODE_TABLE);
-                       if (args[0].from) {
-                               if (match_int(&args[0], &option))
-                                       return 0;
-                       } else
-                               option = EXT4_DEF_LI_WAIT_MULT;
-                       if (option < 0)
-                               return 0;
-                       sbi->s_li_wait_mult = option;
-                       break;
-               case Opt_noinit_itable:
-                       clear_opt(sb, INIT_INODE_TABLE);
-                       break;
-               default:
-                       ext4_msg(sb, KERN_ERR,
-                              "Unrecognized mount option \"%s\" "
-                              "or missing value", p);
-                       return 0;
+                               sbi->s_mount_opt &= ~m->mount_opt;
                }
+               return 1;
+       }
+       ext4_msg(sb, KERN_ERR, "Unrecognized mount option \"%s\" "
+                "or missing value", opt);
+       return -1;
+}
+
+static int parse_options(char *options, struct super_block *sb,
+                        unsigned long *journal_devnum,
+                        unsigned int *journal_ioprio,
+                        int is_remount)
+{
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       char *p;
+       substring_t args[MAX_OPT_ARGS];
+       int token;
+
+       if (!options)
+               return 1;
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               if (!*p)
+                       continue;
+               /*
+                * Initialize args struct so we know whether arg was
+                * found; some options take optional arguments.
+                */
+               args[0].to = args[0].from = 0;
+               token = match_token(p, tokens, args);
+               if (handle_mount_opt(sb, p, token, args, journal_devnum,
+                                    journal_ioprio, is_remount) < 0)
+                       return 0;
        }
 #ifdef CONFIG_QUOTA
        if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
@@ -1942,6 +1651,160 @@ set_qf_format:
        return 1;
 }
 
+static inline void ext4_show_quota_options(struct seq_file *seq,
+                                          struct super_block *sb)
+{
+#if defined(CONFIG_QUOTA)
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+       if (sbi->s_jquota_fmt) {
+               char *fmtname = "";
+
+               switch (sbi->s_jquota_fmt) {
+               case QFMT_VFS_OLD:
+                       fmtname = "vfsold";
+                       break;
+               case QFMT_VFS_V0:
+                       fmtname = "vfsv0";
+                       break;
+               case QFMT_VFS_V1:
+                       fmtname = "vfsv1";
+                       break;
+               }
+               seq_printf(seq, ",jqfmt=%s", fmtname);
+       }
+
+       if (sbi->s_qf_names[USRQUOTA])
+               seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]);
+
+       if (sbi->s_qf_names[GRPQUOTA])
+               seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]);
+
+       if (test_opt(sb, USRQUOTA))
+               seq_puts(seq, ",usrquota");
+
+       if (test_opt(sb, GRPQUOTA))
+               seq_puts(seq, ",grpquota");
+#endif
+}
+
+static const char *token2str(int token)
+{
+       static const struct match_token *t;
+
+       for (t = tokens; t->token != Opt_err; t++)
+               if (t->token == token && !strchr(t->pattern, '='))
+                       break;
+       return t->pattern;
+}
+
+/*
+ * Show an option if
+ *  - it's set to a non-default value OR
+ *  - if the per-sb default is different from the global default
+ */
+static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
+                             int nodefs)
+{
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       struct ext4_super_block *es = sbi->s_es;
+       int def_errors, def_mount_opt = nodefs ? 0 : sbi->s_def_mount_opt;
+       const struct mount_opts *m;
+       char sep = nodefs ? '\n' : ',';
+
+#define SEQ_OPTS_PUTS(str) seq_printf(seq, "%c" str, sep)
+#define SEQ_OPTS_PRINT(str, arg) seq_printf(seq, "%c" str, sep, arg)
+
+       if (sbi->s_sb_block != 1)
+               SEQ_OPTS_PRINT("sb=%llu", sbi->s_sb_block);
+
+       for (m = ext4_mount_opts; m->token != Opt_err; m++) {
+               int want_set = m->flags & MOPT_SET;
+               if (((m->flags & (MOPT_SET|MOPT_CLEAR)) == 0) ||
+                   (m->flags & MOPT_CLEAR_ERR))
+                       continue;
+               if (!(m->mount_opt & (sbi->s_mount_opt ^ def_mount_opt)))
+                       continue; /* skip if same as the default */
+               if ((want_set &&
+                    (sbi->s_mount_opt & m->mount_opt) != m->mount_opt) ||
+                   (!want_set && (sbi->s_mount_opt & m->mount_opt)))
+                       continue; /* select Opt_noFoo vs Opt_Foo */
+               SEQ_OPTS_PRINT("%s", token2str(m->token));
+       }
+
+       if (nodefs || sbi->s_resuid != EXT4_DEF_RESUID ||
+           le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID)
+               SEQ_OPTS_PRINT("resuid=%u", sbi->s_resuid);
+       if (nodefs || sbi->s_resgid != EXT4_DEF_RESGID ||
+           le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID)
+               SEQ_OPTS_PRINT("resgid=%u", sbi->s_resgid);
+       def_errors = nodefs ? -1 : le16_to_cpu(es->s_errors);
+       if (test_opt(sb, ERRORS_RO) && def_errors != EXT4_ERRORS_RO)
+               SEQ_OPTS_PUTS("errors=remount-ro");
+       if (test_opt(sb, ERRORS_CONT) && def_errors != EXT4_ERRORS_CONTINUE)
+               SEQ_OPTS_PUTS("errors=continue");
+       if (test_opt(sb, ERRORS_PANIC) && def_errors != EXT4_ERRORS_PANIC)
+               SEQ_OPTS_PUTS("errors=panic");
+       if (nodefs || sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ)
+               SEQ_OPTS_PRINT("commit=%lu", sbi->s_commit_interval / HZ);
+       if (nodefs || sbi->s_min_batch_time != EXT4_DEF_MIN_BATCH_TIME)
+               SEQ_OPTS_PRINT("min_batch_time=%u", sbi->s_min_batch_time);
+       if (nodefs || sbi->s_max_batch_time != EXT4_DEF_MAX_BATCH_TIME)
+               SEQ_OPTS_PRINT("max_batch_time=%u", sbi->s_max_batch_time);
+       if (sb->s_flags & MS_I_VERSION)
+               SEQ_OPTS_PUTS("i_version");
+       if (nodefs || sbi->s_stripe)
+               SEQ_OPTS_PRINT("stripe=%lu", sbi->s_stripe);
+       if (EXT4_MOUNT_DATA_FLAGS & (sbi->s_mount_opt ^ def_mount_opt)) {
+               if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
+                       SEQ_OPTS_PUTS("data=journal");
+               else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
+                       SEQ_OPTS_PUTS("data=ordered");
+               else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
+                       SEQ_OPTS_PUTS("data=writeback");
+       }
+       if (nodefs ||
+           sbi->s_inode_readahead_blks != EXT4_DEF_INODE_READAHEAD_BLKS)
+               SEQ_OPTS_PRINT("inode_readahead_blks=%u",
+                              sbi->s_inode_readahead_blks);
+
+       if (nodefs || (test_opt(sb, INIT_INODE_TABLE) &&
+                      (sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT)))
+               SEQ_OPTS_PRINT("init_itable=%u", sbi->s_li_wait_mult);
+
+       ext4_show_quota_options(seq, sb);
+       return 0;
+}
+
+static int ext4_show_options(struct seq_file *seq, struct dentry *root)
+{
+       return _ext4_show_options(seq, root->d_sb, 0);
+}
+
+static int options_seq_show(struct seq_file *seq, void *offset)
+{
+       struct super_block *sb = seq->private;
+       int rc;
+
+       seq_puts(seq, (sb->s_flags & MS_RDONLY) ? "ro" : "rw");
+       rc = _ext4_show_options(seq, sb, 1);
+       seq_puts(seq, "\n");
+       return rc;
+}
+
+static int options_open_fs(struct inode *inode, struct file *file)
+{
+       return single_open(file, options_seq_show, PDE(inode)->data);
+}
+
+static const struct file_operations ext4_seq_options_fops = {
+       .owner = THIS_MODULE,
+       .open = options_open_fs,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
 static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
                            int read_only)
 {
@@ -2945,7 +2808,7 @@ static int ext4_run_lazyinit_thread(void)
                ext4_clear_request_list();
                kfree(ext4_li_info);
                ext4_li_info = NULL;
-               printk(KERN_CRIT "EXT4: error %d creating inode table "
+               printk(KERN_CRIT "EXT4-fs: error %d creating inode table "
                                 "initialization thread\n",
                                 err);
                return err;
@@ -3183,11 +3046,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        set_opt(sb, INIT_INODE_TABLE);
        if (def_mount_opts & EXT4_DEFM_DEBUG)
                set_opt(sb, DEBUG);
-       if (def_mount_opts & EXT4_DEFM_BSDGROUPS) {
-               ext4_msg(sb, KERN_WARNING, deprecated_msg, "bsdgroups",
-                       "2.6.38");
+       if (def_mount_opts & EXT4_DEFM_BSDGROUPS)
                set_opt(sb, GRPID);
-       }
        if (def_mount_opts & EXT4_DEFM_UID16)
                set_opt(sb, NO_UID32);
        /* xattr user namespace & acls are now defaulted on */
@@ -3240,13 +3100,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT;
 
        if (!parse_options((char *) sbi->s_es->s_mount_opts, sb,
-                          &journal_devnum, &journal_ioprio, NULL, 0)) {
+                          &journal_devnum, &journal_ioprio, 0)) {
                ext4_msg(sb, KERN_WARNING,
                         "failed to parse options in superblock: %s",
                         sbi->s_es->s_mount_opts);
        }
+       sbi->s_def_mount_opt = sbi->s_mount_opt;
        if (!parse_options((char *) data, sb, &journal_devnum,
-                          &journal_ioprio, NULL, 0))
+                          &journal_ioprio, 0))
                goto failed_mount;
 
        if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
@@ -3416,7 +3277,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 #else
                es->s_flags |= cpu_to_le32(EXT2_FLAGS_SIGNED_HASH);
 #endif
-               sb->s_dirt = 1;
        }
 
        /* Handle clustersize */
@@ -3540,6 +3400,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        if (ext4_proc_root)
                sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root);
 
+       if (sbi->s_proc)
+               proc_create_data("options", S_IRUGO, sbi->s_proc,
+                                &ext4_seq_options_fops, sb);
+
        bgl_lock_init(sbi->s_blockgroup_lock);
 
        for (i = 0; i < db_count; i++) {
@@ -3694,6 +3558,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        }
        set_task_ioprio(sbi->s_journal->j_task, journal_ioprio);
 
+       sbi->s_journal->j_commit_callback = ext4_journal_commit_callback;
+
        /*
         * The journal may have updated the bg summary counts, so we
         * need to update the global counters.
@@ -3861,6 +3727,7 @@ failed_mount2:
        ext4_kvfree(sbi->s_group_desc);
 failed_mount:
        if (sbi->s_proc) {
+               remove_proc_entry("options", sbi->s_proc);
                remove_proc_entry(sb->s_id, ext4_proc_root);
        }
 #ifdef CONFIG_QUOTA
@@ -4090,15 +3957,6 @@ static int ext4_load_journal(struct super_block *sb,
        if (!(journal->j_flags & JBD2_BARRIER))
                ext4_msg(sb, KERN_INFO, "barriers disabled");
 
-       if (!really_read_only && test_opt(sb, UPDATE_JOURNAL)) {
-               err = jbd2_journal_update_format(journal);
-               if (err)  {
-                       ext4_msg(sb, KERN_ERR, "error updating journal");
-                       jbd2_journal_destroy(journal);
-                       return err;
-               }
-       }
-
        if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER))
                err = jbd2_journal_wipe(journal, !really_read_only);
        if (!err) {
@@ -4385,7 +4243,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 {
        struct ext4_super_block *es;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
-       ext4_fsblk_t n_blocks_count = 0;
        unsigned long old_sb_flags;
        struct ext4_mount_options old_opts;
        int enable_quota = 0;
@@ -4418,8 +4275,7 @@ static int ext4_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, &journal_ioprio,
-                          &n_blocks_count, 1)) {
+       if (!parse_options(data, sb, NULL, &journal_ioprio, 1)) {
                err = -EINVAL;
                goto restore_opts;
        }
@@ -4437,8 +4293,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                set_task_ioprio(sbi->s_journal->j_task, journal_ioprio);
        }
 
-       if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) ||
-               n_blocks_count > ext4_blocks_count(es)) {
+       if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
                if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED) {
                        err = -EROFS;
                        goto restore_opts;
@@ -4513,8 +4368,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                        if (sbi->s_journal)
                                ext4_clear_journal_err(sb, es);
                        sbi->s_mount_state = le16_to_cpu(es->s_state);
-                       if ((err = ext4_group_extend(sb, es, n_blocks_count)))
-                               goto restore_opts;
                        if (!ext4_setup_super(sb, es, 0))
                                sb->s_flags &= ~MS_RDONLY;
                        if (EXT4_HAS_INCOMPAT_FEATURE(sb,