summaryrefslogtreecommitdiff
path: root/ext2fs/balloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext2fs/balloc.c')
-rw-r--r--ext2fs/balloc.c108
1 files changed, 74 insertions, 34 deletions
diff --git a/ext2fs/balloc.c b/ext2fs/balloc.c
index 811bca4f..8cdfb79c 100644
--- a/ext2fs/balloc.c
+++ b/ext2fs/balloc.c
@@ -67,37 +67,50 @@ ext2_free_blocks (block_t block, unsigned long count)
ext2_debug ("freeing block %lu[%lu]", block, count);
- block_group = (block - sblock->s_first_data_block) /
- sblock->s_blocks_per_group;
- bit = (block - sblock->s_first_data_block) % sblock->s_blocks_per_group;
- if (bit + count > sblock->s_blocks_per_group)
- ext2_panic ("freeing blocks across group boundary - "
- "block = %u, count = %lu",
- block, count);
- gdp = group_desc (block_group);
- bh = bptr (gdp->bg_block_bitmap);
+ do
+ {
+ unsigned long int gcount = count;
- if (in_range (gdp->bg_block_bitmap, block, count) ||
- in_range (gdp->bg_inode_bitmap, block, count) ||
- in_range (block, gdp->bg_inode_table, itb_per_group) ||
- in_range (block + count - 1, gdp->bg_inode_table, itb_per_group))
- ext2_panic ("freeing blocks in system zones - "
- "block = %u, count = %lu",
- block, count);
+ block_group = ((block - sblock->s_first_data_block)
+ / sblock->s_blocks_per_group);
+ bit = (block - sblock->s_first_data_block) % sblock->s_blocks_per_group;
+ if (bit + count > sblock->s_blocks_per_group)
+ {
+ unsigned long overflow = bit + count - sblock->s_blocks_per_group;
+ gcount -= overflow;
+ ext2_debug ("freeing blocks across group boundary - "
+ "block = %u, count = %lu",
+ block, count);
+ }
+ gdp = group_desc (block_group);
+ bh = bptr (gdp->bg_block_bitmap);
- for (i = 0; i < count; i++)
- {
- if (!clear_bit (bit + i, bh))
- ext2_warning ("bit already cleared for block %lu", block + i);
- else
+ if (in_range (gdp->bg_block_bitmap, block, gcount) ||
+ in_range (gdp->bg_inode_bitmap, block, gcount) ||
+ in_range (block, gdp->bg_inode_table, itb_per_group) ||
+ in_range (block + gcount - 1, gdp->bg_inode_table, itb_per_group))
+ ext2_panic ("freeing blocks in system zones - "
+ "block = %u, count = %lu",
+ block, count);
+
+ for (i = 0; i < gcount; i++)
{
- gdp->bg_free_blocks_count++;
- sblock->s_free_blocks_count++;
+ if (!clear_bit (bit + i, bh))
+ ext2_warning ("bit already cleared for block %lu", block + i);
+ else
+ {
+ gdp->bg_free_blocks_count++;
+ sblock->s_free_blocks_count++;
+ }
}
- }
- record_global_poke (bh);
- record_global_poke (gdp);
+ record_global_poke (bh);
+ record_global_poke (gdp);
+
+ block += gcount;
+ count -= gcount;
+ } while (count > 0);
+
sblock_dirty = 1;
spin_unlock (&global_lock);
@@ -113,7 +126,9 @@ ext2_free_blocks (block_t block, unsigned long count)
* bitmap, and then for any free bit if that fails.
*/
block_t
-ext2_new_block (block_t goal, block_t *prealloc_count, block_t *prealloc_block)
+ext2_new_block (block_t goal,
+ block_t prealloc_goal,
+ block_t *prealloc_count, block_t *prealloc_block)
{
char *bh;
char *p, *r;
@@ -296,12 +311,12 @@ got_block:
* Do block preallocation now if required.
*/
#ifdef EXT2_PREALLOCATE
- if (prealloc_block)
+ if (prealloc_goal)
{
*prealloc_count = 0;
*prealloc_block = tmp + 1;
for (k = 1;
- k < 8 && (j + k) < sblock->s_blocks_per_group; k++)
+ k < prealloc_goal && (j + k) < sblock->s_blocks_per_group; k++)
{
if (set_bit (j + k, bh))
break;
@@ -405,16 +420,41 @@ ext2_check_blocks_bitmap ()
for (i = 0; i < groups_count; i++)
{
+ inline int test_root (int a, int b)
+ {
+ if (a == 0)
+ return 1;
+ while (1)
+ {
+ if (a == 1)
+ return 1;
+ if (a % b)
+ return 0;
+ a = a / b;
+ }
+ }
+ inline int ext2_group_sparse (int group)
+ {
+ return (test_root (group, 3) || test_root (group, 5)
+ || test_root (group, 7));
+ }
+
gdp = group_desc (i);
desc_count += gdp->bg_free_blocks_count;
bh = bptr (gdp->bg_block_bitmap);
- if (!test_bit (0, bh))
- ext2_error ("superblock in group %d is marked free", i);
+ if (!EXT2_HAS_RO_COMPAT_FEATURE (sblock,
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
+ || ext2_group_sparse (i))
+ {
+ if (!test_bit (0, bh))
+ ext2_error ("superblock in group %d is marked free", i);
- for (j = 0; j < desc_blocks; j++)
- if (!test_bit (j + 1, bh))
- ext2_error ("descriptor block #%d in group %d is marked free", j, i);
+ for (j = 0; j < desc_blocks; j++)
+ if (!test_bit (j + 1, bh))
+ ext2_error ("descriptor block #%d in group %d is marked free",
+ j, i);
+ }
if (!block_in_use (gdp->bg_block_bitmap, bh))
ext2_error ("block bitmap for group %d is marked free", i);