aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@us.ibm.com>2012-04-29 18:35:10 -0400
committerTheodore Ts'o <tytso@mit.edu>2012-04-29 18:35:10 -0400
commitfa77dcfafeaa6bc73293c646bfc3d5192dcf0be2 (patch)
tree66c4232c2e5c1f59666e05164b77539a9b1dd290
parent41a246d1ff75a95d2be3191ca6e6db139dc0f430 (diff)
ext4: calculate and verify block bitmap checksum
Compute and verify the checksum of the block bitmap; this checksum is stored in the block group descriptor. Signed-off-by: Darrick J. Wong <djwong@us.ibm.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r--fs/ext4/balloc.c39
-rw-r--r--fs/ext4/bitmap.c44
-rw-r--r--fs/ext4/ext4.h10
-rw-r--r--fs/ext4/ialloc.c4
-rw-r--r--fs/ext4/mballoc.c8
-rw-r--r--fs/ext4/resize.c7
6 files changed, 104 insertions, 8 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index 4bbd07a6fa18..0a64e4d5dbad 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -174,6 +174,8 @@ void ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
174 ext4_free_inodes_set(sb, gdp, 0); 174 ext4_free_inodes_set(sb, gdp, 0);
175 ext4_itable_unused_set(sb, gdp, 0); 175 ext4_itable_unused_set(sb, gdp, 0);
176 memset(bh->b_data, 0xff, sb->s_blocksize); 176 memset(bh->b_data, 0xff, sb->s_blocksize);
177 ext4_block_bitmap_csum_set(sb, block_group, gdp, bh,
178 EXT4_BLOCKS_PER_GROUP(sb) / 8);
177 return; 179 return;
178 } 180 }
179 memset(bh->b_data, 0, sb->s_blocksize); 181 memset(bh->b_data, 0, sb->s_blocksize);
@@ -210,6 +212,9 @@ void ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
210 */ 212 */
211 ext4_mark_bitmap_end(num_clusters_in_group(sb, block_group), 213 ext4_mark_bitmap_end(num_clusters_in_group(sb, block_group),
212 sb->s_blocksize * 8, bh->b_data); 214 sb->s_blocksize * 8, bh->b_data);
215 ext4_block_bitmap_csum_set(sb, block_group, gdp, bh,
216 EXT4_BLOCKS_PER_GROUP(sb) / 8);
217 gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp);
213} 218}
214 219
215/* Return the number of free blocks in a block group. It is used when 220/* Return the number of free blocks in a block group. It is used when
@@ -276,9 +281,9 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
276} 281}
277 282
278static int ext4_valid_block_bitmap(struct super_block *sb, 283static int ext4_valid_block_bitmap(struct super_block *sb,
279 struct ext4_group_desc *desc, 284 struct ext4_group_desc *desc,
280 unsigned int block_group, 285 unsigned int block_group,
281 struct buffer_head *bh) 286 struct buffer_head *bh)
282{ 287{
283 ext4_grpblk_t offset; 288 ext4_grpblk_t offset;
284 ext4_grpblk_t next_zero_bit; 289 ext4_grpblk_t next_zero_bit;
@@ -325,6 +330,23 @@ err_out:
325 block_group, bitmap_blk); 330 block_group, bitmap_blk);
326 return 0; 331 return 0;
327} 332}
333
334void ext4_validate_block_bitmap(struct super_block *sb,
335 struct ext4_group_desc *desc,
336 unsigned int block_group,
337 struct buffer_head *bh)
338{
339 if (buffer_verified(bh))
340 return;
341
342 ext4_lock_group(sb, block_group);
343 if (ext4_valid_block_bitmap(sb, desc, block_group, bh) &&
344 ext4_block_bitmap_csum_verify(sb, block_group, desc, bh,
345 EXT4_BLOCKS_PER_GROUP(sb) / 8))
346 set_buffer_verified(bh);
347 ext4_unlock_group(sb, block_group);
348}
349
328/** 350/**
329 * ext4_read_block_bitmap() 351 * ext4_read_block_bitmap()
330 * @sb: super block 352 * @sb: super block
@@ -355,12 +377,12 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
355 } 377 }
356 378
357 if (bitmap_uptodate(bh)) 379 if (bitmap_uptodate(bh))
358 return bh; 380 goto verify;
359 381
360 lock_buffer(bh); 382 lock_buffer(bh);
361 if (bitmap_uptodate(bh)) { 383 if (bitmap_uptodate(bh)) {
362 unlock_buffer(bh); 384 unlock_buffer(bh);
363 return bh; 385 goto verify;
364 } 386 }
365 ext4_lock_group(sb, block_group); 387 ext4_lock_group(sb, block_group);
366 if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { 388 if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
@@ -379,7 +401,7 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
379 */ 401 */
380 set_bitmap_uptodate(bh); 402 set_bitmap_uptodate(bh);
381 unlock_buffer(bh); 403 unlock_buffer(bh);
382 return bh; 404 goto verify;
383 } 405 }
384 /* 406 /*
385 * submit the buffer_head for reading 407 * submit the buffer_head for reading
@@ -390,6 +412,9 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
390 get_bh(bh); 412 get_bh(bh);
391 submit_bh(READ, bh); 413 submit_bh(READ, bh);
392 return bh; 414 return bh;
415verify:
416 ext4_validate_block_bitmap(sb, desc, block_group, bh);
417 return bh;
393} 418}
394 419
395/* Returns 0 on success, 1 on error */ 420/* Returns 0 on success, 1 on error */
@@ -412,7 +437,7 @@ int ext4_wait_block_bitmap(struct super_block *sb, ext4_group_t block_group,
412 } 437 }
413 clear_buffer_new(bh); 438 clear_buffer_new(bh);
414 /* Panic or remount fs read-only if block bitmap is invalid */ 439 /* Panic or remount fs read-only if block bitmap is invalid */
415 ext4_valid_block_bitmap(sb, desc, block_group, bh); 440 ext4_validate_block_bitmap(sb, desc, block_group, bh);
416 return 0; 441 return 0;
417} 442}
418 443
diff --git a/fs/ext4/bitmap.c b/fs/ext4/bitmap.c
index 5813e7f2e2c6..b319721da26a 100644
--- a/fs/ext4/bitmap.c
+++ b/fs/ext4/bitmap.c
@@ -68,3 +68,47 @@ void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
68 if (sbi->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END) 68 if (sbi->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
69 gdp->bg_inode_bitmap_csum_hi = cpu_to_le16(csum >> 16); 69 gdp->bg_inode_bitmap_csum_hi = cpu_to_le16(csum >> 16);
70} 70}
71
72int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
73 struct ext4_group_desc *gdp,
74 struct buffer_head *bh, int sz)
75{
76 __u32 hi;
77 __u32 provided, calculated;
78 struct ext4_sb_info *sbi = EXT4_SB(sb);
79
80 if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
81 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
82 return 1;
83
84 provided = le16_to_cpu(gdp->bg_block_bitmap_csum_lo);
85 calculated = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz);
86 if (sbi->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_END) {
87 hi = le16_to_cpu(gdp->bg_block_bitmap_csum_hi);
88 provided |= (hi << 16);
89 } else
90 calculated &= 0xFFFF;
91
92 if (provided == calculated)
93 return 1;
94
95 ext4_error(sb, "Bad block bitmap checksum: block_group = %u", group);
96 return 0;
97}
98
99void ext4_block_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
100 struct ext4_group_desc *gdp,
101 struct buffer_head *bh, int sz)
102{
103 __u32 csum;
104 struct ext4_sb_info *sbi = EXT4_SB(sb);
105
106 if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
107 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
108 return;
109
110 csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz);
111 gdp->bg_block_bitmap_csum_lo = cpu_to_le16(csum & 0xFFFF);
112 if (sbi->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_END)
113 gdp->bg_block_bitmap_csum_hi = cpu_to_le16(csum >> 16);
114}
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 7f0ff88f32ba..7a4f16075257 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1857,8 +1857,18 @@ void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
1857int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, 1857int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
1858 struct ext4_group_desc *gdp, 1858 struct ext4_group_desc *gdp,
1859 struct buffer_head *bh, int sz); 1859 struct buffer_head *bh, int sz);
1860void ext4_block_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
1861 struct ext4_group_desc *gdp,
1862 struct buffer_head *bh, int sz);
1863int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
1864 struct ext4_group_desc *gdp,
1865 struct buffer_head *bh, int sz);
1860 1866
1861/* balloc.c */ 1867/* balloc.c */
1868extern void ext4_validate_block_bitmap(struct super_block *sb,
1869 struct ext4_group_desc *desc,
1870 unsigned int block_group,
1871 struct buffer_head *bh);
1862extern unsigned int ext4_block_group(struct super_block *sb, 1872extern unsigned int ext4_block_group(struct super_block *sb,
1863 ext4_fsblk_t blocknr); 1873 ext4_fsblk_t blocknr);
1864extern ext4_grpblk_t ext4_block_group_offset(struct super_block *sb, 1874extern ext4_grpblk_t ext4_block_group_offset(struct super_block *sb,
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index fb897ec183c8..a6383fcb714b 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -753,6 +753,10 @@ got:
753 gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); 753 gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
754 ext4_free_group_clusters_set(sb, gdp, 754 ext4_free_group_clusters_set(sb, gdp,
755 ext4_free_clusters_after_init(sb, group, gdp)); 755 ext4_free_clusters_after_init(sb, group, gdp));
756 ext4_block_bitmap_csum_set(sb, group, gdp,
757 block_bitmap_bh,
758 EXT4_BLOCKS_PER_GROUP(sb) /
759 8);
756 gdp->bg_checksum = ext4_group_desc_csum(sbi, group, 760 gdp->bg_checksum = ext4_group_desc_csum(sbi, group,
757 gdp); 761 gdp);
758 } 762 }
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 99ab428bcfa0..95a388fef397 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -788,7 +788,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
788 int first_block; 788 int first_block;
789 struct super_block *sb; 789 struct super_block *sb;
790 struct buffer_head *bhs; 790 struct buffer_head *bhs;
791 struct buffer_head **bh; 791 struct buffer_head **bh = NULL;
792 struct inode *inode; 792 struct inode *inode;
793 char *data; 793 char *data;
794 char *bitmap; 794 char *bitmap;
@@ -2797,6 +2797,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
2797 } 2797 }
2798 len = ext4_free_group_clusters(sb, gdp) - ac->ac_b_ex.fe_len; 2798 len = ext4_free_group_clusters(sb, gdp) - ac->ac_b_ex.fe_len;
2799 ext4_free_group_clusters_set(sb, gdp, len); 2799 ext4_free_group_clusters_set(sb, gdp, len);
2800 ext4_block_bitmap_csum_set(sb, ac->ac_b_ex.fe_group, gdp, bitmap_bh,
2801 EXT4_BLOCKS_PER_GROUP(sb) / 8);
2800 gdp->bg_checksum = ext4_group_desc_csum(sbi, ac->ac_b_ex.fe_group, gdp); 2802 gdp->bg_checksum = ext4_group_desc_csum(sbi, ac->ac_b_ex.fe_group, gdp);
2801 2803
2802 ext4_unlock_group(sb, ac->ac_b_ex.fe_group); 2804 ext4_unlock_group(sb, ac->ac_b_ex.fe_group);
@@ -4659,6 +4661,8 @@ do_more:
4659 4661
4660 ret = ext4_free_group_clusters(sb, gdp) + count_clusters; 4662 ret = ext4_free_group_clusters(sb, gdp) + count_clusters;
4661 ext4_free_group_clusters_set(sb, gdp, ret); 4663 ext4_free_group_clusters_set(sb, gdp, ret);
4664 ext4_block_bitmap_csum_set(sb, block_group, gdp, bitmap_bh,
4665 EXT4_BLOCKS_PER_GROUP(sb) / 8);
4662 gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp); 4666 gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp);
4663 ext4_unlock_group(sb, block_group); 4667 ext4_unlock_group(sb, block_group);
4664 percpu_counter_add(&sbi->s_freeclusters_counter, count_clusters); 4668 percpu_counter_add(&sbi->s_freeclusters_counter, count_clusters);
@@ -4803,6 +4807,8 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
4803 mb_free_blocks(NULL, &e4b, bit, count); 4807 mb_free_blocks(NULL, &e4b, bit, count);
4804 blk_free_count = blocks_freed + ext4_free_group_clusters(sb, desc); 4808 blk_free_count = blocks_freed + ext4_free_group_clusters(sb, desc);
4805 ext4_free_group_clusters_set(sb, desc, blk_free_count); 4809 ext4_free_group_clusters_set(sb, desc, blk_free_count);
4810 ext4_block_bitmap_csum_set(sb, block_group, desc, bitmap_bh,
4811 EXT4_BLOCKS_PER_GROUP(sb) / 8);
4806 desc->bg_checksum = ext4_group_desc_csum(sbi, block_group, desc); 4812 desc->bg_checksum = ext4_group_desc_csum(sbi, block_group, desc);
4807 ext4_unlock_group(sb, block_group); 4813 ext4_unlock_group(sb, block_group);
4808 percpu_counter_add(&sbi->s_freeclusters_counter, 4814 percpu_counter_add(&sbi->s_freeclusters_counter,
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index 7810cac241e1..dc597e066308 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -1107,6 +1107,13 @@ static int ext4_set_bitmap_checksums(struct super_block *sb,
1107 EXT4_INODES_PER_GROUP(sb) / 8); 1107 EXT4_INODES_PER_GROUP(sb) / 8);
1108 brelse(bh); 1108 brelse(bh);
1109 1109
1110 bh = ext4_get_bitmap(sb, group_data->block_bitmap);
1111 if (!bh)
1112 return -EIO;
1113 ext4_block_bitmap_csum_set(sb, group, gdp, bh,
1114 EXT4_BLOCKS_PER_GROUP(sb) / 8);
1115 brelse(bh);
1116
1110 return 0; 1117 return 0;
1111} 1118}
1112 1119