Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
[safe/jmp/linux-2.6] / fs / ext4 / super.c
index 035516c..49d88c0 100644 (file)
@@ -68,7 +68,21 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf);
 static int ext4_unfreeze(struct super_block *sb);
 static void ext4_write_super(struct super_block *sb);
 static int ext4_freeze(struct super_block *sb);
+static int ext4_get_sb(struct file_system_type *fs_type, int flags,
+                      const char *dev_name, void *data, struct vfsmount *mnt);
 
+#if !defined(CONFIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23)
+static struct file_system_type ext3_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "ext3",
+       .get_sb         = ext4_get_sb,
+       .kill_sb        = kill_block_super,
+       .fs_flags       = FS_REQUIRES_DEV,
+};
+#define IS_EXT3_SB(sb) ((sb)->s_bdev->bd_holder == &ext3_fs_type)
+#else
+#define IS_EXT3_SB(sb) (0)
+#endif
 
 ext4_fsblk_t ext4_block_bitmap(struct super_block *sb,
                               struct ext4_group_desc *bg)
@@ -227,6 +241,7 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
        if (sb->s_flags & MS_RDONLY)
                return ERR_PTR(-EROFS);
 
+       vfs_check_frozen(sb, SB_FREEZE_WRITE);
        /* 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. */
@@ -302,7 +317,7 @@ void ext4_journal_abort_handle(const char *caller, const char *err_fn,
  * write out the superblock safely.
  *
  * We'll just use the jbd2_journal_abort() error code to record an error in
- * the journal instead.  On recovery, the journal will compain about
+ * the journal instead.  On recovery, the journal will complain about
  * that error until we've noted it down and cleared it.
  */
 
@@ -333,7 +348,7 @@ static void ext4_handle_error(struct super_block *sb)
                        sb->s_id);
 }
 
