diff options
Diffstat (limited to 'ext2fs/balloc.c')
-rw-r--r-- | ext2fs/balloc.c | 149 |
1 files changed, 99 insertions, 50 deletions
diff --git a/ext2fs/balloc.c b/ext2fs/balloc.c index 9c47b742..7333123c 100644 --- a/ext2fs/balloc.c +++ b/ext2fs/balloc.c @@ -1,8 +1,8 @@ /* Block allocation routines - Copyright (C) 1995 Free Software Foundation, Inc. + Copyright (C) 1995,99,2000 Free Software Foundation, Inc. - Converted to work under the hurd by Miles Bader <miles@gnu.ai.mit.edu> + Converted to work under the hurd by Miles Bader <miles@gnu.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -42,10 +42,19 @@ #include <string.h> #include "ext2fs.h" +#include "bitmap.c" + +/* Returns a pointer to the first occurrence of CH in the buffer BUF of len + LEN, or BUF + LEN if CH doesn't occur. */ +static inline void * +memscan (void *buf, unsigned char ch, size_t len) +{ + return memchr (buf, ch, len) ?: buf + len; +} #define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1) -void +void ext2_free_blocks (block_t block, unsigned long count) { char *bh; @@ -60,44 +69,57 @@ ext2_free_blocks (block_t block, unsigned long count) (block + count) > sblock->s_blocks_count) { ext2_error ("freeing blocks not in datazone - " - "block = %lu, count = %lu", block, count); + "block = %u, count = %lu", block, count); spin_unlock (&global_lock); return; } - ext2_debug ("freeing block %lu[%lu]", block, count); + ext2_debug ("freeing block %u[%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 = %lu, count = %lu", - block, count); - gdp = group_desc (block_group); - bh = bptr (gdp->bg_block_bitmap); + do + { + unsigned long int gcount = 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); - 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 = %lu, count = %lu", - block, count); + 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 < count; i++) - { - if (!clear_bit (bit + i, bh)) - ext2_warning ("bit already cleared for block %lu", block + i); - else + 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); @@ -108,12 +130,14 @@ ext2_free_blocks (block_t block, unsigned long count) /* * ext2_new_block uses a goal block to assist allocation. If the goal is * free, or there is a free block within 32 blocks of the goal, that block - * is allocated. Otherwise a forward search is made for a free block; within + * is allocated. Otherwise a forward search is made for a free block; within * each block group the search first looks for an entire free byte in the block * 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; @@ -138,7 +162,7 @@ ext2_new_block (block_t goal, block_t *prealloc_count, block_t *prealloc_block) } #endif - ext2_debug ("goal=%lu", goal); + ext2_debug ("goal=%u", goal); repeat: /* @@ -170,7 +194,7 @@ repeat: if (j) { /* - * The goal was occupied; search forward for a free + * The goal was occupied; search forward for a free * block within the next 32 blocks */ lmap = ((((unsigned long *) bh)[j >> 5]) >> @@ -198,7 +222,7 @@ repeat: * of the goal: do a search forward through the block groups, * searching in each group first for an entire free byte in * the bitmap and then for any free bit. - * + * * Search first in the remainder of the current group; then, * cyclicly search through the rest of the groups. */ @@ -223,7 +247,7 @@ repeat: ext2_debug ("bit not found in block group %d", i); /* - * Now search the rest of the groups. We assume that + * Now search the rest of the groups. We assume that * i and gdp correctly point to the last group visited. */ for (k = 0; k < groups_count; k++) @@ -256,7 +280,7 @@ repeat: } search_back: - /* + /* * We have succeeded in finding a free byte in the block * bitmap. Now search backwards up to 7 bits to find the * start of this group of free blocks. @@ -296,12 +320,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; @@ -317,7 +341,7 @@ got_block: } gdp->bg_free_blocks_count -= *prealloc_count; sblock->s_free_blocks_count -= *prealloc_count; - ext2_debug ("preallocated a further %lu bits", *prealloc_count); + ext2_debug ("preallocated a further %u bits", *prealloc_count); } #endif @@ -348,7 +372,7 @@ got_block: return j; } -unsigned long +unsigned long ext2_count_free_blocks () { #ifdef EXT2FS_DEBUG @@ -370,7 +394,7 @@ ext2_count_free_blocks () i, gdp->bg_free_blocks_count, x); bitmap_count += x; } - printf ("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu", + printf ("ext2_count_free_blocks: stored = %u, computed = %lu, %lu", sblock->s_free_blocks_count, desc_count, bitmap_count); spin_unlock (&global_lock); return bitmap_count; @@ -379,14 +403,14 @@ ext2_count_free_blocks () #endif } -static inline int +static inline int block_in_use (block_t block, unsigned char *map) { return test_bit ((block - sblock->s_first_data_block) % sblock->s_blocks_per_group, map); } -void +void ext2_check_blocks_bitmap () { char *bh; @@ -405,16 +429,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); |