]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] ext2/3: better starting group for S_ISREG files
authorAndrew Morton <akpm@digeo.com>
Sat, 21 Dec 2002 09:07:46 +0000 (01:07 -0800)
committerLinus Torvalds <torvalds@home.transmeta.com>
Sat, 21 Dec 2002 09:07:46 +0000 (01:07 -0800)
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.

fs/ext2/ialloc.c
fs/ext3/ialloc.c

index 27e7584c90f308cd663d27d93f26da324ca91df3..bb02b848b77f537e07b50771fd1fd8b0c6bccd70 100644 (file)
@@ -388,24 +388,38 @@ static int find_group_other(struct super_block *sb, struct inode *parent)
         */
        group = parent_group;
        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;
 
        /*
-        * Use a quadratic hash to find a group with a
-        * free inode
+        * We're going to place this inode in a different blockgroup from its
+        * 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) {
                group += i;
                if (group >= ngroups)
                        group -= ngroups;
                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;
        }
 
        /*
-        * 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;
        for (i = 2; i < ngroups; i++) {
index cc1dff50df0f062c21dea051f05abb3c77f9cc01..377e6ba931e9ce54cfc0cea5803b61e9081403a3 100644 (file)
@@ -356,24 +356,38 @@ static int find_group_other(struct super_block *sb, struct inode *parent)
         */
        group = parent_group;
        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;
 
        /*
-        * Use a quadratic hash to find a group with a
-        * free inode
+        * We're going to place this inode in a different blockgroup from its
+        * 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) {
                group += i;
                if (group >= ngroups)
                        group -= ngroups;
                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;
        }
 
        /*
-        * 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;
        for (i = 2; i < ngroups; i++) {