-void ext4_error(struct super_block *sb, const char *function,
+void __ext4_error(struct super_block *sb, const char *function,
                const char *fmt, ...)
 {
        va_list args;
@@ -347,6 +362,42 @@ void ext4_error(struct super_block *sb, const char *function,
        ext4_handle_error(sb);
 }
 
+void ext4_error_inode(const char *function, struct inode *inode,
+                     const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       printk(KERN_CRIT "EXT4-fs error (device %s): %s: inode #%lu: (comm %s) ",
+              inode->i_sb->s_id, function, inode->i_ino, current->comm);
+       vprintk(fmt, args);
+       printk("\n");
+       va_end(args);
+
+       ext4_handle_error(inode->i_sb);
+}
+
+void ext4_error_file(const char *function, struct file *file,
+                    const char *fmt, ...)
+{
+       va_list args;
+       struct inode *inode = file->f_dentry->d_inode;
+       char pathname[80], *path;
+
+       va_start(args, fmt);
+       path = d_path(&(file->f_path), pathname, sizeof(pathname));
+       if (!path)
+               path = "(unknown)";
+       printk(KERN_CRIT
+              "EXT4-fs error (device %s): %s: inode #%lu (comm %s path %s): ",
+              inode->i_sb->s_id, function, inode->i_ino, current->comm, path);
+       vprintk(fmt, args);
+       printk("\n");
+       va_end(args);
+
+       ext4_handle_error(inode->i_sb);
+}
+
 static const char *ext4_decode_error(struct super_block *sb, int errno,
                                     char nbuf[16])
 {
@@ -450,7 +501,7 @@ void ext4_msg (struct super_block * sb, const char *prefix,
        va_end(args);
 }
 
-void ext4_warning(struct super_block *sb, const char *function,
+void __ext4_warning(struct super_block *sb, const char *function,
                  const char *fmt, ...)
 {
        va_list args;
@@ -507,7 +558,7 @@ void ext4_update_dynamic_rev(struct super_block *sb)
        if (le32_to_cpu(es->s_rev_level) > EXT4_GOOD_OLD_REV)
                return;
 
-       ext4_warning(sb, __func__,
+       ext4_warning(sb,
                     "updating to rev %d because of new feature flag, "
                     "running e2fsck is recommended",
                     EXT4_DYNAMIC_REV);
@@ -708,7 +759,8 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
 #ifdef CONFIG_QUOTA
        ei->i_reserved_quota = 0;
 #endif
-       INIT_LIST_HEAD(&ei->i_aio_dio_complete_list);
+       INIT_LIST_HEAD(&ei->i_completed_io_list);
+       spin_lock_init(&ei->i_completed_io_lock);
        ei->cur_aio_dio = NULL;
        ei->i_sync_tid = 0;
        ei->i_datasync_tid = 0;
@@ -797,10 +849,10 @@ static inline void ext4_show_quota_options(struct seq_file *seq,
        if (sbi->s_qf_names[GRPQUOTA])
                seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]);
 
-       if (sbi->s_mount_opt & EXT4_MOUNT_USRQUOTA)
+       if (test_opt(sb, USRQUOTA))
                seq_puts(seq, ",usrquota");
 
-       if (sbi->s_mount_opt & EXT4_MOUNT_GRPQUOTA)
+       if (test_opt(sb, GRPQUOTA))
                seq_puts(seq, ",grpquota");
 #endif
 }
@@ -890,6 +942,8 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
        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, NOBH))
                seq_puts(seq, ",nobh");
        if (test_opt(sb, I_VERSION))
@@ -927,6 +981,9 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
        if (test_opt(sb, NOLOAD))
                seq_puts(seq, ",norecovery");
 
+       if (test_opt(sb, DIOREAD_NOLOCK))
+               seq_puts(seq, ",dioread_nolock");
+
        ext4_show_quota_options(seq, sb);
 
        return 0;
@@ -1013,7 +1070,6 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
                                const char *data, size_t len, loff_t off);
 
 static const struct dquot_operations ext4_quota_operations = {
-       .initialize     = dquot_initialize,
 #ifdef CONFIG_QUOTA
        .get_reserved_space = ext4_get_reserved_space,
 #endif
@@ -1101,6 +1157,7 @@ enum {
        Opt_stripe, Opt_delalloc, Opt_nodelalloc,
        Opt_block_validity, Opt_noblock_validity,
        Opt_inode_readahead_blks, Opt_journal_ioprio,
+       Opt_dioread_nolock, Opt_dioread_lock,
        Opt_discard, Opt_nodiscard,
 };
 
@@ -1168,6 +1225,8 @@ static const match_table_t tokens = {
        {Opt_auto_da_alloc, "auto_da_alloc=%u"},
        {Opt_auto_da_alloc, "auto_da_alloc"},
        {Opt_noauto_da_alloc, "noauto_da_alloc"},
+       {Opt_dioread_nolock, "dioread_nolock"},
+       {Opt_dioread_lock, "dioread_lock"},
        {Opt_discard, "discard"},
        {Opt_nodiscard, "nodiscard"},
        {Opt_err, NULL},
@@ -1197,6 +1256,66 @@ static ext4_fsblk_t get_sb_block(void **data)
 }
 
 #define DEFAULT_JOURNAL_IOPRIO (IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 3))
+static char deprecated_msg[] = "Mount option \"%s\" will be removed by %s\n"
+       "Contact linux-ext4@vger.kernel.org if you think we should keep it.\n";
+
+#ifdef CONFIG_QUOTA
+static int set_qf_name(struct super_block *sb, int qtype, substring_t *args)
+{
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       char *qname;
+
+       if (sb_any_quota_loaded(sb) &&
+               !sbi->s_qf_names[qtype]) {
+               ext4_msg(sb, KERN_ERR,
+                       "Cannot change journaled "
+                       "quota options when quota turned on");
+               return 0;
+       }
+       qname = match_strdup(args);
+       if (!qname) {
+               ext4_msg(sb, KERN_ERR,
+                       "Not enough memory for storing quotafile name");
+               return 0;
+       }
+       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 0;
+       }
+       sbi->s_qf_names[qtype] = qname;
+       if (strchr(sbi->s_qf_names[qtype], '/')) {
+               ext4_msg(sb, KERN_ERR,
+                       "quotafile must be on filesystem root");
+               kfree(sbi->s_qf_names[qtype]);
+               sbi->s_qf_names[qtype] = NULL;
+               return 0;
+       }
+       set_opt(sbi->s_mount_opt, QUOTA);
+       return 1;
+}
+
+static int clear_qf_name(struct super_block *sb, int qtype)
+{
+
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+       if (sb_any_quota_loaded(sb) &&
+               sbi->s_qf_names[qtype]) {
+               ext4_msg(sb, KERN_ERR, "Cannot change journaled quota options"
+                       " when quota turned on");
+               return 0;
+       }
+       /*
+        * The space will be released later when all options are confirmed
+        * to be correct
+        */
+       sbi->s_qf_names[qtype] = NULL;
+       return 1;
+}
+#endif
 
 static int parse_options(char *options, struct super_block *sb,
                         unsigned long *journal_devnum,
@@ -1209,8 +1328,7 @@ static int parse_options(char *options, struct super_block *sb,
        int data_opt = 0;
        int option;
 #ifdef CONFIG_QUOTA
-       int qtype, qfmt;
-       char *qname;
+       int qfmt;
 #endif
 
        if (!options)
@@ -1221,19 +1339,31 @@ static int parse_options(char *options, struct super_block *sb,
                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);
                switch (token) {
                case Opt_bsd_df:
+                       ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38");
                        clear_opt(sbi->s_mount_opt, MINIX_DF);
                        break;
                case Opt_minix_df:
+                       ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38");
                        set_opt(sbi->s_mount_opt, MINIX_DF);
+
                        break;
                case Opt_grpid:
+                       ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38");
                        set_opt(sbi->s_mount_opt, GRPID);
+
                        break;
                case Opt_nogrpid:
+                       ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38");
                        clear_opt(sbi->s_mount_opt, GRPID);
+
                        break;
                case Opt_resuid:
                        if (match_int(&args[0], &option))
@@ -1370,14 +1500,13 @@ static int parse_options(char *options, struct super_block *sb,
                        data_opt = EXT4_MOUNT_WRITEBACK_DATA;
                datacheck:
                        if (is_remount) {
-                               if ((sbi->s_mount_opt & EXT4_MOUNT_DATA_FLAGS)
-                                               != data_opt) {
+                               if (test_opt(sb, DATA_FLAGS) != data_opt) {
                                        ext4_msg(sb, KERN_ERR,
                                                "Cannot change data mode on remount");
                                        return 0;
                                }
                        } else {
-                               sbi->s_mount_opt &= ~EXT4_MOUNT_DATA_FLAGS;
+                               clear_opt(sbi->s_mount_opt, DATA_FLAGS);
                                sbi->s_mount_opt |= data_opt;
                        }
                        break;
@@ -1389,63 +1518,22 @@ static int parse_options(char *options, struct super_block *sb,
                        break;
 #ifdef CONFIG_QUOTA
                case Opt_usrjquota:
-                       qtype = USRQUOTA;
-                       goto set_qf_name;
-               case Opt_grpjquota:
-                       qtype = GRPQUOTA;
-set_qf_name:
-                       if (sb_any_quota_loaded(sb) &&
-                           !sbi->s_qf_names[qtype]) {
-                               ext4_msg(sb, KERN_ERR,
-                                      "Cannot change journaled "
-                                      "quota options when quota turned on");
-                               return 0;
-                       }
-                       qname = match_strdup(&args[0]);
-                       if (!qname) {
-                               ext4_msg(sb, KERN_ERR,
-                                       "Not enough memory for "
-                                       "storing quotafile name");
-                               return 0;
-                       }
-                       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);
+                       if (!set_qf_name(sb, USRQUOTA, &args[0]))
                                return 0;
-                       }
-                       sbi->s_qf_names[qtype] = qname;
-                       if (strchr(sbi->s_qf_names[qtype], '/')) {
-                               ext4_msg(sb, KERN_ERR,
-                                       "quotafile must be on "
-                                       "filesystem root");
-                               kfree(sbi->s_qf_names[qtype]);
-                               sbi->s_qf_names[qtype] = NULL;
+                       break;
+               case Opt_grpjquota:
+                       if (!set_qf_name(sb, GRPQUOTA, &args[0]))
                                return 0;
-                       }
-                       set_opt(sbi->s_mount_opt, QUOTA);
                        break;
                case Opt_offusrjquota:
-                       qtype = USRQUOTA;
-                       goto clear_qf_name;
+                       if (!clear_qf_name(sb, USRQUOTA))
+                               return 0;
+                       break;
                case Opt_offgrpjquota:
-                       qtype = GRPQUOTA;
-clear_qf_name:
-                       if (sb_any_quota_loaded(sb) &&
-                           sbi->s_qf_names[qtype]) {
-                               ext4_msg(sb, KERN_ERR, "Cannot change "
-                                       "journaled quota options when "
-                                       "quota turned on");
+                       if (!clear_qf_name(sb, GRPQUOTA))
                                return 0;
-                       }
-                       /*
-                        * The space will be released later when all options
-                        * are confirmed to be correct
-                        */
-                       sbi->s_qf_names[qtype] = NULL;
                        break;
+
                case Opt_jqfmt_vfsold:
                        qfmt = QFMT_VFS_OLD;
                        goto set_qf_format;
@@ -1510,10 +1598,11 @@ set_qf_format:
                        clear_opt(sbi->s_mount_opt, BARRIER);
                        break;
                case Opt_barrier:
-                       if (match_int(&args[0], &option)) {
-                               set_opt(sbi->s_mount_opt, BARRIER);
-                               break;
-                       }
+                       if (args[0].from) {
+                               if (match_int(&args[0], &option))
+                                       return 0;
+                       } else
+                               option = 1;     /* No argument, default to 1 */
                        if (option)
                                set_opt(sbi->s_mount_opt, BARRIER);
                        else
@@ -1586,10 +1675,11 @@ set_qf_format:
                        set_opt(sbi->s_mount_opt,NO_AUTO_DA_ALLOC);
                        break;
                case Opt_auto_da_alloc:
-                       if (match_int(&args[0], &option)) {
-                               clear_opt(sbi->s_mount_opt, NO_AUTO_DA_ALLOC);
-                               break;
-                       }
+                       if (args[0].from) {
+                               if (match_int(&args[0], &option))
+                                       return 0;
+                       } else
+                               option = 1;     /* No argument, default to 1 */
                        if (option)
                                clear_opt(sbi->s_mount_opt, NO_AUTO_DA_ALLOC);
                        else
@@ -1601,6 +1691,12 @@ set_qf_format:
                case Opt_nodiscard:
                        clear_opt(sbi->s_mount_opt, DISCARD);
                        break;
+               case Opt_dioread_nolock:
+                       set_opt(sbi->s_mount_opt, DIOREAD_NOLOCK);
+                       break;
+               case Opt_dioread_lock:
+                       clear_opt(sbi->s_mount_opt, DIOREAD_NOLOCK);
+                       break;
                default:
                        ext4_msg(sb, KERN_ERR,
                               "Unrecognized mount option \"%s\" "
@@ -1610,18 +1706,13 @@ set_qf_format:
        }
 #ifdef CONFIG_QUOTA
        if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
-               if ((sbi->s_mount_opt & EXT4_MOUNT_USRQUOTA) &&
-                    sbi->s_qf_names[USRQUOTA])
+               if (test_opt(sb, USRQUOTA) && sbi->s_qf_names[USRQUOTA])
                        clear_opt(sbi->s_mount_opt, USRQUOTA);
 
-               if ((sbi->s_mount_opt & EXT4_MOUNT_GRPQUOTA) &&
-                    sbi->s_qf_names[GRPQUOTA])
+               if (test_opt(sb, GRPQUOTA) && sbi->s_qf_names[GRPQUOTA])
                        clear_opt(sbi->s_mount_opt, GRPQUOTA);
 
-               if ((sbi->s_qf_names[USRQUOTA] &&
-                               (sbi->s_mount_opt & EXT4_MOUNT_GRPQUOTA)) ||
-                   (sbi->s_qf_names[GRPQUOTA] &&
-                               (sbi->s_mount_opt & EXT4_MOUNT_USRQUOTA))) {
+               if (test_opt(sb, GRPQUOTA) || test_opt(sb, USRQUOTA)) {
                        ext4_msg(sb, KERN_ERR, "old and new quota "
                                        "format mixing");
                        return 0;
@@ -1931,7 +2022,7 @@ static void ext4_orphan_cleanup(struct super_block *sb,
                }
 
                list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan);
-               vfs_dq_init(inode);
+               dquot_initialize(inode);
                if (inode->i_nlink) {
                        ext4_msg(sb, KERN_DEBUG,
                                "%s: truncating inode %lu to %lld bytes",
@@ -2125,7 +2216,7 @@ static unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi)
 struct ext4_attr {
        struct attribute attr;
        ssize_t (*show)(struct ext4_attr *, struct ext4_sb_info *, char *);
-       ssize_t (*store)(struct ext4_attr *, struct ext4_sb_info *, 
+       ssize_t (*store)(struct ext4_attr *, struct ext4_sb_info *,
                         const char *, size_t);
        int offset;
 };
@@ -2284,7 +2375,7 @@ static void ext4_sb_release(struct kobject *kobj)
 }
 
 
-static struct sysfs_ops ext4_attr_ops = {
+static const struct sysfs_ops ext4_attr_ops = {
        .show   = ext4_attr_show,
        .store  = ext4_attr_store,
 };
@@ -2342,6 +2433,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                                __releases(kernel_lock)
                                __acquires(kernel_lock)
 {
+       char *orig_data = kstrdup(data, GFP_KERNEL);
        struct buffer_head *bh;
        struct ext4_super_block *es = NULL;
        struct ext4_sb_info *sbi;
@@ -2424,8 +2516,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
        if (def_mount_opts & EXT4_DEFM_DEBUG)
                set_opt(sbi->s_mount_opt, DEBUG);
-       if (def_mount_opts & EXT4_DEFM_BSDGROUPS)
+       if (def_mount_opts & EXT4_DEFM_BSDGROUPS) {
+               ext4_msg(sb, KERN_WARNING, deprecated_msg, "bsdgroups",
+                       "2.6.38");
                set_opt(sbi->s_mount_opt, GRPID);
+       }
        if (def_mount_opts & EXT4_DEFM_UID16)
                set_opt(sbi->s_mount_opt, NO_UID32);
 #ifdef CONFIG_EXT4_FS_XATTR
@@ -2437,11 +2532,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                set_opt(sbi->s_mount_opt, POSIX_ACL);
 #endif
        if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_DATA)
-               sbi->s_mount_opt |= EXT4_MOUNT_JOURNAL_DATA;
+               set_opt(sbi->s_mount_opt, JOURNAL_DATA);
        else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_ORDERED)
-               sbi->s_mount_opt |= EXT4_MOUNT_ORDERED_DATA;
+               set_opt(sbi->s_mount_opt, ORDERED_DATA);
        else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_WBACK)
-               sbi->s_mount_opt |= EXT4_MOUNT_WRITEBACK_DATA;
+               set_opt(sbi->s_mount_opt, WRITEBACK_DATA);
 
        if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_PANIC)
                set_opt(sbi->s_mount_opt, ERRORS_PANIC);
@@ -2462,14 +2557,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
         * enable delayed allocation by default
         * Use -o nodelalloc to turn it off
         */
-       set_opt(sbi->s_mount_opt, DELALLOC);
+       if (!IS_EXT3_SB(sb))
+               set_opt(sbi->s_mount_opt, DELALLOC);
 
        if (!parse_options((char *) data, sb, &journal_devnum,
                           &journal_ioprio, NULL, 0))
                goto failed_mount;
 
        sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
-               ((sbi->s_mount_opt & EXT4_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
+               (test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0);
 
        if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV &&
            (EXT4_HAS_COMPAT_FEATURE(sb, ~0U) ||
@@ -2701,24 +2797,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        get_random_bytes(&sbi->s_next_generation, sizeof(u32));
        spin_lock_init(&sbi->s_next_gen_lock);
 
-       err = percpu_counter_init(&sbi->s_freeblocks_counter,
-                       ext4_count_free_blocks(sb));
-       if (!err) {
-               err = percpu_counter_init(&sbi->s_freeinodes_counter,
-                               ext4_count_free_inodes(sb));
-       }
-       if (!err) {
-               err = percpu_counter_init(&sbi->s_dirs_counter,
-                               ext4_count_dirs(sb));
-       }
-       if (!err) {
-               err = percpu_counter_init(&sbi->s_dirtyblocks_counter, 0);
-       }
-       if (err) {
-               ext4_msg(sb, KERN_ERR, "insufficient memory");
-               goto failed_mount3;
-       }
-
        sbi->s_stripe = ext4_get_stripe_size(sbi);
        sbi->s_max_writeback_mb_bump = 128;
 
@@ -2758,7 +2836,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
              EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) {
                ext4_msg(sb, KERN_ERR, "required journal recovery "
                       "suppressed and not mounted read-only");
-               goto failed_mount4;
+               goto failed_mount_wq;
        } else {
                clear_opt(sbi->s_mount_opt, DATA_FLAGS);
                set_opt(sbi->s_mount_opt, WRITEBACK_DATA);
@@ -2771,7 +2849,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
            !jbd2_journal_set_features(EXT4_SB(sb)->s_journal, 0, 0,
                                       JBD2_FEATURE_INCOMPAT_64BIT)) {
                ext4_msg(sb, KERN_ERR, "Failed to set 64-bit journal feature");
-               goto failed_mount4;
+               goto failed_mount_wq;
        }
 
        if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) {
@@ -2810,7 +2888,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                    (sbi->s_journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)) {
                        ext4_msg(sb, KERN_ERR, "Journal does not support "
                               "requested data journaling mode");
-                       goto failed_mount4;
+                       goto failed_mount_wq;
                }
        default:
                break;
@@ -2818,13 +2896,31 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        set_task_ioprio(sbi->s_journal->j_task, journal_ioprio);
 
 no_journal:
-
+       err = percpu_counter_init(&sbi->s_freeblocks_counter,
+                                 ext4_count_free_blocks(sb));
+       if (!err)
+               err = percpu_counter_init(&sbi->s_freeinodes_counter,
+                                         ext4_count_free_inodes(sb));
+       if (!err)
+               err = percpu_counter_init(&sbi->s_dirs_counter,
+                                         ext4_count_dirs(sb));
+       if (!err)
+               err = percpu_counter_init(&sbi->s_dirtyblocks_counter, 0);
+       if (err) {
+               ext4_msg(sb, KERN_ERR, "insufficient memory");
+               goto failed_mount_wq;
+       }
        if (test_opt(sb, NOBH)) {
                if (!(test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)) {
                        ext4_msg(sb, KERN_WARNING, "Ignoring nobh option - "
                                "its supported only with writeback mode");
                        clear_opt(sbi->s_mount_opt, NOBH);
                }
+               if (test_opt(sb, DIOREAD_NOLOCK)) {
+                       ext4_msg(sb, KERN_WARNING, "dioread_nolock option is "
+                               "not supported with nobh mode");
+                       goto failed_mount_wq;
+               }
        }
        EXT4_SB(sb)->dio_unwritten_wq = create_workqueue("ext4-dio-unwritten");
        if (!EXT4_SB(sb)->dio_unwritten_wq) {
@@ -2889,11 +2985,23 @@ no_journal:
                         "requested data journaling mode");
                clear_opt(sbi->s_mount_opt, DELALLOC);
        }
+       if (test_opt(sb, DIOREAD_NOLOCK)) {
+               if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
+                       ext4_msg(sb, KERN_WARNING, "Ignoring dioread_nolock "
+                               "option - requested data journaling mode");
+                       clear_opt(sbi->s_mount_opt, DIOREAD_NOLOCK);
+               }
+               if (sb->s_blocksize < PAGE_SIZE) {
+                       ext4_msg(sb, KERN_WARNING, "Ignoring dioread_nolock "
+                               "option - block size is too small");
+                       clear_opt(sbi->s_mount_opt, DIOREAD_NOLOCK);
+               }
+       }
 
        err = ext4_setup_system_zone(sb);
        if (err) {
                ext4_msg(sb, KERN_ERR, "failed to initialize system "
-                        "zone (%d)\n", err);
+                        "zone (%d)", err);
                goto failed_mount4;
        }
 
@@ -2932,9 +3040,11 @@ no_journal:
        } else
                descr = "out journal";
 
-       ext4_msg(sb, KERN_INFO, "mounted filesystem with%s", descr);
+       ext4_msg(sb, KERN_INFO, "mounted filesystem with%s. "
+               "Opts: %s", descr, orig_data);
 
        lock_kernel();
+       kfree(orig_data);
        return 0;
 
 cantfind_ext4:
@@ -2951,6 +3061,10 @@ failed_mount_wq:
                jbd2_journal_destroy(sbi->s_journal);
                sbi->s_journal = NULL;
        }
+       percpu_counter_destroy(&sbi->s_freeblocks_counter);
+       percpu_counter_destroy(&sbi->s_freeinodes_counter);
+       percpu_counter_destroy(&sbi->s_dirs_counter);
+       percpu_counter_destroy(&sbi->s_dirtyblocks_counter);
 failed_mount3:
        if (sbi->s_flex_groups) {
                if (is_vmalloc_addr(sbi->s_flex_groups))
@@ -2958,10 +3072,6 @@ failed_mount3:
                else
                        kfree(sbi->s_flex_groups);
        }
-       percpu_counter_destroy(&sbi->s_freeblocks_counter);
-       percpu_counter_destroy(&sbi->s_freeinodes_counter);
-       percpu_counter_destroy(&sbi->s_dirs_counter);
-       percpu_counter_destroy(&sbi->s_dirtyblocks_counter);
 failed_mount2:
        for (i = 0; i < db_count; i++)
                brelse(sbi->s_group_desc[i]);
@@ -2981,6 +3091,7 @@ out_fail:
        kfree(sbi->s_blockgroup_lock);
        kfree(sbi);
        lock_kernel();
+       kfree(orig_data);
        return ret;
 }
 
