]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/ext4/super.c
ext4: Enable delalloc by default.
[linux-2.6-omap-h63xx.git] / fs / ext4 / super.c
index 09d9359c80550a66654653b0993c30117b9f0865..4e104dd0ec212124b42da43c5ae08ebe62f663f7 100644 (file)
@@ -506,6 +506,7 @@ static void ext4_put_super (struct super_block * sb)
        ext4_ext_release(sb);
        ext4_xattr_put_super(sb);
        jbd2_journal_destroy(sbi->s_journal);
+       sbi->s_journal = NULL;
        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);
@@ -517,6 +518,7 @@ static void ext4_put_super (struct super_block * sb)
        for (i = 0; i < sbi->s_gdb_count; i++)
                brelse(sbi->s_group_desc[i]);
        kfree(sbi->s_group_desc);
+       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);
@@ -571,6 +573,12 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
        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);
+       jbd2_journal_init_jbd_inode(&ei->jinode, &ei->vfs_inode);
+       ei->i_reserved_data_blocks = 0;
+       ei->i_reserved_meta_blocks = 0;
+       ei->i_allocated_meta_blocks = 0;
+       ei->i_delalloc_reserved_flag = 0;
+       spin_lock_init(&(ei->i_block_reservation_lock));
        return &ei->vfs_inode;
 }
 
@@ -635,6 +643,8 @@ static void ext4_clear_inode(struct inode *inode)
        EXT4_I(inode)->i_block_alloc_info = NULL;
        if (unlikely(rsv))
                kfree(rsv);
+       jbd2_journal_release_jbd_inode(EXT4_SB(inode->i_sb)->s_journal,
+                                      &EXT4_I(inode)->jinode);
 }
 
 static inline void ext4_show_quota_options(struct seq_file *seq, struct super_block *sb)
@@ -729,8 +739,15 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
                seq_printf(seq, ",commit=%u",
                           (unsigned) (sbi->s_commit_interval / HZ));
        }
-       if (test_opt(sb, BARRIER))
-               seq_puts(seq, ",barrier=1");
+       /*
+        * 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");
        if (test_opt(sb, NOBH))
                seq_puts(seq, ",nobh");
        if (!test_opt(sb, EXTENTS))
@@ -739,6 +756,9 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
                seq_puts(seq, ",nomballoc");
        if (test_opt(sb, I_VERSION))
                seq_puts(seq, ",i_version");
+       if (!test_opt(sb, DELALLOC))
+               seq_puts(seq, ",nodelalloc");
+
 
        if (sbi->s_stripe)
                seq_printf(seq, ",stripe=%lu", sbi->s_stripe);
@@ -886,7 +906,7 @@ enum {
        Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
        Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
        Opt_grpquota, Opt_extents, Opt_noextents, Opt_i_version,
-       Opt_mballoc, Opt_nomballoc, Opt_stripe,
+       Opt_mballoc, Opt_nomballoc, Opt_stripe, Opt_delalloc, Opt_nodelalloc,
 };
 
 static match_table_t tokens = {
@@ -945,6 +965,8 @@ static match_table_t tokens = {
        {Opt_nomballoc, "nomballoc"},
        {Opt_stripe, "stripe=%u"},
        {Opt_resize, "resize"},
+       {Opt_delalloc, "delalloc"},
+       {Opt_nodelalloc, "nodelalloc"},
        {Opt_err, NULL},
 };
 
@@ -1310,6 +1332,9 @@ set_qf_format:
                        set_opt(sbi->s_mount_opt, I_VERSION);
                        sb->s_flags |= MS_I_VERSION;
                        break;
+               case Opt_nodelalloc:
+                       clear_opt(sbi->s_mount_opt, DELALLOC);
+                       break;
                case Opt_mballoc:
                        set_opt(sbi->s_mount_opt, MBALLOC);
                        break;
@@ -1323,6 +1348,9 @@ set_qf_format:
                                return 0;
                        sbi->s_stripe = option;
                        break;
+               case Opt_delalloc:
+                       set_opt(sbi->s_mount_opt, DELALLOC);
+                       break;
                default:
                        printk (KERN_ERR
                                "EXT4-fs: Unrecognized mount option \"%s\" "
@@ -1435,6 +1463,54 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
        return res;
 }
 
+static int ext4_fill_flex_info(struct super_block *sb)
+{
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
+       struct ext4_group_desc *gdp = NULL;
+       struct buffer_head *bh;
+       ext4_group_t flex_group_count;
+       ext4_group_t flex_group;
+       int groups_per_flex = 0;
+       __u64 block_bitmap = 0;
+       int i;
+
+       if (!sbi->s_es->s_log_groups_per_flex) {
+               sbi->s_log_groups_per_flex = 0;
+               return 1;
+       }
+
+       sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex;
+       groups_per_flex = 1 << sbi->s_log_groups_per_flex;
+
+       flex_group_count = (sbi->s_groups_count + groups_per_flex - 1) /
+               groups_per_flex;
+       sbi->s_flex_groups = kmalloc(flex_group_count *
+                                    sizeof(struct flex_groups), GFP_KERNEL);
+       if (sbi->s_flex_groups == NULL) {
+               printk(KERN_ERR "EXT4-fs: not enough memory\n");
+               goto failed;
+       }
+       memset(sbi->s_flex_groups, 0, flex_group_count *
+              sizeof(struct flex_groups));
+
+       gdp = ext4_get_group_desc(sb, 1, &bh);
+       block_bitmap = ext4_block_bitmap(sb, gdp) - 1;
+
+       for (i = 0; i < sbi->s_groups_count; i++) {
+               gdp = ext4_get_group_desc(sb, i, &bh);
+
+               flex_group = ext4_flex_group(sbi, i);
+               sbi->s_flex_groups[flex_group].free_inodes +=
+                       le16_to_cpu(gdp->bg_free_inodes_count);
+               sbi->s_flex_groups[flex_group].free_blocks +=
+                       le16_to_cpu(gdp->bg_free_blocks_count);
+       }
+
+       return 1;
+failed:
+       return 0;
+}
+
 __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group,
                            struct ext4_group_desc *gdp)
 {
@@ -1802,8 +1878,8 @@ static unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi)
 }
 
 static int ext4_fill_super (struct super_block *sb, void *data, int silent)
-                               __releases(kernel_sem)
-                               __acquires(kernel_sem)
+                               __releases(kernel_lock)
+                               __acquires(kernel_lock)
 
 {
        struct buffer_head * bh;
@@ -1843,11 +1919,6 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
                goto out_fail;
        }
 
-       if (!sb_set_blocksize(sb, blocksize)) {
-               printk(KERN_ERR "EXT4-fs: bad blocksize %d.\n", blocksize);
-               goto out_fail;
-       }
-
        /*
         * The ext4 superblock will not be buffer aligned for other than 1kB
         * block sizes.  We need to calculate the offset from buffer start.
@@ -1907,6 +1978,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
        sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
 
        set_opt(sbi->s_mount_opt, RESERVATION);
+       set_opt(sbi->s_mount_opt, BARRIER);
 
        /*
         * turn on extents feature by default in ext4 filesystem
@@ -1919,6 +1991,13 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
         */
        set_opt(sbi->s_mount_opt, MBALLOC);
 
+       /*
+        * enable delayed allocation by default
+        * Use -o nodelalloc to turn it off
+        */
+       set_opt(sbi->s_mount_opt, DELALLOC);
+
+
        if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum,
                            NULL, 0))
                goto failed_mount;
@@ -2129,6 +2208,14 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
                printk(KERN_ERR "EXT4-fs: group descriptors corrupted!\n");
                goto failed_mount2;
        }
+       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG))
+               if (!ext4_fill_flex_info(sb)) {
+                       printk(KERN_ERR
+                              "EXT4-fs: unable to initialize "
+                              "flex_bg meta info!\n");
+                       goto failed_mount2;
+               }
+
        sbi->s_gdb_count = db_count;
        get_random_bytes(&sbi->s_next_generation, sizeof(u32));
        spin_lock_init(&sbi->s_next_gen_lock);
@@ -2189,6 +2276,29 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
            EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) {
                if (ext4_load_journal(sb, es, journal_devnum))
                        goto failed_mount3;
+               if (!(sb->s_flags & MS_RDONLY) &&
+                   EXT4_SB(sb)->s_journal->j_failed_commit) {
+                       printk(KERN_CRIT "EXT4-fs error (device %s): "
+                              "ext4_fill_super: Journal transaction "
+                              "%u is corrupt\n", sb->s_id, 
+                              EXT4_SB(sb)->s_journal->j_failed_commit);
+                       if (test_opt (sb, ERRORS_RO)) {
+                               printk (KERN_CRIT
+                                       "Mounting filesystem read-only\n");
+                               sb->s_flags |= MS_RDONLY;
+                               EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
+                               es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
+                       }
+                       if (test_opt(sb, ERRORS_PANIC)) {
+                               EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
+                               es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
+                               ext4_commit_super(sb, es, 1);
+                               printk(KERN_CRIT
+                                      "EXT4-fs (device %s): mount failed\n",
+                                     sb->s_id);
+                               goto failed_mount4;
+                       }
+               }
        } else if (journal_inum) {
                if (ext4_create_journal(sb, es, journal_inum))
                        goto failed_mount3;
@@ -2326,6 +2436,13 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
                test_opt(sb,DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA ? "ordered":
                "writeback");
 
+       if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
+               printk(KERN_WARNING "EXT4-fs: Ignoring delalloc option - "
+                               "requested data journaling mode\n");
+               clear_opt(sbi->s_mount_opt, DELALLOC);
+       } else if (test_opt(sb, DELALLOC))
+               printk(KERN_INFO "EXT4-fs: delayed allocation enabled\n");
+
        ext4_ext_init(sb);
        ext4_mb_init(sb, needs_recovery);
 
@@ -2340,6 +2457,7 @@ cantfind_ext4:
 
 failed_mount4:
        jbd2_journal_destroy(sbi->s_journal);
+       sbi->s_journal = NULL;
 failed_mount3:
        percpu_counter_destroy(&sbi->s_freeblocks_counter);
        percpu_counter_destroy(&sbi->s_freeinodes_counter);
@@ -3293,7 +3411,7 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
                        err = ext4_journal_dirty_metadata(handle, bh);
                else {
                        /* Always do at least ordered writes for quotas */
-                       err = ext4_journal_dirty_data(handle, bh);
+                       err = ext4_jbd2_file_inode(handle, inode);
                        mark_buffer_dirty(bh);
                }
                brelse(bh);
@@ -3305,8 +3423,10 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
                blk++;
        }
 out:
-       if (len == towrite)
+       if (len == towrite) {
+               mutex_unlock(&inode->i_mutex);
                return err;
+       }
        if (inode->i_size < off+len-towrite) {
                i_size_write(inode, off+len-towrite);
                EXT4_I(inode)->i_disksize = inode->i_size;