Whamcloud - gitweb
b=19625
[fs/lustre-release.git] / ldiskfs / kernel_patches / patches / ext4-ialloc-2.6-sles11.patch
diff --git a/ldiskfs/kernel_patches/patches/ext4-ialloc-2.6-sles11.patch b/ldiskfs/kernel_patches/patches/ext4-ialloc-2.6-sles11.patch
new file mode 100644 (file)
index 0000000..1423331
--- /dev/null
@@ -0,0 +1,129 @@
+Index: linux-2.6.27.21-0.1/fs/ext4/ialloc.c
+===================================================================
+--- linux-2.6.27.21-0.1.orig/fs/ext4/ialloc.c
++++ linux-2.6.27.21-0.1/fs/ext4/ialloc.c
+@@ -535,12 +535,16 @@ fallback:
+ }
+ static int find_group_other(struct super_block *sb, struct inode *parent,
+-                              ext4_group_t *group)
++                          ext4_group_t *group, int mode)
+ {
++      struct ext4_sb_info *sbi = EXT4_SB(sb);
+       ext4_group_t parent_group = EXT4_I(parent)->i_block_group;
+-      ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
++      ext4_group_t ngroups = sbi->s_groups_count;
+       struct ext4_group_desc *desc;
+       ext4_group_t i;
++      int best_group = -1;
++      ext4_fsblk_t avefreeb, freeb;
++      int best_group_freeb = 0;
+       /*
+        * Try to place the inode in its parent directory
+@@ -548,8 +552,10 @@ static int find_group_other(struct super
+       *group = parent_group;
+       desc = ext4_get_group_desc(sb, *group, NULL);
+       if (desc && ext4_free_inodes_count(sb, desc) &&
+-                      ext4_free_blks_count(sb, desc))
++          (!S_ISREG(mode) || ext4_free_blks_count(sb, desc)))
+               return 0;
++      avefreeb = ext4_free_blocks_count(sbi->s_es);
++      do_div(avefreeb, ngroups);
+       /*
+        * We're going to place this inode in a different blockgroup from its
+@@ -563,33 +569,49 @@ static int find_group_other(struct super
+       *group = (*group + parent->i_ino) % ngroups;
+       /*
+-       * Use a quadratic hash to find a group with a free inode and some free
+-       * blocks.
++       * Use a quadratic hash to find a group with a free inode and
++       * average number of free blocks.
+        */
+       for (i = 1; i < ngroups; i <<= 1) {
+               *group += i;
+               if (*group >= ngroups)
+                       *group -= ngroups;
+               desc = ext4_get_group_desc(sb, *group, NULL);
+-              if (desc && ext4_free_inodes_count(sb, desc) &&
+-                              ext4_free_blks_count(sb, desc))
++              if (!desc || ext4_free_inodes_count(sb, desc))
++                      continue;
++              if (!S_ISREG(mode))
++                      return 0;
++              if (ext4_free_blks_count(sb, desc) >= avefreeb)
+                       return 0;
+       }
+       /*
+-       * That failed: try linear search for a free inode, even if that group
+-       * has no free blocks.
++       * That failed: start from last group used to allocate inode
++       * try linear search for a free inode and prefereably
++       * free blocks.
+        */
+-      *group = parent_group;
++      *group = sbi->s_last_alloc_group;
++      if (*group == -1)
++              *group = parent_group;
++
+       for (i = 0; i < ngroups; i++) {
+               if (++*group >= ngroups)
+                       *group = 0;
+               desc = ext4_get_group_desc(sb, *group, NULL);
+-              if (desc && ext4_free_inodes_count(sb, desc))
+-                      return 0;
++              if (!desc || ext4_free_inodes_count(sb, desc))
++                      continue;
++              freeb = ext4_free_blks_count(sb, desc);
++              if (freeb > best_group_freeb) {
++                      best_group_freeb = freeb;
++                      best_group = *group;
++                      if (freeb >= avefreeb || !S_ISREG(mode))
++                              break;
++              }
+       }
+-      return -1;
++      sbi->s_last_alloc_group = best_group;
++      *group = best_group;
++      return 0;
+ }
+ /*
+@@ -755,7 +777,7 @@ continue_allocation:
+               else
+                       ret2 = find_group_orlov(sb, dir, &group);
+       } else
+-              ret2 = find_group_other(sb, dir, &group);
++              ret2 = find_group_other(sb, dir, &group, mode);
+ got_group:
+       err = -ENOSPC;
+Index: linux-2.6.27.21-0.1/fs/ext4/super.c
+===================================================================
+--- linux-2.6.27.21-0.1.orig/fs/ext4/super.c
++++ linux-2.6.27.21-0.1/fs/ext4/super.c
+@@ -2300,6 +2300,7 @@ static int ext4_fill_super(struct super_
+       bgl_lock_init(&sbi->s_blockgroup_lock);
++      sbi->s_last_alloc_group = -1;
+       for (i = 0; i < db_count; i++) {
+               block = descriptor_loc(sb, logical_sb_block, i);
+               sbi->s_group_desc[i] = sb_bread(sb, block);
+Index: linux-2.6.27.21-0.1/fs/ext4/ext4_sb.h
+===================================================================
+--- linux-2.6.27.21-0.1.orig/fs/ext4/ext4_sb.h
++++ linux-2.6.27.21-0.1/fs/ext4/ext4_sb.h
+@@ -64,6 +64,8 @@ struct ext4_sb_info {
+       struct percpu_counter s_dirtyblocks_counter;
+       struct blockgroup_lock s_blockgroup_lock;
+       struct proc_dir_entry *s_proc;
++      /* Last group used to allocate inode */
++      ext4_group_t s_last_alloc_group;
+       /* root of the per fs reservation window tree */
+       spinlock_t s_rsv_window_lock;