Skip to content

Commit fa77dcf

Browse files
Darrick J. Wongtytso
authored andcommitted
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 <[email protected]> Signed-off-by: "Theodore Ts'o" <[email protected]>
1 parent 41a246d commit fa77dcf

File tree

6 files changed

+104
-8
lines changed

6 files changed

+104
-8
lines changed

fs/ext4/balloc.c

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ void ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
174174
ext4_free_inodes_set(sb, gdp, 0);
175175
ext4_itable_unused_set(sb, gdp, 0);
176176
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);
177179
return;
178180
}
179181
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,
210212
*/
211213
ext4_mark_bitmap_end(num_clusters_in_group(sb, block_group),
212214
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);
213218
}
214219

215220
/* 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,
276281
}
277282

278283
static int ext4_valid_block_bitmap(struct super_block *sb,
279-
struct ext4_group_desc *desc,
280-
unsigned int block_group,
281-
struct buffer_head *bh)
284+
struct ext4_group_desc *desc,
285+
unsigned int block_group,
286+
struct buffer_head *bh)
282287
{
283288
ext4_grpblk_t offset;
284289
ext4_grpblk_t next_zero_bit;
@@ -325,6 +330,23 @@ static int ext4_valid_block_bitmap(struct super_block *sb,
325330
block_group, bitmap_blk);
326331
return 0;
327332
}
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+
328350
/**
329351
* ext4_read_block_bitmap()
330352
* @sb: super block
@@ -355,12 +377,12 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
355377
}
356378

357379
if (bitmap_uptodate(bh))
358-
return bh;
380+
goto verify;
359381

360382
lock_buffer(bh);
361383
if (bitmap_uptodate(bh)) {
362384
unlock_buffer(bh);
363-
return bh;
385+
goto verify;
364386
}
365387
ext4_lock_group(sb, block_group);
366388
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)
379401
*/
380402
set_bitmap_uptodate(bh);
381403
unlock_buffer(bh);
382-
return bh;
404+
goto verify;
383405
}
384406
/*
385407
* submit the buffer_head for reading
@@ -390,6 +412,9 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
390412
get_bh(bh);
391413
submit_bh(READ, bh);
392414
return bh;
415+
verify:
416+
ext4_validate_block_bitmap(sb, desc, block_group, bh);
417+
return bh;
393418
}
394419

395420
/* 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,
412437
}
413438
clear_buffer_new(bh);
414439
/* 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);
416441
return 0;
417442
}
418443

fs/ext4/bitmap.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,47 @@ void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
6868
if (sbi->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
6969
gdp->bg_inode_bitmap_csum_hi = cpu_to_le16(csum >> 16);
7070
}
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+
}

fs/ext4/ext4.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1857,8 +1857,18 @@ void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
18571857
int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
18581858
struct ext4_group_desc *gdp,
18591859
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);
18601866

18611867
/* 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);
18621872
extern unsigned int ext4_block_group(struct super_block *sb,
18631873
ext4_fsblk_t blocknr);
18641874
extern ext4_grpblk_t ext4_block_group_offset(struct super_block *sb,

fs/ext4/ialloc.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,10 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, umode_t mode,
753753
gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
754754
ext4_free_group_clusters_set(sb, gdp,
755755
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);
756760
gdp->bg_checksum = ext4_group_desc_csum(sbi, group,
757761
gdp);
758762
}

fs/ext4/mballoc.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
788788
int first_block;
789789
struct super_block *sb;
790790
struct buffer_head *bhs;
791-
struct buffer_head **bh;
791+
struct buffer_head **bh = NULL;
792792
struct inode *inode;
793793
char *data;
794794
char *bitmap;
@@ -2797,6 +2797,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
27972797
}
27982798
len = ext4_free_group_clusters(sb, gdp) - ac->ac_b_ex.fe_len;
27992799
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);
28002802
gdp->bg_checksum = ext4_group_desc_csum(sbi, ac->ac_b_ex.fe_group, gdp);
28012803

28022804
ext4_unlock_group(sb, ac->ac_b_ex.fe_group);
@@ -4659,6 +4661,8 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
46594661

46604662
ret = ext4_free_group_clusters(sb, gdp) + count_clusters;
46614663
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);
46624666
gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp);
46634667
ext4_unlock_group(sb, block_group);
46644668
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,
48034807
mb_free_blocks(NULL, &e4b, bit, count);
48044808
blk_free_count = blocks_freed + ext4_free_group_clusters(sb, desc);
48054809
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);
48064812
desc->bg_checksum = ext4_group_desc_csum(sbi, block_group, desc);
48074813
ext4_unlock_group(sb, block_group);
48084814
percpu_counter_add(&sbi->s_freeclusters_counter,

fs/ext4/resize.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,6 +1107,13 @@ static int ext4_set_bitmap_checksums(struct super_block *sb,
11071107
EXT4_INODES_PER_GROUP(sb) / 8);
11081108
brelse(bh);
11091109

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+
11101117
return 0;
11111118
}
11121119

0 commit comments

Comments
 (0)