ext4: Avoid updating the inode table bh twice in no journal mode
[safe/jmp/linux-2.6] / fs / ext4 / super.c
index 04c6933..f095c60 100644 (file)
@@ -45,6 +45,7 @@
 #include "ext4_jbd2.h"
 #include "xattr.h"
 #include "acl.h"
+#include "mballoc.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/ext4.h>
@@ -579,6 +580,9 @@ static void ext4_put_super(struct super_block *sb)
        struct ext4_super_block *es = sbi->s_es;
        int i, err;
 
+       flush_workqueue(sbi->dio_unwritten_wq);
+       destroy_workqueue(sbi->dio_unwritten_wq);
+
        lock_super(sb);
        lock_kernel();
        if (sb->s_dirt)
@@ -683,6 +687,8 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
        ei->i_allocated_meta_blocks = 0;
        ei->i_delalloc_reserved_flag = 0;
        spin_lock_init(&(ei->i_block_reservation_lock));
+       INIT_LIST_HEAD(&ei->i_aio_dio_complete_list);
+       ei->cur_aio_dio = NULL;
 
        return &ei->vfs_inode;
 }
@@ -963,7 +969,7 @@ static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
 static ssize_t ext4_quota_write(struct super_block *sb, int type,
                                const char *data, size_t len, loff_t off);
 
-static struct dquot_operations ext4_quota_operations = {
+static const struct dquot_operations ext4_quota_operations = {
        .initialize     = dquot_initialize,
        .drop           = dquot_drop,
        .alloc_space    = dquot_alloc_space,
@@ -984,7 +990,7 @@ static struct dquot_operations ext4_quota_operations = {
        .destroy_dquot  = dquot_destroy,
 };
 
-static struct quotactl_ops ext4_qctl_operations = {
+static const struct quotactl_ops ext4_qctl_operations = {
        .quota_on       = ext4_quota_on,
        .quota_off      = vfs_quota_off,
        .quota_sync     = vfs_quota_sync,
@@ -2196,6 +2202,7 @@ EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan);
 EXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs);
 EXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request);
 EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc);
+EXT4_RW_ATTR_SBI_UI(max_writeback_mb_bump, s_max_writeback_mb_bump);
 
 static struct attribute *ext4_attrs[] = {
        ATTR_LIST(delayed_allocation_blocks),
@@ -2209,6 +2216,7 @@ static struct attribute *ext4_attrs[] = {
        ATTR_LIST(mb_order2_req),
        ATTR_LIST(mb_stream_req),
        ATTR_LIST(mb_group_prealloc),
+       ATTR_LIST(max_writeback_mb_bump),
        NULL,
 };
 
@@ -2615,6 +2623,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                goto failed_mount;
        }
        sbi->s_groups_count = blocks_count;
+       sbi->s_blockfile_groups = min_t(ext4_group_t, sbi->s_groups_count,
+                       (EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb)));
        db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) /
                   EXT4_DESC_PER_BLOCK(sb);
        sbi->s_group_desc = kmalloc(db_count * sizeof(struct buffer_head *),
@@ -2676,6 +2686,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        sbi->s_stripe = ext4_get_stripe_size(sbi);
+       sbi->s_max_writeback_mb_bump = 128;
 
        /*
         * set up enough so that it can read an inode
@@ -2795,6 +2806,12 @@ no_journal:
                        clear_opt(sbi->s_mount_opt, NOBH);
                }
        }
+       EXT4_SB(sb)->dio_unwritten_wq = create_workqueue("ext4-dio-unwritten");
+       if (!EXT4_SB(sb)->dio_unwritten_wq) {
+               printk(KERN_ERR "EXT4-fs: failed to create DIO workqueue\n");
+               goto failed_mount_wq;
+       }
+
        /*
         * The jbd2_journal_load will have done any necessary log recovery,
         * so we can safely mount the rest of the filesystem now.
@@ -2907,6 +2924,8 @@ cantfind_ext4:
 
 failed_mount4:
        ext4_msg(sb, KERN_ERR, "mount failed");
+       destroy_workqueue(EXT4_SB(sb)->dio_unwritten_wq);
+failed_mount_wq:
        ext4_release_system_zone(sb);
        if (sbi->s_journal) {
                jbd2_journal_destroy(sbi->s_journal);
@@ -3358,11 +3377,13 @@ static int ext4_sync_fs(struct super_block *sb, int wait)
 {
        int ret = 0;
        tid_t target;
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
 
        trace_ext4_sync_fs(sb, wait);
-       if (jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, &target)) {
+       flush_workqueue(sbi->dio_unwritten_wq);
+       if (jbd2_journal_start_commit(sbi->s_journal, &target)) {
                if (wait)
-                       jbd2_log_wait_commit(EXT4_SB(sb)->s_journal, target);
+                       jbd2_log_wait_commit(sbi->s_journal, target);
        }
        return ret;
 }