patch-2.1.93 linux/fs/ext2/balloc.c
Next file: linux/fs/ext2/dir.c
Previous file: linux/fs/exec.c
Back to the patch index
Back to the overall index
- Lines: 370
- Date:
Thu Apr 2 13:39:52 1998
- Orig file:
v2.1.92/linux/fs/ext2/balloc.c
- Orig date:
Sun Dec 21 17:41:24 1997
diff -u --recursive --new-file v2.1.92/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c
@@ -38,27 +38,33 @@
#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
-static struct ext2_group_desc * get_group_desc (struct super_block * sb,
- unsigned int block_group,
- struct buffer_head ** bh)
+struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
+ unsigned int block_group,
+ struct buffer_head ** bh)
{
unsigned long group_desc;
unsigned long desc;
struct ext2_group_desc * gdp;
- if (block_group >= sb->u.ext2_sb.s_groups_count)
- ext2_panic (sb, "get_group_desc",
+ if (block_group >= sb->u.ext2_sb.s_groups_count) {
+ ext2_error (sb, "ext2_get_group_desc",
"block_group >= groups_count - "
"block_group = %d, groups_count = %lu",
block_group, sb->u.ext2_sb.s_groups_count);
+ return NULL;
+ }
+
group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
desc = block_group % EXT2_DESC_PER_BLOCK(sb);
- if (!sb->u.ext2_sb.s_group_desc[group_desc])
- ext2_panic (sb, "get_group_desc",
+ if (!sb->u.ext2_sb.s_group_desc[group_desc]) {
+ ext2_error (sb, "ext2_get_group_desc",
"Group descriptor not loaded - "
"block_group = %d, group_desc = %lu, desc = %lu",
block_group, group_desc, desc);
+ return NULL;
+ }
+
gdp = (struct ext2_group_desc *)
sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
if (bh)
@@ -66,22 +72,40 @@
return gdp + desc;
}
-static void read_block_bitmap (struct super_block * sb,
+/*
+ * Read the bitmap for a given block_group, reading into the specified
+ * slot in the superblock's bitmap cache.
+ *
+ * Return >=0 on success or a -ve error code.
+ */
+
+static int read_block_bitmap (struct super_block * sb,
unsigned int block_group,
unsigned long bitmap_nr)
{
struct ext2_group_desc * gdp;
- struct buffer_head * bh;
+ struct buffer_head * bh = NULL;
+ int retval = 0;
- gdp = get_group_desc (sb, block_group, NULL);
+ gdp = ext2_get_group_desc (sb, block_group, NULL);
+ if (!gdp)
+ goto error_out;
bh = bread (sb->s_dev, le32_to_cpu(gdp->bg_block_bitmap), sb->s_blocksize);
- if (!bh)
- ext2_panic (sb, "read_block_bitmap",
+ if (!bh) {
+ ext2_error (sb, "read_block_bitmap",
"Cannot read block bitmap - "
"block_group = %d, block_bitmap = %lu",
- block_group, (unsigned long) le32_to_cpu(gdp->bg_block_bitmap));
+ block_group, (unsigned long) gdp->bg_block_bitmap);
+ retval = -EIO;
+ }
+ /*
+ * On IO error, just leave a zero in the superblock's block pointer for
+ * this group. The IO will be retried next time.
+ */
+error_out:
sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group;
sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh;
+ return retval;
}
/*
@@ -94,11 +118,13 @@
* 1/ There is one cache per mounted file system.
* 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
* this function reads the bitmap without maintaining a LRU cache.
+ *
+ * Return the slot used to store the bitmap, or a -ve error code.
*/
static int load__block_bitmap (struct super_block * sb,
unsigned int block_group)
{
- int i, j;
+ int i, j, retval = 0;
unsigned long block_bitmap_number;
struct buffer_head * block_bitmap;
@@ -110,16 +136,16 @@
if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) {
if (sb->u.ext2_sb.s_block_bitmap[block_group]) {
- if (sb->u.ext2_sb.s_block_bitmap_number[block_group] !=
+ if (sb->u.ext2_sb.s_block_bitmap_number[block_group] ==
block_group)
- ext2_panic (sb, "load_block_bitmap",
- "block_group != block_bitmap_number");
- else
return block_group;
- } else {
- read_block_bitmap (sb, block_group, block_group);
- return block_group;
+ ext2_error (sb, "load_block_bitmap",
+ "block_group != block_bitmap_number");
}
+ retval = read_block_bitmap (sb, block_group, block_group);
+ if (retval < 0)
+ return retval;
+ return block_group;
}
for (i = 0; i < sb->u.ext2_sb.s_loaded_block_bitmaps &&
@@ -137,6 +163,14 @@
}
sb->u.ext2_sb.s_block_bitmap_number[0] = block_bitmap_number;
sb->u.ext2_sb.s_block_bitmap[0] = block_bitmap;
+
+ /*
+ * There's still one special case here --- if block_bitmap == 0
+ * then our last attempt to read the bitmap failed and we have
+ * just ended up caching that failure. Try again to read it.
+ */
+ if (!block_bitmap)
+ retval = read_block_bitmap (sb, block_group, 0);
} else {
if (sb->u.ext2_sb.s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
sb->u.ext2_sb.s_loaded_block_bitmaps++;
@@ -148,24 +182,71 @@
sb->u.ext2_sb.s_block_bitmap[j] =
sb->u.ext2_sb.s_block_bitmap[j - 1];
}
- read_block_bitmap (sb, block_group, 0);
+ retval = read_block_bitmap (sb, block_group, 0);
}
- return 0;
+ return retval;
}
+/*
+ * Load the block bitmap for a given block group. First of all do a couple
+ * of fast lookups for common cases and then pass the request onto the guts
+ * of the bitmap loader.
+ *
+ * Return the slot number of the group in the superblock bitmap cache's on
+ * success, or a -ve error code.
+ *
+ * There is still one inconsistancy here --- if the number of groups in this
+ * filesystems is <= EXT2_MAX_GROUP_LOADED, then we have no way of
+ * differentiating between a group for which we have never performed a bitmap
+ * IO request, and a group for which the last bitmap read request failed.
+ */
static inline int load_block_bitmap (struct super_block * sb,
unsigned int block_group)
{
- if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 &&
- sb->u.ext2_sb.s_block_bitmap_number[0] == block_group)
- return 0;
+ int slot;
- if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED &&
- sb->u.ext2_sb.s_block_bitmap_number[block_group] == block_group &&
- sb->u.ext2_sb.s_block_bitmap[block_group])
- return block_group;
+ /*
+ * Do the lookup for the slot. First of all, check if we're asking
+ * for the same slot as last time, and did we succeed that last time?
+ */
+ if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 &&
+ sb->u.ext2_sb.s_block_bitmap_number[0] == block_group &&
+ sb->u.ext2_sb.s_block_bitmap[block_group]) {
+ slot = 0;
+ }
+ /*
+ * Or can we do a fast lookup based on a loaded group on a filesystem
+ * small enough to be mapped directly into the superblock?
+ */
+ else if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED &&
+ sb->u.ext2_sb.s_block_bitmap_number[block_group] == block_group &&
+ sb->u.ext2_sb.s_block_bitmap[block_group]) {
+ slot = block_group;
+ }
+ /*
+ * If not, then do a full lookup for this block group.
+ */
+ else {
+ slot = load__block_bitmap (sb, block_group);
+ }
- return load__block_bitmap (sb, block_group);
+ /*
+ * <0 means we just got an error
+ */
+ if (slot < 0)
+ return slot;
+
+ /*
+ * If it's a valid slot, we may still have cached a previous IO error,
+ * in which case the bh in the superblock cache will be zero.
+ */
+ if (!sb->u.ext2_sb.s_block_bitmap[slot])
+ return -EIO;
+
+ /*
+ * Must have been read in OK to get this far.
+ */
+ return slot;
}
void ext2_free_blocks (const struct inode * inode, unsigned long block,
@@ -194,8 +275,7 @@
ext2_error (sb, "ext2_free_blocks",
"Freeing blocks not in datazone - "
"block = %lu, count = %lu", block, count);
- unlock_super (sb);
- return;
+ goto error_return;
}
ext2_debug ("freeing block %lu\n", block);
@@ -215,8 +295,13 @@
count -= overflow;
}
bitmap_nr = load_block_bitmap (sb, block_group);
+ if (bitmap_nr < 0)
+ goto error_return;
+
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
- gdp = get_group_desc (sb, block_group, &bh2);
+ gdp = ext2_get_group_desc (sb, block_group, &bh2);
+ if (!gdp)
+ goto error_return;
if (test_opt (sb, CHECK_STRICT) &&
(in_range (le32_to_cpu(gdp->bg_block_bitmap), block, count) ||
@@ -259,6 +344,7 @@
goto do_more;
}
sb->s_dirt = 1;
+error_return:
unlock_super (sb);
return;
}
@@ -312,7 +398,10 @@
goal >= le32_to_cpu(es->s_blocks_count))
goal = le32_to_cpu(es->s_first_data_block);
i = (goal - le32_to_cpu(es->s_first_data_block)) / EXT2_BLOCKS_PER_GROUP(sb);
- gdp = get_group_desc (sb, i, &bh2);
+ gdp = ext2_get_group_desc (sb, i, &bh2);
+ if (!gdp)
+ goto io_error;
+
if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) {
j = ((goal - le32_to_cpu(es->s_first_data_block)) % EXT2_BLOCKS_PER_GROUP(sb));
#ifdef EXT2FS_DEBUG
@@ -320,6 +409,9 @@
goal_attempts++;
#endif
bitmap_nr = load_block_bitmap (sb, i);
+ if (bitmap_nr < 0)
+ goto io_error;
+
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
ext2_debug ("goal is at %d:%d.\n", i, j);
@@ -384,7 +476,12 @@
i++;
if (i >= sb->u.ext2_sb.s_groups_count)
i = 0;
- gdp = get_group_desc (sb, i, &bh2);
+ gdp = ext2_get_group_desc (sb, i, &bh2);
+ if (!gdp) {
+ *err = -EIO;
+ unlock_super (sb);
+ return 0;
+ }
if (le16_to_cpu(gdp->bg_free_blocks_count) > 0)
break;
}
@@ -393,6 +490,9 @@
return 0;
}
bitmap_nr = load_block_bitmap (sb, i);
+ if (bitmap_nr < 0)
+ goto io_error;
+
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
r = memscan(bh->b_data, 0, EXT2_BLOCKS_PER_GROUP(sb) >> 3);
j = (r - bh->b_data) << 3;
@@ -455,10 +555,16 @@
*/
#ifdef EXT2_PREALLOCATE
if (prealloc_block) {
+ int prealloc_goal;
+
+ prealloc_goal = es->s_prealloc_blocks ?
+ es->s_prealloc_blocks : EXT2_DEFAULT_PREALLOC_BLOCKS;
+
*prealloc_count = 0;
*prealloc_block = tmp + 1;
for (k = 1;
- k < 8 && (j + k) < EXT2_BLOCKS_PER_GROUP(sb); k++) {
+ k < prealloc_goal && (j + k) < EXT2_BLOCKS_PER_GROUP(sb);
+ k++) {
if (sb->dq_op)
if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(1, sb->s_blocksize)))
break;
@@ -516,6 +622,12 @@
unlock_super (sb);
*err = 0;
return j;
+
+io_error:
+ *err = -EIO;
+ unlock_super (sb);
+ return 0;
+
}
unsigned long ext2_count_free_blocks (struct super_block * sb)
@@ -533,9 +645,14 @@
bitmap_count = 0;
gdp = NULL;
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
- gdp = get_group_desc (sb, i, NULL);
+ gdp = ext2_get_group_desc (sb, i, NULL);
+ if (!gdp)
+ continue;
desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
bitmap_nr = load_block_bitmap (sb, i);
+ if (bitmap_nr < 0)
+ continue;
+
x = ext2_count_free (sb->u.ext2_sb.s_block_bitmap[bitmap_nr],
sb->s_blocksize);
printk ("group %d: stored = %d, counted = %lu\n",
@@ -590,12 +707,17 @@
desc_blocks = (sb->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) /
EXT2_DESC_PER_BLOCK(sb);
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
- gdp = get_group_desc (sb, i, NULL);
+ gdp = ext2_get_group_desc (sb, i, NULL);
+ if (!gdp)
+ continue;
desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
bitmap_nr = load_block_bitmap (sb, i);
+ if (bitmap_nr < 0)
+ continue;
+
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
- if (!(sb->u.ext2_sb.s_feature_ro_compat &
+ if (!(le32_to_cpu(sb->u.ext2_sb.s_feature_ro_compat) &
EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) ||
(test_root(i, 3) || test_root(i, 5) || test_root(i, 7))) {
if (!ext2_test_bit (0, bh->b_data))
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov