From Alex Tomas.

Fix a lockup wherein the inode allocation code will loop around thinking that
a blockgroup has a free block, then finding that it didn't, then reselecting
the same blockgroup.


 fs/ext3/ialloc.c |   84 +++++++++++++++++++++++++++++--------------------------
 1 files changed, 45 insertions(+), 39 deletions(-)

diff -puN fs/ext3/ialloc.c~ext3-concurrent-block-inode-allocation-fix fs/ext3/ialloc.c
--- 25/fs/ext3/ialloc.c~ext3-concurrent-block-inode-allocation-fix	2003-05-29 10:48:00.000000000 -0700
+++ 25-akpm/fs/ext3/ialloc.c	2003-05-29 11:39:15.000000000 -0700
@@ -426,14 +426,15 @@ struct inode *ext3_new_inode(handle_t *h
 	struct buffer_head *bitmap_bh = NULL;
 	struct buffer_head *bh2;
 	int group;
-	unsigned long ino;
+	unsigned long ino = 0;
 	struct inode * inode;
-	struct ext3_group_desc * gdp;
+	struct ext3_group_desc * gdp = NULL;
 	struct ext3_super_block * es;
 	struct ext3_inode_info *ei;
 	struct ext3_sb_info *sbi;
 	int err = 0;
 	struct inode *ret;
+	int i;
 
 	/* Cannot create files in a deleted directory */
 	if (!dir || !dir->i_nlink)
@@ -447,7 +448,6 @@ struct inode *ext3_new_inode(handle_t *h
 
 	es = EXT3_SB(sb)->s_es;
 	sbi = EXT3_SB(sb);
-repeat:
 	if (S_ISDIR(mode)) {
 		if (test_opt (sb, OLDALLOC))
 			group = find_group_dir(sb, dir);
@@ -460,46 +460,52 @@ repeat:
 	if (group == -1)
 		goto out;
 
-	err = -EIO;
-	brelse(bitmap_bh);
-	bitmap_bh = read_inode_bitmap(sb, group);
-	if (!bitmap_bh)
-		goto fail;
-	gdp = ext3_get_group_desc (sb, group, &bh2);
-
-	if ((ino = ext3_find_first_zero_bit((unsigned long *)bitmap_bh->b_data,
-				      EXT3_INODES_PER_GROUP(sb))) <
-	    EXT3_INODES_PER_GROUP(sb)) {
-		BUFFER_TRACE(bitmap_bh, "get_write_access");
-		err = ext3_journal_get_write_access(handle, bitmap_bh);
-		if (err) goto fail;
-
-		if (ext3_set_bit_atomic(sb_bgl_lock(sbi, group),
-						ino, bitmap_bh->b_data)) 
-			goto repeat;
-		BUFFER_TRACE(bitmap_bh, "call ext3_journal_dirty_metadata");
-		err = ext3_journal_dirty_metadata(handle, bitmap_bh);
-		if (err) goto fail;
-	} else {
-		if (le16_to_cpu(gdp->bg_free_inodes_count) != 0) {
-			ext3_error (sb, "ext3_new_inode",
-				    "Free inodes count corrupted in group %d",
-				    group);
-			/* Is it really ENOSPC? */
-			err = -ENOSPC;
-			if (sb->s_flags & MS_RDONLY)
+	for (i = 0; i < sbi->s_groups_count; i++) {
+		gdp = ext3_get_group_desc(sb, group, &bh2);
+		
+		err = -EIO;
+		brelse(bitmap_bh);
+		bitmap_bh = read_inode_bitmap(sb, group);
+		if (!bitmap_bh)
+			goto fail;
+		
+		ino = ext3_find_first_zero_bit((unsigned long *)
+				bitmap_bh->b_data, EXT3_INODES_PER_GROUP(sb));
+		if (ino < EXT3_INODES_PER_GROUP(sb)) {
+			BUFFER_TRACE(bitmap_bh, "get_write_access");
+			err = ext3_journal_get_write_access(handle, bitmap_bh);
+			if (err)
 				goto fail;
 
-			BUFFER_TRACE(bh2, "get_write_access");
-			err = ext3_journal_get_write_access(handle, bh2);
-			if (err) goto fail;
-			gdp->bg_free_inodes_count = 0;
-			BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata");
-			err = ext3_journal_dirty_metadata(handle, bh2);
-			if (err) goto fail;
+			if (!ext3_set_bit_atomic(sb_bgl_lock(sbi, group),
+						ino, bitmap_bh->b_data)) {
+				/* we won it */
+				BUFFER_TRACE(bitmap_bh,
+					"call ext3_journal_dirty_metadata");
+				err = ext3_journal_dirty_metadata(handle,
+								bitmap_bh);
+				if (err)
+					goto fail;
+				goto got;
+			}
+			/* we lost it */
+			journal_release_buffer(handle, bitmap_bh);
 		}
-		goto repeat;
+
+		/*
+		 * This case is possible in concurrent environment.  It is very
+		 * rare.  We cannot repeat the find_group_xxx() call because
+		 * that will simply return the same blockgroup, because the
+		 * group descriptor metadata has not yet been updated.
+		 * So we just go onto the next blockgroup.
+		 */
+		if (++group == sbi->s_groups_count)
+			group = 0;
 	}
+	err = -ENOSPC;
+	goto out;
+
+got:
 	ino += group * EXT3_INODES_PER_GROUP(sb) + 1;
 	if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {
 		ext3_error (sb, "ext3_new_inode",

_