@@ -3272,7 +3383,7 @@ static int ext4_commit_super(struct super_block *sb, int sync)
        if (!(sb->s_flags & MS_RDONLY))
                es->s_wtime = cpu_to_le32(get_seconds());
        es->s_kbytes_written =
-               cpu_to_le64(EXT4_SB(sb)->s_kbytes_written + 
+               cpu_to_le64(EXT4_SB(sb)->s_kbytes_written +
                            ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) -
                              EXT4_SB(sb)->s_sectors_written_start) >> 1));
        ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
@@ -3352,10 +3463,9 @@ static void ext4_clear_journal_err(struct super_block *sb,
                char nbuf[16];
 
                errstr = ext4_decode_error(sb, j_errno, nbuf);
-               ext4_warning(sb, __func__, "Filesystem error recorded "
+               ext4_warning(sb, "Filesystem error recorded "
                             "from previous mount: %s", errstr);
-               ext4_warning(sb, __func__, "Marking fs in need of "
-                            "filesystem check.");
+               ext4_warning(sb, "Marking fs in need of filesystem check.");
 
                EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
                es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
@@ -3378,8 +3488,10 @@ int ext4_force_commit(struct super_block *sb)
                return 0;
 
        journal = EXT4_SB(sb)->s_journal;
-       if (journal)
+       if (journal) {
+               vfs_check_frozen(sb, SB_FREEZE_WRITE);
                ret = ext4_journal_force_commit(journal);
+       }
 
        return ret;
 }
@@ -3428,18 +3540,16 @@ static int ext4_freeze(struct super_block *sb)
         * the journal.
         */
        error = jbd2_journal_flush(journal);
-       if (error < 0) {
-       out:
-               jbd2_journal_unlock_updates(journal);
-               return error;
-       }
+       if (error < 0)
+               goto out;
 
        /* Journal blocked and flushed, clear needs_recovery flag. */
        EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
        error = ext4_commit_super(sb, 1);
-       if (error)
-               goto out;
-       return 0;
+out:
+       /* we rely on s_frozen to stop further updates */
+       jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+       return error;
 }
 
 /*
@@ -3456,7 +3566,6 @@ static int ext4_unfreeze(struct super_block *sb)
        EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
        ext4_commit_super(sb, 1);
        unlock_super(sb);
-       jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
        return 0;
 }
 
@@ -3473,6 +3582,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 #ifdef CONFIG_QUOTA
        int i;
 #endif
+       char *orig_data = kstrdup(data, GFP_KERNEL);
 
        lock_kernel();
 
@@ -3506,7 +3616,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                ext4_abort(sb, __func__, "Abort forced by user");
 
        sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
-               ((sbi->s_mount_opt & EXT4_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
+               (test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0);
 
        es = sbi->s_es;
 
@@ -3606,6 +3716,9 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
 #endif
        unlock_super(sb);
        unlock_kernel();
+
+       ext4_msg(sb, KERN_INFO, "re-mounted. Opts: %s", orig_data);
+       kfree(orig_data);
        return 0;
 
 restore_opts:
@@ -3627,6 +3740,7 @@ restore_opts:
 #endif
        unlock_super(sb);
        unlock_kernel();
+       kfree(orig_data);
        return err;
 }
 
@@ -3700,7 +3814,7 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
  * Process 1                         Process 2
  * ext4_create()                     quota_sync()
  *   jbd2_journal_start()                  write_dquot()
- *   vfs_dq_init()                         down(dqio_mutex)
+ *   dquot_initialize()                         down(dqio_mutex)
  *     down(dqio_mutex)                    jbd2_journal_start()
  *
  */
