Fix a couple of problems which were introduced by a recent race fix in the
ext2 block allocator:

- if the allocation attempt raced, and lost the race then a new attempt is
  made.  But the earlier reservation must be put back first.

  Add a call to group_release_blocks() to fix this.

- if the filesystem is genuinely corrupted then the code as-is can get
  stuck in an infinite loop, thinking that a blockgroup has free blocks and
  then discovering that its bitmap is full.

  Fix this by baling out after having scanned all blockgroups twice.

  (Thanks Muli Ben-Yehuda <mulix@mulix.org> for spotting this).


 fs/ext2/balloc.c |   19 ++++++++++++++++---
 1 files changed, 16 insertions(+), 3 deletions(-)

diff -puN fs/ext2/balloc.c~ext2-block-allocator-fixes fs/ext2/balloc.c
--- 25/fs/ext2/balloc.c~ext2-block-allocator-fixes	2003-11-10 12:24:12.000000000 -0800
+++ 25-akpm/fs/ext2/balloc.c	2003-11-10 12:42:36.000000000 -0800
@@ -331,7 +331,7 @@ int ext2_new_block(struct inode *inode, 
 	struct ext2_group_desc *desc;
 	int group_no;			/* i */
 	int ret_block;			/* j */
-	int bit;			/* k */
+	int group_idx;			/* k */
 	int target_block;		/* tmp */
 	int block = 0;
 	struct super_block *sb = inode->i_sb;
@@ -340,6 +340,7 @@ int ext2_new_block(struct inode *inode, 
 	unsigned group_size = EXT2_BLOCKS_PER_GROUP(sb);
 	unsigned prealloc_goal = es->s_prealloc_blocks;
 	unsigned group_alloc = 0, es_alloc, dq_alloc;
+	int nr_scanned_groups;
 
 	if (!prealloc_goal--)
 		prealloc_goal = EXT2_DEFAULT_PREALLOC_BLOCKS - 1;
@@ -402,9 +403,10 @@ int ext2_new_block(struct inode *inode, 
 	 * Now search the rest of the groups.  We assume that 
 	 * i and desc correctly point to the last group visited.
 	 */
+	nr_scanned_groups = 0;
 retry:
-	for (bit = 0; !group_alloc &&
-			bit < sbi->s_groups_count; bit++) {
+	for (group_idx = 0; !group_alloc &&
+			group_idx < sbi->s_groups_count; group_idx++) {
 		group_no++;
 		if (group_no >= sbi->s_groups_count)
 			group_no = 0;
@@ -427,9 +429,20 @@ retry:
 				group_size, 0);
 	if (ret_block < 0) {
 		/*
+		 * If a free block counter is corrupted we can loop inifintely.
+		 * Detect that here.
+		 */
+		nr_scanned_groups++;
+		if (nr_scanned_groups > 2 * sbi->s_groups_count) {
+			ext2_error(sb, "ext2_new_block",
+				"corrupted free blocks counters");
+			goto io_error;
+		}
+		/*
 		 * Someone else grabbed the last free block in this blockgroup
 		 * before us.  Retry the scan.
 		 */
+		group_release_blocks(sb, group_no, desc, gdp_bh, group_alloc);
 		group_alloc = 0;
 		goto retry;
 	}

_