diff options
author | Darrick J. Wong <djwong@us.ibm.com> | 2012-04-29 18:35:10 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2012-04-29 18:35:10 -0400 |
commit | fa77dcfafeaa6bc73293c646bfc3d5192dcf0be2 (patch) | |
tree | 66c4232c2e5c1f59666e05164b77539a9b1dd290 | |
parent | 41a246d1ff75a95d2be3191ca6e6db139dc0f430 (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.c | 39 | ||||
-rw-r--r-- | fs/ext4/bitmap.c | 44 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 10 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 4 | ||||
-rw-r--r-- | fs/ext4/mballoc.c | 8 | ||||
-rw-r--r-- | fs/ext4/resize.c | 7 |
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 | ||
278 | static int ext4_valid_block_bitmap(struct super_block *sb, | 283 | static 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 | |||
334 | void 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; |
415 | verify: | ||
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 | |||
72 | int 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 | |||
99 | void 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, | |||
1857 | int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, | 1857 | int 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); |
1860 | void 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); | ||
1863 | int 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 */ |
1868 | extern 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); | ||
1862 | extern unsigned int ext4_block_group(struct super_block *sb, | 1872 | extern unsigned int ext4_block_group(struct super_block *sb, |
1863 | ext4_fsblk_t blocknr); | 1873 | ext4_fsblk_t blocknr); |
1864 | extern ext4_grpblk_t ext4_block_group_offset(struct super_block *sb, | 1874 | extern 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 | ||