]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] ext2/ext3 -ENOSPC bug
authorAndrew Morton <akpm@osdl.org>
Sat, 6 Mar 2004 16:50:11 +0000 (08:50 -0800)
committerJaroslav Kysela <perex@suse.cz>
Sat, 6 Mar 2004 16:50:11 +0000 (08:50 -0800)
From: Chris Mason <mason@suse.com>

find_group_other looks buggy for ext2 and ext3 in 2.6, it can cause -ENOSPC
errors when the fs has plenty of free room.

To hit the bug, you need a filesystem where:

parent_group has no free blocks (but might have free inodes) Every other
group with free inodes has no free blocks.

That gets you down to the final linear search in find_group_other.  The
linear search has two bugs:

group = parent_group + 1; means we start searching at parent_group + 2
because the loop increments group before using it.

for(i = 2 ; i < ngroups ; i++) means we don't search through all the
groups.

The end result is that parent_group and parent_group + 1 are not checked
for free inodes in the final linear search.  ext3 has the same problem.

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

index df5eb0b299dd52d2a3926fbb446f383a783de8e0..b03d3e01d3cf971259dbfff83b51ff03eae32af0 100644 (file)
@@ -431,8 +431,8 @@ static int find_group_other(struct super_block *sb, struct inode *parent)
         * 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++) {
+       group = parent_group;
+       for (i = 0; i < ngroups; i++) {
                if (++group >= ngroups)
                        group = 0;
                desc = ext2_get_group_desc (sb, group, &bh);
index c0c206fea39160219fe0abe8296532dd120dae0b..307e325e642f87755dc1a052cd0a64e21e6047d1 100644 (file)
@@ -398,8 +398,8 @@ static int find_group_other(struct super_block *sb, struct inode *parent)
         * 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++) {
+       group = parent_group;
+       for (i = 0; i < ngroups; i++) {
                if (++group >= ngroups)
                        group = 0;
                desc = ext3_get_group_desc (sb, group, &bh);