From a9bca0184042b03b80a0514d015f20b9425eeea9 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 18 Nov 2003 08:16:07 -0800 Subject: [PATCH] [PATCH] ext2 block allocator fixes 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 for spotting this). --- fs/ext2/balloc.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index a0aa0386f21fa..a34b3801336e4 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -331,7 +331,7 @@ int ext2_new_block(struct inode *inode, unsigned long goal, 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 long goal, 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, unsigned long goal, * 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; @@ -426,10 +428,21 @@ retry: ret_block = grab_block(sb_bgl_lock(sbi, group_no), bitmap_bh->b_data, 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; } -- 2.53.0