aboutsummaryrefslogtreecommitdiff
path: root/ext2fs/balloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext2fs/balloc.c')
-rw-r--r--ext2fs/balloc.c149
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);