Commit 1cdf4231 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] ext2/3: better starting group for S_ISREG files

ext2 places non-directory objects into the same blockgroup as their
directory, as long as that directory has free inodes.  It does this
even if there are no free blocks in that blockgroup (!).

This means that if there are lots of files being created at a common
point in the tree, they _all_ have the same starting blockgroup.  For
each file we do a big search forwards for the first block and the
allocations end up getting intermingled.

So this patch will avoid placing new inodes in block groups which have
no free blocks.

So far so good.  But this means that if a lot of new files are being
created under a directory (or multiple directories) which are in the
same blockgroup, all the new inodes will overflow into the same
blockgroup.  No improvement at all.

So the patch arranges for the new inode locations to be "spread out"
across different blockgroups if they are not going to be placed in
their directory's block group.  This is done by adding parent->i_ino
into the starting point for the quadratic hash.  i_ino was chosen so
that files which are in the same directory will tend to all land in the
same new blockgroup.
parent 61432dbc
...@@ -388,24 +388,38 @@ static int find_group_other(struct super_block *sb, struct inode *parent) ...@@ -388,24 +388,38 @@ static int find_group_other(struct super_block *sb, struct inode *parent)
*/ */
group = parent_group; group = parent_group;
desc = ext2_get_group_desc (sb, group, &bh); desc = ext2_get_group_desc (sb, group, &bh);
if (desc && le16_to_cpu(desc->bg_free_inodes_count)) if (desc && le16_to_cpu(desc->bg_free_inodes_count) &&
le16_to_cpu(desc->bg_free_blocks_count))
goto found; goto found;
/* /*
* Use a quadratic hash to find a group with a * We're going to place this inode in a different blockgroup from its
* free inode * parent. We want to cause files in a common directory to all land in
* the same blockgroup. But we want files which are in a different
* directory which shares a blockgroup with our parent to land in a
* different blockgroup.
*
* So add our directory's i_ino into the starting point for the hash.
*/
group = (group + parent->i_ino) % ngroups;
/*
* Use a quadratic hash to find a group with a free inode and some
* free blocks.
*/ */
for (i = 1; i < ngroups; i <<= 1) { for (i = 1; i < ngroups; i <<= 1) {
group += i; group += i;
if (group >= ngroups) if (group >= ngroups)
group -= ngroups; group -= ngroups;
desc = ext2_get_group_desc (sb, group, &bh); desc = ext2_get_group_desc (sb, group, &bh);
if (desc && le16_to_cpu(desc->bg_free_inodes_count)) if (desc && le16_to_cpu(desc->bg_free_inodes_count) &&
le16_to_cpu(desc->bg_free_blocks_count))
goto found; goto found;
} }
/* /*
* That failed: try linear search for a free inode * That failed: try linear search for a free inode, even if that group
* has no free blocks.
*/ */
group = parent_group + 1; group = parent_group + 1;
for (i = 2; i < ngroups; i++) { for (i = 2; i < ngroups; i++) {
......
...@@ -356,24 +356,38 @@ static int find_group_other(struct super_block *sb, struct inode *parent) ...@@ -356,24 +356,38 @@ static int find_group_other(struct super_block *sb, struct inode *parent)
*/ */
group = parent_group; group = parent_group;
desc = ext3_get_group_desc (sb, group, &bh); desc = ext3_get_group_desc (sb, group, &bh);
if (desc && le16_to_cpu(desc->bg_free_inodes_count)) if (desc && le16_to_cpu(desc->bg_free_inodes_count) &&
le16_to_cpu(desc->bg_free_blocks_count))
return group; return group;
/* /*
* Use a quadratic hash to find a group with a * We're going to place this inode in a different blockgroup from its
* free inode * parent. We want to cause files in a common directory to all land in
* the same blockgroup. But we want files which are in a different
* directory which shares a blockgroup with our parent to land in a
* different blockgroup.
*
* So add our directory's i_ino into the starting point for the hash.
*/
group = (group + parent->i_ino) % ngroups;
/*
* Use a quadratic hash to find a group with a free inode and some free
* blocks.
*/ */
for (i = 1; i < ngroups; i <<= 1) { for (i = 1; i < ngroups; i <<= 1) {
group += i; group += i;
if (group >= ngroups) if (group >= ngroups)
group -= ngroups; group -= ngroups;
desc = ext3_get_group_desc (sb, group, &bh); desc = ext3_get_group_desc (sb, group, &bh);
if (desc && le16_to_cpu(desc->bg_free_inodes_count)) if (desc && le16_to_cpu(desc->bg_free_inodes_count) &&
le16_to_cpu(desc->bg_free_blocks_count))
return group; return group;
} }
/* /*
* That failed: try linear search for a free inode * That failed: try linear search for a free inode, even if that group
* has no free blocks.
*/ */
group = parent_group + 1; group = parent_group + 1;
for (i = 2; i < ngroups; i++) { for (i = 2; i < ngroups; i++) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment