patch-2.0.31 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: 291
- Date:
Sat Aug 16 16:23:19 1997
- Orig file:
v2.0.30/linux/fs/ext2/balloc.c
- Orig date:
Thu Jan 4 04:14:20 1996
diff -u --recursive --new-file v2.0.30/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c
@@ -43,6 +43,10 @@
unsigned long desc;
struct ext2_group_desc * gdp;
+ /*
+ * This panic should never trigger on a bad filesystem: the caller
+ * should have verified the block/group number already.
+ */
if (block_group >= sb->u.ext2_sb.s_groups_count)
ext2_panic (sb, "get_group_desc",
"block_group >= groups_count - "
@@ -63,22 +67,37 @@
return gdp + desc;
}
-static void read_block_bitmap (struct super_block * sb,
- unsigned int block_group,
- unsigned long bitmap_nr)
+/*
+ * 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;
+ int retval = 0;
gdp = get_group_desc (sb, block_group, NULL);
bh = bread (sb->s_dev, 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) 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.
+ */
sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group;
sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh;
+ return retval;
}
/*
@@ -91,11 +110,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;
@@ -114,7 +135,9 @@
else
return block_group;
} else {
- read_block_bitmap (sb, block_group, block_group);
+ retval = read_block_bitmap (sb, block_group, block_group);
+ if (retval < 0)
+ return retval;
return block_group;
}
}
@@ -134,6 +157,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++;
@@ -145,24 +176,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,
@@ -199,12 +277,19 @@
block_group = (block - es->s_first_data_block) /
EXT2_BLOCKS_PER_GROUP(sb);
bit = (block - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb);
- if (bit + count > EXT2_BLOCKS_PER_GROUP(sb))
- ext2_panic (sb, "ext2_free_blocks",
+ if (bit + count > EXT2_BLOCKS_PER_GROUP(sb)) {
+ ext2_error (sb, "ext2_free_blocks",
"Freeing blocks across group boundary - "
"Block = %lu, count = %lu",
block, count);
+ unlock_super (sb);
+ return;
+ }
+
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);
@@ -214,11 +299,14 @@
in_range (block, gdp->bg_inode_table,
sb->u.ext2_sb.s_itb_per_group) ||
in_range (block + count - 1, gdp->bg_inode_table,
- sb->u.ext2_sb.s_itb_per_group)))
- ext2_panic (sb, "ext2_free_blocks",
+ sb->u.ext2_sb.s_itb_per_group))) {
+ ext2_error (sb, "ext2_free_blocks",
"Freeing blocks in system zones - "
"Block = %lu, count = %lu",
block, count);
+ unlock_super (sb);
+ return;
+ }
for (i = 0; i < count; i++) {
if (!clear_bit (bit + i, bh->b_data))
@@ -242,6 +330,7 @@
wait_on_buffer (bh);
}
sb->s_dirt = 1;
+error_return:
unlock_super (sb);
return;
}
@@ -301,6 +390,12 @@
goal_attempts++;
#endif
bitmap_nr = load_block_bitmap (sb, i);
+ if (bitmap_nr < 0) {
+ *err = -EIO;
+ unlock_super (sb);
+ return 0;
+ }
+
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
ext2_debug ("goal is at %d:%d.\n", i, j);
@@ -372,7 +467,14 @@
unlock_super (sb);
return 0;
}
+
bitmap_nr = load_block_bitmap (sb, i);
+ if (bitmap_nr < 0) {
+ *err = -EIO;
+ unlock_super (sb);
+ return 0;
+ }
+
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;
@@ -415,10 +517,14 @@
if (test_opt (sb, CHECK_STRICT) &&
(tmp == gdp->bg_block_bitmap ||
tmp == gdp->bg_inode_bitmap ||
- in_range (tmp, gdp->bg_inode_table, sb->u.ext2_sb.s_itb_per_group)))
- ext2_panic (sb, "ext2_new_block",
+ in_range (tmp, gdp->bg_inode_table, sb->u.ext2_sb.s_itb_per_group))) {
+ ext2_error (sb, "ext2_new_block",
"Allocating block in system zone - "
"block = %u", tmp);
+ unlock_super (sb);
+ *err = -EIO;
+ return 0;
+ }
if (set_bit (j, bh->b_data)) {
ext2_warning (sb, "ext2_new_block",
@@ -511,7 +617,11 @@
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
gdp = get_group_desc (sb, i, NULL);
desc_count += 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",
@@ -556,6 +666,9 @@
gdp = get_group_desc (sb, i, NULL);
desc_count += 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 (!test_bit (0, bh->b_data))
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov