]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/ext4/super.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[karo-tx-linux.git] / fs / ext4 / super.c
index 4df78dd3f5234ae5eb613963ee1dd2571ca6f925..620cf5615ba28098ef81665c9d094aacfc0553bf 100644 (file)
@@ -69,8 +69,6 @@ static void ext4_mark_recovery_complete(struct super_block *sb,
 static void ext4_clear_journal_err(struct super_block *sb,
                                   struct ext4_super_block *es);
 static int ext4_sync_fs(struct super_block *sb, int wait);
-static const char *ext4_decode_error(struct super_block *sb, int errno,
-                                    char nbuf[16]);
 static int ext4_remount(struct super_block *sb, int *flags, char *data);
 static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf);
 static int ext4_unfreeze(struct super_block *sb);
@@ -296,107 +294,6 @@ void ext4_itable_unused_set(struct super_block *sb,
 }
 
 
-/* Just increment the non-pointer handle value */
-static handle_t *ext4_get_nojournal(void)
-{
-       handle_t *handle = current->journal_info;
-       unsigned long ref_cnt = (unsigned long)handle;
-
-       BUG_ON(ref_cnt >= EXT4_NOJOURNAL_MAX_REF_COUNT);
-
-       ref_cnt++;
-       handle = (handle_t *)ref_cnt;
-
-       current->journal_info = handle;
-       return handle;
-}
-
-
-/* Decrement the non-pointer handle value */
-static void ext4_put_nojournal(handle_t *handle)
-{
-       unsigned long ref_cnt = (unsigned long)handle;
-
-       BUG_ON(ref_cnt == 0);
-
-       ref_cnt--;
-       handle = (handle_t *)ref_cnt;
-
-       current->journal_info = handle;
-}
-
-/*
- * Wrappers for jbd2_journal_start/end.
- */
-handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
-{
-       journal_t *journal;
-
-       trace_ext4_journal_start(sb, nblocks, _RET_IP_);
-       if (sb->s_flags & MS_RDONLY)
-               return ERR_PTR(-EROFS);
-
-       WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE);
-       journal = EXT4_SB(sb)->s_journal;
-       if (!journal)
-               return ext4_get_nojournal();
-       /*
-        * Special case here: if the journal has aborted behind our
-        * backs (eg. EIO in the commit thread), then we still need to
-        * take the FS itself readonly cleanly.
-        */
-       if (is_journal_aborted(journal)) {
-               ext4_abort(sb, "Detected aborted journal");
-               return ERR_PTR(-EROFS);
-       }
-       return jbd2_journal_start(journal, nblocks);
-}
-
-int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
-{
-       struct super_block *sb;
-       int err;
-       int rc;
-
-       if (!ext4_handle_valid(handle)) {
-               ext4_put_nojournal(handle);
-               return 0;
-       }
-       sb = handle->h_transaction->t_journal->j_private;
-       err = handle->h_err;
-       rc = jbd2_journal_stop(handle);
-
-       if (!err)
-               err = rc;
-       if (err)
-               __ext4_std_error(sb, where, line, err);
-       return err;
-}
-
-void ext4_journal_abort_handle(const char *caller, unsigned int line,
-                              const char *err_fn, struct buffer_head *bh,
-                              handle_t *handle, int err)
-{
-       char nbuf[16];
-       const char *errstr = ext4_decode_error(NULL, err, nbuf);
-
-       BUG_ON(!ext4_handle_valid(handle));
-
-       if (bh)
-               BUFFER_TRACE(bh, "abort");
-
-       if (!handle->h_err)
-               handle->h_err = err;
-
-       if (is_handle_aborted(handle))
-               return;
-
-       printk(KERN_ERR "EXT4-fs: %s:%d: aborting transaction: %s in %s\n",
-              caller, line, errstr, err_fn);
-
-       jbd2_journal_abort_handle(handle);
-}
-
 static void __save_error_info(struct super_block *sb, const char *func,
                            unsigned int line)
 {
@@ -582,8 +479,8 @@ void ext4_error_file(struct file *file, const char *function,
        ext4_handle_error(inode->i_sb);
 }
 
-static const char *ext4_decode_error(struct super_block *sb, int errno,
-                                    char nbuf[16])
+const char *ext4_decode_error(struct super_block *sb, int errno,
+                             char nbuf[16])
 {
        char *errstr = NULL;
 
@@ -858,6 +755,7 @@ static void ext4_put_super(struct super_block *sb)
                        ext4_abort(sb, "Couldn't clean up the journal");
        }
 
+       ext4_es_unregister_shrinker(sb);
        del_timer(&sbi->s_err_report);
        ext4_release_system_zone(sb);
        ext4_mb_release(sb);
@@ -939,11 +837,12 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
                return NULL;
 
        ei->vfs_inode.i_version = 1;
-       memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache));
        INIT_LIST_HEAD(&ei->i_prealloc_list);
        spin_lock_init(&ei->i_prealloc_lock);
        ext4_es_init_tree(&ei->i_es_tree);
        rwlock_init(&ei->i_es_lock);
+       INIT_LIST_HEAD(&ei->i_es_lru);
+       ei->i_es_lru_nr = 0;
        ei->i_reserved_data_blocks = 0;
        ei->i_reserved_meta_blocks = 0;
        ei->i_allocated_meta_blocks = 0;
@@ -960,6 +859,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
        ei->i_datasync_tid = 0;
        atomic_set(&ei->i_ioend_count, 0);
        atomic_set(&ei->i_unwritten, 0);
+       INIT_WORK(&ei->i_unwritten_work, ext4_end_io_work);
 
        return &ei->vfs_inode;
 }
@@ -1031,6 +931,7 @@ void ext4_clear_inode(struct inode *inode)
        dquot_drop(inode);
        ext4_discard_preallocations(inode);
        ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS);
+       ext4_es_lru_del(inode);
        if (EXT4_I(inode)->jinode) {
                jbd2_journal_release_jbd_inode(EXT4_JOURNAL(inode),
                                               EXT4_I(inode)->jinode);
@@ -1280,8 +1181,8 @@ static const match_table_t tokens = {
        {Opt_stripe, "stripe=%u"},
        {Opt_delalloc, "delalloc"},
        {Opt_nodelalloc, "nodelalloc"},
-       {Opt_mblk_io_submit, "mblk_io_submit"},
-       {Opt_nomblk_io_submit, "nomblk_io_submit"},
+       {Opt_removed, "mblk_io_submit"},
+       {Opt_removed, "nomblk_io_submit"},
        {Opt_block_validity, "block_validity"},
        {Opt_noblock_validity, "noblock_validity"},
        {Opt_inode_readahead_blks, "inode_readahead_blks=%u"},
@@ -1337,6 +1238,7 @@ static int set_qf_name(struct super_block *sb, int qtype, substring_t *args)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        char *qname;
+       int ret = -1;
 
        if (sb_any_quota_loaded(sb) &&
                !sbi->s_qf_names[qtype]) {
@@ -1351,23 +1253,26 @@ static int set_qf_name(struct super_block *sb, int qtype, substring_t *args)
                        "Not enough memory for storing quotafile name");
                return -1;
        }
-       if (sbi->s_qf_names[qtype] &&
-               strcmp(sbi->s_qf_names[qtype], qname)) {
-               ext4_msg(sb, KERN_ERR,
-                       "%s quota file already specified", QTYPE2NAME(qtype));
-               kfree(qname);
-               return -1;
+       if (sbi->s_qf_names[qtype]) {
+               if (strcmp(sbi->s_qf_names[qtype], qname) == 0)
+                       ret = 1;
+               else
+                       ext4_msg(sb, KERN_ERR,
+                                "%s quota file already specified",
+                                QTYPE2NAME(qtype));
+               goto errout;
        }
-       sbi->s_qf_names[qtype] = qname;
-       if (strchr(sbi->s_qf_names[qtype], '/')) {
+       if (strchr(qname, '/')) {
                ext4_msg(sb, KERN_ERR,
                        "quotafile must be on filesystem root");
-               kfree(sbi->s_qf_names[qtype]);
-               sbi->s_qf_names[qtype] = NULL;
-               return -1;
+               goto errout;
        }
+       sbi->s_qf_names[qtype] = qname;
        set_opt(sb, QUOTA);
        return 1;
+errout:
+       kfree(qname);
+       return ret;
 }
 
 static int clear_qf_name(struct super_block *sb, int qtype)
@@ -1381,10 +1286,7 @@ static int clear_qf_name(struct super_block *sb, int qtype)
                        " when quota turned on");
                return -1;
        }