@@ -3909,9 +4023,7 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
        ext4_lblk_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb);
        int err = 0;
        int offset = off & (sb->s_blocksize - 1);
-       int tocopy;
        int journal_quota = EXT4_SB(sb)->s_qf_names[type] != NULL;
-       size_t towrite = len;
        struct buffer_head *bh;
        handle_t *handle = journal_current_handle();
 
@@ -3921,52 +4033,53 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
                        (unsigned long long)off, (unsigned long long)len);
                return -EIO;
        }
+       /*
+        * Since we account only one data block in transaction credits,
+        * then it is impossible to cross a block boundary.
+        */
+       if (sb->s_blocksize - offset < len) {
+               ext4_msg(sb, KERN_WARNING, "Quota write (off=%llu, len=%llu)"
+                       " cancelled because not block aligned",
+                       (unsigned long long)off, (unsigned long long)len);
+               return -EIO;
+       }
+
        mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
-       while (towrite > 0) {
-               tocopy = sb->s_blocksize - offset < towrite ?
-                               sb->s_blocksize - offset : towrite;
-               bh = ext4_bread(handle, inode, blk, 1, &err);
-               if (!bh)
+       bh = ext4_bread(handle, inode, blk, 1, &err);
+       if (!bh)
+               goto out;
+       if (journal_quota) {
+               err = ext4_journal_get_write_access(handle, bh);
+               if (err) {
+                       brelse(bh);
                        goto out;
-               if (journal_quota) {
-                       err = ext4_journal_get_write_access(handle, bh);
-                       if (err) {
-                               brelse(bh);
-                               goto out;
-                       }
-               }
-               lock_buffer(bh);
-               memcpy(bh->b_data+offset, data, tocopy);
-               flush_dcache_page(bh->b_page);
-               unlock_buffer(bh);
-               if (journal_quota)
-                       err = ext4_handle_dirty_metadata(handle, NULL, bh);
-               else {
-                       /* Always do at least ordered writes for quotas */
-                       err = ext4_jbd2_file_inode(handle, inode);
-                       mark_buffer_dirty(bh);
                }
-               brelse(bh);
-               if (err)
-                       goto out;
-               offset = 0;
-               towrite -= tocopy;
-               data += tocopy;
-               blk++;
        }
+       lock_buffer(bh);
+       memcpy(bh->b_data+offset, data, len);
+       flush_dcache_page(bh->b_page);
+       unlock_buffer(bh);
+       if (journal_quota)
+               err = ext4_handle_dirty_metadata(handle, NULL, bh);
+       else {
+               /* Always do at least ordered writes for quotas */
+               err = ext4_jbd2_file_inode(handle, inode);
+               mark_buffer_dirty(bh);
+       }
+       brelse(bh);
 out:
-       if (len == towrite) {
+       if (err) {
                mutex_unlock(&inode->i_mutex);
                return err;
        }
-       if (inode->i_size < off+len-towrite) {
-               i_size_write(inode, off+len-towrite);
+       if (inode->i_size < off + len) {
+               i_size_write(inode, off + len);
                EXT4_I(inode)->i_disksize = inode->i_size;
        }
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
        ext4_mark_inode_dirty(handle, inode);
        mutex_unlock(&inode->i_mutex);
-       return len - towrite;
+       return len;
 }
 
 #endif
@@ -3977,7 +4090,7 @@ static int ext4_get_sb(struct file_system_type *fs_type, int flags,
        return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super,mnt);
 }
 
-#if !defined(CONTIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23)
+#if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23)
 static struct file_system_type ext2_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "ext2",
@@ -4004,15 +4117,7 @@ static inline void register_as_ext2(void) { }
 static inline void unregister_as_ext2(void) { }
 #endif
 
-#if !defined(CONTIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23)
-static struct file_system_type ext3_fs_type = {
-       .owner          = THIS_MODULE,
-       .name           = "ext3",
-       .get_sb         = ext4_get_sb,
-       .kill_sb        = kill_block_super,
-       .fs_flags       = FS_REQUIRES_DEV,
-};
-
+#if !defined(CONFIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23)
 static inline void register_as_ext3(void)
 {
        int err = register_filesystem(&ext3_fs_type);
@@ -4043,6 +4148,7 @@ static int __init init_ext4_fs(void)
 {
        int err;
 
+       ext4_check_flag_values();
        err = init_ext4_system_zone();
        if (err)
                return err;