diff --git a/ldiskfs/kernel_patches/patches/ext3-block-bitmap-validation-2.6-rhel5.patch b/ldiskfs/kernel_patches/patches/ext3-block-bitmap-validation-2.6-rhel5.patch new file mode 100644 index 0000000000000000000000000000000000000000..39cbcc84a4074ea8f06b6d1f3d61c2b09c819ace --- /dev/null +++ b/ldiskfs/kernel_patches/patches/ext3-block-bitmap-validation-2.6-rhel5.patch @@ -0,0 +1,169 @@ + fs/ext3/balloc.c | 99 ++++++++++++++++++++++++++++++++++++++++++++---------- + 1 files changed, 81 insertions(+), 18 deletions(-) +diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c +index ff3428e..a9140ea 100644 +Index: linux-stage/fs/ext3/balloc.c +=================================================================== +--- linux-stage.orig/fs/ext3/balloc.c ++++ linux-stage/fs/ext3/balloc.c +@@ -143,9 +143,96 @@ unsigned ext3_init_block_bitmap(struct s + return free_blocks - sbi->s_itb_per_group - 2; + } + +-/* +- * Read the bitmap for a given block_group, reading into the specified +- * slot in the superblock's bitmap cache. ++/** ++* bh_uptodate_or_lock: Test whether the buffer is uptodate ++* @bh: struct buffer_head ++* ++* Return true if the buffer is up-to-date and false, ++* with the buffer locked, if not. ++*/ ++int bh_uptodate_or_lock(struct buffer_head *bh) ++{ ++ if (!buffer_uptodate(bh)) { ++ lock_buffer(bh); ++ if (!buffer_uptodate(bh)) ++ return 0; ++ unlock_buffer(bh); ++ } ++ return 1; ++} ++ ++/** ++* bh_submit_read: Submit a locked buffer for reading ++* @bh: struct buffer_head ++* ++* Returns a negative error ++*/ ++int bh_submit_read(struct buffer_head *bh) ++{ ++ if (!buffer_locked(bh)) ++ lock_buffer(bh); ++ if (buffer_uptodate(bh)) ++ return 0; ++ get_bh(bh); ++ bh->b_end_io = end_buffer_read_sync; ++ submit_bh(READ, bh); ++ wait_on_buffer(bh); ++ if (buffer_uptodate(bh)) ++ return 0; ++ return -EIO; ++} ++ ++static int ext3_valid_block_bitmap(struct super_block *sb, ++ struct ext3_group_desc *desc, ++ unsigned int block_group, ++ struct buffer_head *bh) ++{ ++ ext3_grpblk_t offset; ++ ext3_grpblk_t next_zero_bit; ++ ext3_fsblk_t bitmap_blk; ++ ext3_fsblk_t group_first_block; ++ ++ group_first_block = ext3_group_first_block_no(sb, block_group); ++ ++ /* check whether block bitmap block number is set */ ++ bitmap_blk = le32_to_cpu(desc->bg_block_bitmap); ++ offset = bitmap_blk - group_first_block; ++ if (!ext3_test_bit(offset, bh->b_data)) ++ /* bad block bitmap */ ++ goto err_out; ++ ++ /* check whether the inode bitmap block number is set */ ++ bitmap_blk = le32_to_cpu(desc->bg_inode_bitmap); ++ offset = bitmap_blk - group_first_block; ++ if (!ext3_test_bit(offset, bh->b_data)) ++ /* bad block bitmap */ ++ goto err_out; ++ ++ /* check whether the inode table block number is set */ ++ bitmap_blk = le32_to_cpu(desc->bg_inode_table); ++ offset = bitmap_blk - group_first_block; ++ next_zero_bit = ext3_find_next_zero_bit(bh->b_data, ++ offset + EXT3_SB(sb)->s_itb_per_group, ++ offset); ++ if (next_zero_bit >= offset + EXT3_SB(sb)->s_itb_per_group) ++ /* good bitmap for inode tables */ ++ return 1; ++ ++err_out: ++ ext3_error(sb, __FUNCTION__, ++ "Invalid block bitmap - " ++ "block_group = %d, block = %lu", ++ (int)block_group, bitmap_blk); ++ return 0; ++} ++ ++/** ++ * read_block_bitmap() ++ * @sb: super block ++ * @block_group: given block group ++ * ++ * Read the bitmap for a given block_group,and validate the ++ * bits for block/inode/inode tables are set in the bitmaps. + * + * Return buffer_head on success or NULL in case of failure. + */ +@@ -154,29 +241,42 @@ read_block_bitmap(struct super_block *sb + { + struct ext3_group_desc * desc; + struct buffer_head * bh = NULL; ++ ext3_fsblk_t bitmap_blk; + + desc = ext3_get_group_desc (sb, block_group, NULL); + if (!desc) +- goto error_out; ++ return NULL; ++ bitmap_blk = desc->bg_block_bitmap; ++ bh = sb_getblk(sb, bitmap_blk); ++ if (unlikely(!bh)) { ++ ext3_error(sb, __FUNCTION__, ++ "Can not read block bitmap - " ++ "block group = %d, block_bitmap = %lu", ++ (int)block_group, bitmap_blk); ++ return NULL; ++ } ++ if (bh_uptodate_or_lock(bh)) ++ return bh; ++ + if (desc->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT)) { +- bh = sb_getblk(sb, le32_to_cpu(desc->bg_block_bitmap)); +- if (!buffer_uptodate(bh)) { +- lock_buffer(bh); +- if (!buffer_uptodate(bh)) { +- ext3_init_block_bitmap(sb, bh,block_group,desc); +- set_buffer_uptodate(bh); +- } +- unlock_buffer(bh); +- } +- } else { +- bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap)); ++ ext3_init_block_bitmap(sb, bh, block_group, desc); ++ set_buffer_uptodate(bh); ++ unlock_buffer(bh); ++ return bh; ++ } ++ if (bh_submit_read(bh) < 0) { ++ brelse(bh); ++ ext3_error(sb, __FUNCTION__, ++ "Cannot read block bitmap - " ++ "block group = %d block_bitmap = %lu", ++ (int)block_group, bitmap_blk); ++ return NULL; ++ } ++ if (!ext3_valid_block_bitmap(sb, desc, block_group, bh)) { ++ brelse(bh); ++ return NULL; + } +- if (!bh) +- ext3_error (sb, "read_block_bitmap", +- "Cannot read block bitmap - " +- "block_group = %d, block_bitmap = %u", +- block_group, le32_to_cpu(desc->bg_block_bitmap)); +-error_out: ++ + return bh; + } + /* diff --git a/ldiskfs/kernel_patches/patches/ext3-block-bitmap-validation-2.6-sles10.patch b/ldiskfs/kernel_patches/patches/ext3-block-bitmap-validation-2.6-sles10.patch new file mode 100644 index 0000000000000000000000000000000000000000..417591d1c3e664ab1d62d7afc31574646133d871 --- /dev/null +++ b/ldiskfs/kernel_patches/patches/ext3-block-bitmap-validation-2.6-sles10.patch @@ -0,0 +1,188 @@ + fs/ext3/balloc.c | 99 ++++++++++++++++++++++++++++++++++++++++++++---------- + 1 files changed, 81 insertions(+), 18 deletions(-) +diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c +index ff3428e..a9140ea 100644 +Index: linux-stage/fs/ext3/balloc.c +=================================================================== +--- linux-stage.orig/fs/ext3/balloc.c ++++ linux-stage/fs/ext3/balloc.c +@@ -144,9 +144,96 @@ unsigned ext3_init_block_bitmap(struct s + return free_blocks - sbi->s_itb_per_group - 2; + } + +-/* +- * Read the bitmap for a given block_group, reading into the specified +- * slot in the superblock's bitmap cache. ++/** ++* bh_uptodate_or_lock: Test whether the buffer is uptodate ++* @bh: struct buffer_head ++* ++* Return true if the buffer is up-to-date and false, ++* with the buffer locked, if not. ++*/ ++int bh_uptodate_or_lock(struct buffer_head *bh) ++{ ++ if (!buffer_uptodate(bh)) { ++ lock_buffer(bh); ++ if (!buffer_uptodate(bh)) ++ return 0; ++ unlock_buffer(bh); ++ } ++ return 1; ++} ++ ++/** ++* bh_submit_read: Submit a locked buffer for reading ++* @bh: struct buffer_head ++* ++* Returns a negative error ++*/ ++int bh_submit_read(struct buffer_head *bh) ++{ ++ if (!buffer_locked(bh)) ++ lock_buffer(bh); ++ if (buffer_uptodate(bh)) ++ return 0; ++ get_bh(bh); ++ bh->b_end_io = end_buffer_read_sync; ++ submit_bh(READ, bh); ++ wait_on_buffer(bh); ++ if (buffer_uptodate(bh)) ++ return 0; ++ return -EIO; ++} ++ ++static int ext3_valid_block_bitmap(struct super_block *sb, ++ struct ext3_group_desc *desc, ++ unsigned int block_group, ++ struct buffer_head *bh) ++{ ++ unsigned long long offset; ++ unsigned long long next_zero_bit; ++ unsigned long long bitmap_blk; ++ unsigned long long group_first_block; ++ ++ group_first_block = ext3_group_first_block_no(sb, block_group); ++ ++ /* check whether block bitmap block number is set */ ++ bitmap_blk = le32_to_cpu(desc->bg_block_bitmap); ++ offset = bitmap_blk - group_first_block; ++ if (!ext3_test_bit(offset, bh->b_data)) ++ /* bad block bitmap */ ++ goto err_out; ++ ++ /* check whether the inode bitmap block number is set */ ++ bitmap_blk = le32_to_cpu(desc->bg_inode_bitmap); ++ offset = bitmap_blk - group_first_block; ++ if (!ext3_test_bit(offset, bh->b_data)) ++ /* bad block bitmap */ ++ goto err_out; ++ ++ /* check whether the inode table block number is set */ ++ bitmap_blk = le32_to_cpu(desc->bg_inode_table); ++ offset = bitmap_blk - group_first_block; ++ next_zero_bit = ext3_find_next_zero_bit(bh->b_data, ++ offset + EXT3_SB(sb)->s_itb_per_group, ++ offset); ++ if (next_zero_bit >= offset + EXT3_SB(sb)->s_itb_per_group) ++ /* good bitmap for inode tables */ ++ return 1; ++ ++err_out: ++ ext3_error(sb, __FUNCTION__, ++ "Invalid block bitmap - " ++ "block_group = %d, block = %llu", ++ block_group, bitmap_blk); ++ return 0; ++} ++ ++/** ++ * read_block_bitmap() ++ * @sb: super block ++ * @block_group: given block group ++ * ++ * Read the bitmap for a given block_group,and validate the ++ * bits for block/inode/inode tables are set in the bitmaps. + * + * Return buffer_head on success or NULL in case of failure. + */ +@@ -155,29 +242,42 @@ read_block_bitmap(struct super_block *sb + { + struct ext3_group_desc * desc; + struct buffer_head * bh = NULL; ++ unsigned long long bitmap_blk; + + desc = ext3_get_group_desc (sb, block_group, NULL); + if (!desc) +- goto error_out; ++ return NULL; ++ bitmap_blk = desc->bg_block_bitmap; ++ bh = sb_getblk(sb, bitmap_blk); ++ if (unlikely(!bh)) { ++ ext3_error(sb, __FUNCTION__, ++ "Can not read block bitmap - " ++ "block group = %d, block_bitmap = %llu", ++ (int)block_group, bitmap_blk); ++ return NULL; ++ } ++ if (bh_uptodate_or_lock(bh)) ++ return bh; ++ + if (desc->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT)) { +- bh = sb_getblk(sb, le32_to_cpu(desc->bg_block_bitmap)); +- if (!buffer_uptodate(bh)) { +- lock_buffer(bh); +- if (!buffer_uptodate(bh)) { +- ext3_init_block_bitmap(sb, bh,block_group,desc); +- set_buffer_uptodate(bh); +- } +- unlock_buffer(bh); +- } +- } else { +- bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap)); ++ ext3_init_block_bitmap(sb, bh, block_group, desc); ++ set_buffer_uptodate(bh); ++ unlock_buffer(bh); ++ return bh; ++ } ++ if (bh_submit_read(bh) < 0) { ++ brelse(bh); ++ ext3_error(sb, __FUNCTION__, ++ "Cannot read block bitmap - " ++ "block group = %d block_bitmap = %llu", ++ (int)block_group, bitmap_blk); ++ return NULL; + } +- if (!bh) +- ext3_error (sb, "read_block_bitmap", +- "Cannot read block bitmap - " +- "block_group = %d, block_bitmap = %u", +- block_group, le32_to_cpu(desc->bg_block_bitmap)); +-error_out: ++ if (!ext3_valid_block_bitmap(sb, desc, block_group, bh)) { ++ brelse(bh); ++ return NULL; ++ } ++ + return bh; + } + /* +Index: linux-stage/include/linux/ext3_fs.h +=================================================================== +--- linux-stage.orig/include/linux/ext3_fs.h ++++ linux-stage/include/linux/ext3_fs.h +@@ -872,6 +872,14 @@ struct dir_private_info { + __u32 next_hash; + }; + ++/* calculate the first block number of the group */ ++static inline long long ++ext3_group_first_block_no(struct super_block *sb, unsigned long group_no) ++{ ++ return group_no * (long long)EXT3_BLOCKS_PER_GROUP(sb) + ++ le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block); ++} ++ + /* + * Special error return code only used by dx_probe() and its callers. + */ diff --git a/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel5.series b/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel5.series index acc17b303a678a7a86a3223843f1a2a9ae444742..5e20e498af8ba2294bfcfb07769e015748515dc5 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel5.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel5.series @@ -21,3 +21,4 @@ ext3-statfs-2.6-rhel5.patch ext3-lookup-dotdot-2.6.9.patch ext3-max-dir-size.patch ext3-print-inum-in-htree-warning.patch +ext3-block-bitmap-validation-2.6-rhel5.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-2.6-sles10.series b/ldiskfs/kernel_patches/series/ldiskfs-2.6-sles10.series index 2a5b9758b65a7fb0923a2e7e92864deee0c2b5d4..952f260a77ef2811a7182d4458280b7a6d5731bf 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-2.6-sles10.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-2.6-sles10.series @@ -25,3 +25,4 @@ ext3-statfs-2.6-sles10.patch ext3-lookup-dotdot-2.6.9.patch ext3-max-dir-size.patch ext3-print-inum-in-htree-warning.patch +ext3-block-bitmap-validation-2.6-sles10.patch