-       /*
-        * The space will be released later when all options are confirmed
-        * to be correct
-        */
+       kfree(sbi->s_qf_names[qtype]);
        sbi->s_qf_names[qtype] = NULL;
        return 1;
 }
@@ -1404,6 +1306,9 @@ static int clear_qf_name(struct super_block *sb, int qtype)
 #define MOPT_QFMT      MOPT_NOSUPPORT
 #endif
 #define MOPT_DATAJ     0x0080
+#define MOPT_NO_EXT2   0x0100
+#define MOPT_NO_EXT3   0x0200
+#define MOPT_EXT4_ONLY (MOPT_NO_EXT2 | MOPT_NO_EXT3)
 
 static const struct mount_opts {
        int     token;
@@ -1414,25 +1319,31 @@ static const struct mount_opts {
        {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_dioread_nolock, EXT4_MOUNT_DIOREAD_NOLOCK,
+        MOPT_EXT4_ONLY | MOPT_SET},
+       {Opt_dioread_lock, EXT4_MOUNT_DIOREAD_NOLOCK,
+        MOPT_EXT4_ONLY | 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_delalloc, EXT4_MOUNT_DELALLOC,
+        MOPT_EXT4_ONLY | MOPT_SET | MOPT_EXPLICIT},
+       {Opt_nodelalloc, EXT4_MOUNT_DELALLOC,
+        MOPT_EXT4_ONLY | MOPT_CLEAR | MOPT_EXPLICIT},
+       {Opt_journal_checksum, EXT4_MOUNT_JOURNAL_CHECKSUM,
+        MOPT_EXT4_ONLY | MOPT_SET},
        {Opt_journal_async_commit, (EXT4_MOUNT_JOURNAL_ASYNC_COMMIT |
-                                   EXT4_MOUNT_JOURNAL_CHECKSUM), MOPT_SET},
-       {Opt_noload, EXT4_MOUNT_NOLOAD, MOPT_SET},
+                                   EXT4_MOUNT_JOURNAL_CHECKSUM),
+        MOPT_EXT4_ONLY | MOPT_SET},
+       {Opt_noload, EXT4_MOUNT_NOLOAD, MOPT_NO_EXT2 | 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_data_err_abort, EXT4_MOUNT_DATA_ERR_ABORT,
+        MOPT_NO_EXT2 | MOPT_SET},
+       {Opt_data_err_ignore, EXT4_MOUNT_DATA_ERR_ABORT,
+        MOPT_NO_EXT2 | 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},
@@ -1444,9 +1355,14 @@ static const struct mount_opts {
        {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},
+       {Opt_resuid, 0, MOPT_GTE0},
+       {Opt_resgid, 0, MOPT_GTE0},
+       {Opt_journal_dev, 0, MOPT_GTE0},
+       {Opt_journal_ioprio, 0, MOPT_GTE0},
+       {Opt_data_journal, EXT4_MOUNT_JOURNAL_DATA, MOPT_NO_EXT2 | MOPT_DATAJ},
+       {Opt_data_ordered, EXT4_MOUNT_ORDERED_DATA, MOPT_NO_EXT2 | MOPT_DATAJ},
+       {Opt_data_writeback, EXT4_MOUNT_WRITEBACK_DATA,
+        MOPT_NO_EXT2 | MOPT_DATAJ},
        {Opt_user_xattr, EXT4_MOUNT_XATTR_USER, MOPT_SET},
        {Opt_nouser_xattr, EXT4_MOUNT_XATTR_USER, MOPT_CLEAR},
 #ifdef CONFIG_EXT4_FS_POSIX_ACL
@@ -1496,8 +1412,6 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
        else if (token == Opt_offgrpjquota)
                return clear_qf_name(sb, GRPQUOTA);
 #endif
-       if (args->from && match_int(args, &arg))
-               return -1;
        switch (token) {
        case Opt_noacl:
        case Opt_nouser_xattr:
@@ -1506,138 +1420,149 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
        case Opt_sb:
                return 1;       /* handled by get_sb_block() */
        case Opt_removed:
-               ext4_msg(sb, KERN_WARNING,
-                        "Ignoring removed %s option", opt);
+               ext4_msg(sb, KERN_WARNING, "Ignoring removed %s option", opt);
+               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_resuid:
+       }
+
+       for (m = ext4_mount_opts; m->token != Opt_err; m++)
+               if (token == m->token)
+                       break;
+
+       if (m->token == Opt_err) {
+               ext4_msg(sb, KERN_ERR, "Unrecognized mount option \"%s\" "
+                        "or missing value", opt);
+               return -1;
+       }
+
+       if ((m->flags & MOPT_NO_EXT2) && IS_EXT2_SB(sb)) {
+               ext4_msg(sb, KERN_ERR,
+                        "Mount option \"%s\" incompatible with ext2", opt);
+               return -1;
+       }
+       if ((m->flags & MOPT_NO_EXT3) && IS_EXT3_SB(sb)) {
+               ext4_msg(sb, KERN_ERR,
+                        "Mount option \"%s\" incompatible with ext3", opt);
+               return -1;
+       }
+
+       if (args->from && match_int(args, &arg))
+               return -1;
+       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 && (arg > (1 << 30) || !is_power_of_2(arg))) {
+                       ext4_msg(sb, KERN_ERR,
+                                "EXT4-fs: inode_readahead_blks must be "
+                                "0 or a power of 2 smaller than 2^31");
+                       return -1;
+               }
+               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_max_dir_size_kb) {
+               sbi->s_max_dir_size_kb = arg;
+       } else if (token == Opt_stripe) {
+               sbi->s_stripe = arg;
+       } else if (token == Opt_resuid) {
                uid = make_kuid(current_user_ns(), arg);
                if (!uid_valid(uid)) {
                        ext4_msg(sb, KERN_ERR, "Invalid uid value %d", arg);
                        return -1;
                }
                sbi->s_resuid = uid;
-               return 1;
-       case Opt_resgid:
+       } else if (token == Opt_resgid) {
                gid = make_kgid(current_user_ns(), arg);
                if (!gid_valid(gid)) {
                        ext4_msg(sb, KERN_ERR, "Invalid gid value %d", arg);
                        return -1;
                }
                sbi->s_resgid = gid;
-               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:
+       } else if (token == 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");
+       } else if (token == Opt_journal_ioprio) {
+               if (arg > 7) {
+                       ext4_msg(sb, KERN_ERR, "Invalid journal IO priority"
+                                " (must be 0-7)");
                        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)) {
+               *journal_ioprio =
+                       IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 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) != m->mount_opt) {
                                ext4_msg(sb, KERN_ERR,
-                                        "EXT4-fs: inode_readahead_blks"
-                                        " must be a power of 2");
-                               return -1;
-                       }
-                       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_max_dir_size_kb) {
-                       sbi->s_max_dir_size_kb = 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) !=
-                                        m->mount_opt) {
-                                       ext4_msg(sb, KERN_ERR,
                                         "Cannot change data mode on remount");
-                                       return -1;
-                               }
-                       } else {
-                               clear_opt(sb, DATA_FLAGS);
-                               sbi->s_mount_opt |= m->mount_opt;
-                       }
-#ifdef CONFIG_QUOTA
-               } else if (m->flags & MOPT_QFMT) {
-                       if (sb_any_quota_loaded(sb) &&
-                           sbi->s_jquota_fmt != m->mount_opt) {
-                               ext4_msg(sb, KERN_ERR, "Cannot "
-                                        "change journaled quota options "
-                                        "when quota turned on");
                                return -1;
                        }
-                       sbi->s_jquota_fmt = m->mount_opt;
-#endif
                } 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;
-                       }
-                       if (arg != 0)
-                               sbi->s_mount_opt |= m->mount_opt;
-                       else
-                               sbi->s_mount_opt &= ~m->mount_opt;
+                       clear_opt(sb, DATA_FLAGS);
+                       sbi->s_mount_opt |= m->mount_opt;
                }
-               return 1;
+#ifdef CONFIG_QUOTA
+       } else if (m->flags & MOPT_QFMT) {
+               if (sb_any_quota_loaded(sb) &&
+                   sbi->s_jquota_fmt != m->mount_opt) {
+                       ext4_msg(sb, KERN_ERR, "Cannot change journaled "
+                                "quota options when quota turned on");
+                       return -1;
+               }
+               sbi->s_jquota_fmt = m->mount_opt;
+#endif
+       } 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;
+               }
+               if (arg != 0)
+                       sbi->s_mount_opt |= m->mount_opt;
+               else
+                       sbi->s_mount_opt &= ~m->mount_opt;
        }
-       ext4_msg(sb, KERN_ERR, "Unrecognized mount option \"%s\" "
-                "or missing value", opt);
-       return -1;
+       return 1;
 }
 
 static int parse_options(char *options, struct super_block *sb,
@@ -2776,7 +2701,7 @@ static int ext4_run_li_request(struct ext4_li_request *elr)
                        break;
        }
 
-       if (group == ngroups)
+       if (group >= ngroups)
                ret = 1;
 
        if (!ret) {
@@ -3016,33 +2941,34 @@ static struct ext4_li_request *ext4_li_request_new(struct super_block *sb,
        return elr;
 }
 
-static int ext4_register_li_request(struct super_block *sb,
-                                   ext4_group_t first_not_zeroed)
+int ext4_register_li_request(struct super_block *sb,
+                            ext4_group_t first_not_zeroed)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
-       struct ext4_li_request *elr;
+       struct ext4_li_request *elr = NULL;
        ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
        int ret = 0;
 
+       mutex_lock(&ext4_li_mtx);
        if (sbi->s_li_request != NULL) {
                /*
                 * Reset timeout so it can be computed again, because
                 * s_li_wait_mult might have changed.
                 */
                sbi->s_li_request->lr_timeout = 0;
-               return 0;
+               goto out;
        }
 
        if (first_not_zeroed == ngroups ||
            (sb->s_flags & MS_RDONLY) ||
            !test_opt(sb, INIT_INODE_TABLE))
-               return 0;
+               goto out;
 
        elr = ext4_li_request_new(sb, first_not_zeroed);
-       if (!elr)
-               return -ENOMEM;
-
-       mutex_lock(&ext4_li_mtx);
+       if (!elr) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
        if (NULL == ext4_li_info) {
                ret = ext4_li_info_new();
@@ -3379,7 +3305,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 #ifdef CONFIG_EXT4_FS_POSIX_ACL
        set_opt(sb, POSIX_ACL);
 #endif
-       set_opt(sb, MBLK_IO_SUBMIT);
        if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_DATA)
                set_opt(sb, JOURNAL_DATA);
        else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_ORDERED)
@@ -3772,6 +3697,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sbi->s_max_writeback_mb_bump = 128;
        sbi->s_extent_max_zeroout_kb = 32;
 
+       /* Register extent status tree shrinker */
+       ext4_es_register_shrinker(sb);
+
        /*
         * set up enough so that it can read an inode
         */
@@ -4008,7 +3936,7 @@ no_journal:
            !(sb->s_flags & MS_RDONLY)) {
                err = ext4_enable_quotas(sb);
                if (err)
-                       goto failed_mount7;
+                       goto failed_mount8;
        }
 #endif  /* CONFIG_QUOTA */
 
@@ -4035,6 +3963,10 @@ cantfind_ext4:
                ext4_msg(sb, KERN_ERR, "VFS: Can't find ext4 filesystem");
        goto failed_mount;
 
+#ifdef CONFIG_QUOTA
+failed_mount8:
+       kobject_del(&sbi->s_kobj);
+#endif
 failed_mount7:
        ext4_unregister_li_request(sb);
 failed_mount6:
@@ -4476,16 +4408,12 @@ static void ext4_clear_journal_err(struct super_block *sb,
 int ext4_force_commit(struct super_block *sb)
 {
        journal_t *journal;
-       int ret = 0;
 
        if (sb->s_flags & MS_RDONLY)
                return 0;
 
        journal = EXT4_SB(sb)->s_journal;
-       if (journal)
-               ret = ext4_journal_force_commit(journal);
-
-       return ret;
+       return ext4_journal_force_commit(journal);
 }
 
 static int ext4_sync_fs(struct super_block *sb, int wait)
@@ -4588,7 +4516,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
        unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
        int err = 0;
 #ifdef CONFIG_QUOTA
-       int i;
+       int i, j;
 #endif
        char *orig_data = kstrdup(data, GFP_KERNEL);
 
@@ -4604,7 +4532,16 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 #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];
+               if (sbi->s_qf_names[i]) {
+                       old_opts.s_qf_names[i] = kstrdup(sbi->s_qf_names[i],
+                                                        GFP_KERNEL);
+                       if (!old_opts.s_qf_names[i]) {
+                               for (j = 0; j < i; j++)
+                                       kfree(old_opts.s_qf_names[j]);
+                               return -ENOMEM;
+                       }
+               } else
+                       old_opts.s_qf_names[i] = NULL;
 #endif
        if (sbi->s_journal && sbi->s_journal->j_task->io_context)
                journal_ioprio = sbi->s_journal->j_task->io_context->ioprio;
@@ -4737,9 +4674,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 #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]);
+               kfree(old_opts.s_qf_names[i]);
        if (enable_quota) {
                if (sb_any_quota_suspended(sb))
                        dquot_resume(sb, -1);
@@ -4768,9 +4703,7 @@ restore_opts:
 #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]);
+               kfree(sbi->s_qf_names[i]);
                sbi->s_qf_names[i] = old_opts.s_qf_names[i];
        }
 #endif
@@ -4835,7 +4768,7 @@ static int ext4_write_dquot(struct dquot *dquot)
        struct inode *inode;
 
        inode = dquot_to_inode(dquot);
-       handle = ext4_journal_start(inode,
+       handle = ext4_journal_start(inode, EXT4_HT_QUOTA,
                                    EXT4_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
@@ -4851,7 +4784,7 @@ static int ext4_acquire_dquot(struct dquot *dquot)
        int ret, err;
        handle_t *handle;
 
-       handle = ext4_journal_start(dquot_to_inode(dquot),
+       handle = ext4_journal_start(dquot_to_inode(dquot), EXT4_HT_QUOTA,
                                    EXT4_QUOTA_INIT_BLOCKS(dquot->dq_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
@@ -4867,7 +4800,7 @@ static int ext4_release_dquot(struct dquot *dquot)
        int ret, err;
        handle_t *handle;
 
-       handle = ext4_journal_start(dquot_to_inode(dquot),
+       handle = ext4_journal_start(dquot_to_inode(dquot), EXT4_HT_QUOTA,
                                    EXT4_QUOTA_DEL_BLOCKS(dquot->dq_sb));
        if (IS_ERR(handle)) {
                /* Release dquot anyway to avoid endless cycle in dqput() */
@@ -4899,7 +4832,7 @@ static int ext4_write_info(struct super_block *sb, int type)
        handle_t *handle;
 
        /* Data block + inode block */
-       handle = ext4_journal_start(sb->s_root->d_inode, 2);
+       handle = ext4_journal_start(sb->s_root->d_inode, EXT4_HT_QUOTA, 2);
        if (IS_ERR(handle))
                return PTR_ERR(handle);
        ret = dquot_commit_info(sb, type);
@@ -5005,9 +4938,9 @@ static int ext4_enable_quotas(struct super_block *sb)
                                                DQUOT_USAGE_ENABLED);
                        if (err) {
                                ext4_warning(sb,
-                                       "Failed to enable quota (type=%d) "
-                                       "tracking. Please run e2fsck to fix.",
-                                       type);
+                                       "Failed to enable quota tracking "
+                                       "(type=%d, err=%d). Please run "
+                                       "e2fsck to fix.", type, err);
                                return err;
                        }
                }
@@ -5045,7 +4978,7 @@ static int ext4_quota_off(struct super_block *sb, int type)
 
        /* Update modification times of quota files when userspace can
         * start looking at them */
-       handle = ext4_journal_start(inode, 1);
+       handle = ext4_journal_start(inode, EXT4_HT_QUOTA, 1);
        if (IS_ERR(handle))
                goto out;
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;