1 Index: linux-2.6.27.21-0.1/fs/ext4/ialloc.c
2 ===================================================================
3 --- linux-2.6.27.21-0.1.orig/fs/ext4/ialloc.c
4 +++ linux-2.6.27.21-0.1/fs/ext4/ialloc.c
5 @@ -535,12 +535,16 @@ fallback:
8 static int find_group_other(struct super_block *sb, struct inode *parent,
10 + ext4_group_t *group, int mode)
12 + struct ext4_sb_info *sbi = EXT4_SB(sb);
13 ext4_group_t parent_group = EXT4_I(parent)->i_block_group;
14 - ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
15 + ext4_group_t ngroups = sbi->s_groups_count;
16 struct ext4_group_desc *desc;
18 + int best_group = -1;
19 + ext4_fsblk_t avefreeb, freeb;
20 + int best_group_freeb = 0;
23 * Try to place the inode in its parent directory
24 @@ -548,8 +552,10 @@ static int find_group_other(struct super
25 *group = parent_group;
26 desc = ext4_get_group_desc(sb, *group, NULL);
27 if (desc && ext4_free_inodes_count(sb, desc) &&
28 - ext4_free_blks_count(sb, desc))
29 + (!S_ISREG(mode) || ext4_free_blks_count(sb, desc)))
31 + avefreeb = ext4_free_blocks_count(sbi->s_es);
32 + do_div(avefreeb, ngroups);
35 * We're going to place this inode in a different blockgroup from its
36 @@ -563,33 +569,49 @@ static int find_group_other(struct super
37 *group = (*group + parent->i_ino) % ngroups;
40 - * Use a quadratic hash to find a group with a free inode and some free
42 + * Use a quadratic hash to find a group with a free inode and
43 + * average number of free blocks.
45 for (i = 1; i < ngroups; i <<= 1) {
47 if (*group >= ngroups)
49 desc = ext4_get_group_desc(sb, *group, NULL);
50 - if (desc && ext4_free_inodes_count(sb, desc) &&
51 - ext4_free_blks_count(sb, desc))
52 + if (!desc || ext4_free_inodes_count(sb, desc))
56 + if (ext4_free_blks_count(sb, desc) >= avefreeb)
61 - * That failed: try linear search for a free inode, even if that group
62 - * has no free blocks.
63 + * That failed: start from last group used to allocate inode
64 + * try linear search for a free inode and prefereably
67 - *group = parent_group;
68 + *group = sbi->s_last_alloc_group;
70 + *group = parent_group;
72 for (i = 0; i < ngroups; i++) {
73 if (++*group >= ngroups)
75 desc = ext4_get_group_desc(sb, *group, NULL);
76 - if (desc && ext4_free_inodes_count(sb, desc))
78 + if (!desc || ext4_free_inodes_count(sb, desc))
80 + freeb = ext4_free_blks_count(sb, desc);
81 + if (freeb > best_group_freeb) {
82 + best_group_freeb = freeb;
83 + best_group = *group;
84 + if (freeb >= avefreeb || !S_ISREG(mode))
90 + sbi->s_last_alloc_group = best_group;
91 + *group = best_group;
96 @@ -755,7 +777,7 @@ continue_allocation:
98 ret2 = find_group_orlov(sb, dir, &group);
100 - ret2 = find_group_other(sb, dir, &group);
101 + ret2 = find_group_other(sb, dir, &group, mode);
105 Index: linux-2.6.27.21-0.1/fs/ext4/super.c
106 ===================================================================
107 --- linux-2.6.27.21-0.1.orig/fs/ext4/super.c
108 +++ linux-2.6.27.21-0.1/fs/ext4/super.c
109 @@ -2300,6 +2300,7 @@ static int ext4_fill_super(struct super_
111 bgl_lock_init(&sbi->s_blockgroup_lock);
113 + sbi->s_last_alloc_group = -1;
114 for (i = 0; i < db_count; i++) {
115 block = descriptor_loc(sb, logical_sb_block, i);
116 sbi->s_group_desc[i] = sb_bread(sb, block);
117 Index: linux-2.6.27.21-0.1/fs/ext4/ext4_sb.h
118 ===================================================================
119 --- linux-2.6.27.21-0.1.orig/fs/ext4/ext4_sb.h
120 +++ linux-2.6.27.21-0.1/fs/ext4/ext4_sb.h
121 @@ -64,6 +64,8 @@ struct ext4_sb_info {
122 struct percpu_counter s_dirtyblocks_counter;
123 struct blockgroup_lock s_blockgroup_lock;
124 struct proc_dir_entry *s_proc;
125 + /* Last group used to allocate inode */
126 + ext4_group_t s_last_alloc_group;
128 /* root of the per fs reservation window tree */
129 spinlock_t s_rsv_window_lock;