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>
This commit is contained in:
		
					parent
					
						
							
								41a246d1ff
							
						
					
				
			
			
				commit
				
					
						fa77dcfafe
					
				
			
		
					 6 changed files with 104 additions and 8 deletions
				
			
		|  | @ -174,6 +174,8 @@ void ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, | ||||||
| 		ext4_free_inodes_set(sb, gdp, 0); | 		ext4_free_inodes_set(sb, gdp, 0); | ||||||
| 		ext4_itable_unused_set(sb, gdp, 0); | 		ext4_itable_unused_set(sb, gdp, 0); | ||||||
| 		memset(bh->b_data, 0xff, sb->s_blocksize); | 		memset(bh->b_data, 0xff, sb->s_blocksize); | ||||||
|  | 		ext4_block_bitmap_csum_set(sb, block_group, gdp, bh, | ||||||
|  | 					   EXT4_BLOCKS_PER_GROUP(sb) / 8); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
| 	memset(bh->b_data, 0, sb->s_blocksize); | 	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, | ||||||
| 	 */ | 	 */ | ||||||
| 	ext4_mark_bitmap_end(num_clusters_in_group(sb, block_group), | 	ext4_mark_bitmap_end(num_clusters_in_group(sb, block_group), | ||||||
| 			     sb->s_blocksize * 8, bh->b_data); | 			     sb->s_blocksize * 8, bh->b_data); | ||||||
|  | 	ext4_block_bitmap_csum_set(sb, block_group, gdp, bh, | ||||||
|  | 				   EXT4_BLOCKS_PER_GROUP(sb) / 8); | ||||||
|  | 	gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Return the number of free blocks in a block group.  It is used when
 | /* 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, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int ext4_valid_block_bitmap(struct super_block *sb, | static int ext4_valid_block_bitmap(struct super_block *sb, | ||||||
| 					struct ext4_group_desc *desc, | 				   struct ext4_group_desc *desc, | ||||||
| 					unsigned int block_group, | 				   unsigned int block_group, | ||||||
| 					struct buffer_head *bh) | 				   struct buffer_head *bh) | ||||||
| { | { | ||||||
| 	ext4_grpblk_t offset; | 	ext4_grpblk_t offset; | ||||||
| 	ext4_grpblk_t next_zero_bit; | 	ext4_grpblk_t next_zero_bit; | ||||||
|  | @ -325,6 +330,23 @@ err_out: | ||||||
| 			block_group, bitmap_blk); | 			block_group, bitmap_blk); | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void ext4_validate_block_bitmap(struct super_block *sb, | ||||||
|  | 			       struct ext4_group_desc *desc, | ||||||
|  | 			       unsigned int block_group, | ||||||
|  | 			       struct buffer_head *bh) | ||||||
|  | { | ||||||
|  | 	if (buffer_verified(bh)) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	ext4_lock_group(sb, block_group); | ||||||
|  | 	if (ext4_valid_block_bitmap(sb, desc, block_group, bh) && | ||||||
|  | 	    ext4_block_bitmap_csum_verify(sb, block_group, desc, bh, | ||||||
|  | 					  EXT4_BLOCKS_PER_GROUP(sb) / 8)) | ||||||
|  | 		set_buffer_verified(bh); | ||||||
|  | 	ext4_unlock_group(sb, block_group); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * ext4_read_block_bitmap() |  * ext4_read_block_bitmap() | ||||||
|  * @sb:			super block |  * @sb:			super block | ||||||
|  | @ -355,12 +377,12 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (bitmap_uptodate(bh)) | 	if (bitmap_uptodate(bh)) | ||||||
| 		return bh; | 		goto verify; | ||||||
| 
 | 
 | ||||||
| 	lock_buffer(bh); | 	lock_buffer(bh); | ||||||
| 	if (bitmap_uptodate(bh)) { | 	if (bitmap_uptodate(bh)) { | ||||||
| 		unlock_buffer(bh); | 		unlock_buffer(bh); | ||||||
| 		return bh; | 		goto verify; | ||||||
| 	} | 	} | ||||||
| 	ext4_lock_group(sb, block_group); | 	ext4_lock_group(sb, block_group); | ||||||
| 	if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { | 	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) | ||||||
| 		 */ | 		 */ | ||||||
| 		set_bitmap_uptodate(bh); | 		set_bitmap_uptodate(bh); | ||||||
| 		unlock_buffer(bh); | 		unlock_buffer(bh); | ||||||
| 		return bh; | 		goto verify; | ||||||
| 	} | 	} | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * submit the buffer_head for reading | 	 * submit the buffer_head for reading | ||||||
|  | @ -390,6 +412,9 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) | ||||||
| 	get_bh(bh); | 	get_bh(bh); | ||||||
| 	submit_bh(READ, bh); | 	submit_bh(READ, bh); | ||||||
| 	return bh; | 	return bh; | ||||||
|  | verify: | ||||||
|  | 	ext4_validate_block_bitmap(sb, desc, block_group, bh); | ||||||
|  | 	return bh; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Returns 0 on success, 1 on error */ | /* 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, | ||||||
| 	} | 	} | ||||||
| 	clear_buffer_new(bh); | 	clear_buffer_new(bh); | ||||||
| 	/* Panic or remount fs read-only if block bitmap is invalid */ | 	/* Panic or remount fs read-only if block bitmap is invalid */ | ||||||
| 	ext4_valid_block_bitmap(sb, desc, block_group, bh); | 	ext4_validate_block_bitmap(sb, desc, block_group, bh); | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -68,3 +68,47 @@ void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group, | ||||||
| 	if (sbi->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END) | 	if (sbi->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END) | ||||||
| 		gdp->bg_inode_bitmap_csum_hi = cpu_to_le16(csum >> 16); | 		gdp->bg_inode_bitmap_csum_hi = cpu_to_le16(csum >> 16); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, | ||||||
|  | 				  struct ext4_group_desc *gdp, | ||||||
|  | 				  struct buffer_head *bh, int sz) | ||||||
|  | { | ||||||
|  | 	__u32 hi; | ||||||
|  | 	__u32 provided, calculated; | ||||||
|  | 	struct ext4_sb_info *sbi = EXT4_SB(sb); | ||||||
|  | 
 | ||||||
|  | 	if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||||||
|  | 					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||||||
|  | 		return 1; | ||||||
|  | 
 | ||||||
|  | 	provided = le16_to_cpu(gdp->bg_block_bitmap_csum_lo); | ||||||
|  | 	calculated = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz); | ||||||
|  | 	if (sbi->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_END) { | ||||||
|  | 		hi = le16_to_cpu(gdp->bg_block_bitmap_csum_hi); | ||||||
|  | 		provided |= (hi << 16); | ||||||
|  | 	} else | ||||||
|  | 		calculated &= 0xFFFF; | ||||||
|  | 
 | ||||||
|  | 	if (provided == calculated) | ||||||
|  | 		return 1; | ||||||
|  | 
 | ||||||
|  | 	ext4_error(sb, "Bad block bitmap checksum: block_group = %u", group); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ext4_block_bitmap_csum_set(struct super_block *sb, ext4_group_t group, | ||||||
|  | 				struct ext4_group_desc *gdp, | ||||||
|  | 				struct buffer_head *bh, int sz) | ||||||
|  | { | ||||||
|  | 	__u32 csum; | ||||||
|  | 	struct ext4_sb_info *sbi = EXT4_SB(sb); | ||||||
|  | 
 | ||||||
|  | 	if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||||||
|  | 			EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz); | ||||||
|  | 	gdp->bg_block_bitmap_csum_lo = cpu_to_le16(csum & 0xFFFF); | ||||||
|  | 	if (sbi->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_END) | ||||||
|  | 		gdp->bg_block_bitmap_csum_hi = cpu_to_le16(csum >> 16); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -1857,8 +1857,18 @@ void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group, | ||||||
| int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, | int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, | ||||||
| 				  struct ext4_group_desc *gdp, | 				  struct ext4_group_desc *gdp, | ||||||
| 				  struct buffer_head *bh, int sz); | 				  struct buffer_head *bh, int sz); | ||||||
|  | void ext4_block_bitmap_csum_set(struct super_block *sb, ext4_group_t group, | ||||||
|  | 				struct ext4_group_desc *gdp, | ||||||
|  | 				struct buffer_head *bh, int sz); | ||||||
|  | int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, | ||||||
|  | 				  struct ext4_group_desc *gdp, | ||||||
|  | 				  struct buffer_head *bh, int sz); | ||||||
| 
 | 
 | ||||||
| /* balloc.c */ | /* balloc.c */ | ||||||
|  | extern void ext4_validate_block_bitmap(struct super_block *sb, | ||||||
|  | 				       struct ext4_group_desc *desc, | ||||||
|  | 				       unsigned int block_group, | ||||||
|  | 				       struct buffer_head *bh); | ||||||
| extern unsigned int ext4_block_group(struct super_block *sb, | extern unsigned int ext4_block_group(struct super_block *sb, | ||||||
| 			ext4_fsblk_t blocknr); | 			ext4_fsblk_t blocknr); | ||||||
| extern ext4_grpblk_t ext4_block_group_offset(struct super_block *sb, | extern ext4_grpblk_t ext4_block_group_offset(struct super_block *sb, | ||||||
|  |  | ||||||
|  | @ -753,6 +753,10 @@ got: | ||||||
| 			gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); | 			gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); | ||||||
| 			ext4_free_group_clusters_set(sb, gdp, | 			ext4_free_group_clusters_set(sb, gdp, | ||||||
| 				ext4_free_clusters_after_init(sb, group, gdp)); | 				ext4_free_clusters_after_init(sb, group, gdp)); | ||||||
|  | 			ext4_block_bitmap_csum_set(sb, group, gdp, | ||||||
|  | 						   block_bitmap_bh, | ||||||
|  | 						   EXT4_BLOCKS_PER_GROUP(sb) / | ||||||
|  | 						   8); | ||||||
| 			gdp->bg_checksum = ext4_group_desc_csum(sbi, group, | 			gdp->bg_checksum = ext4_group_desc_csum(sbi, group, | ||||||
| 								gdp); | 								gdp); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -788,7 +788,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore) | ||||||
| 	int first_block; | 	int first_block; | ||||||
| 	struct super_block *sb; | 	struct super_block *sb; | ||||||
| 	struct buffer_head *bhs; | 	struct buffer_head *bhs; | ||||||
| 	struct buffer_head **bh; | 	struct buffer_head **bh = NULL; | ||||||
| 	struct inode *inode; | 	struct inode *inode; | ||||||
| 	char *data; | 	char *data; | ||||||
| 	char *bitmap; | 	char *bitmap; | ||||||
|  | @ -2797,6 +2797,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, | ||||||
| 	} | 	} | ||||||
| 	len = ext4_free_group_clusters(sb, gdp) - ac->ac_b_ex.fe_len; | 	len = ext4_free_group_clusters(sb, gdp) - ac->ac_b_ex.fe_len; | ||||||
| 	ext4_free_group_clusters_set(sb, gdp, len); | 	ext4_free_group_clusters_set(sb, gdp, len); | ||||||
|  | 	ext4_block_bitmap_csum_set(sb, ac->ac_b_ex.fe_group, gdp, bitmap_bh, | ||||||
|  | 				   EXT4_BLOCKS_PER_GROUP(sb) / 8); | ||||||
| 	gdp->bg_checksum = ext4_group_desc_csum(sbi, ac->ac_b_ex.fe_group, gdp); | 	gdp->bg_checksum = ext4_group_desc_csum(sbi, ac->ac_b_ex.fe_group, gdp); | ||||||
| 
 | 
 | ||||||
| 	ext4_unlock_group(sb, ac->ac_b_ex.fe_group); | 	ext4_unlock_group(sb, ac->ac_b_ex.fe_group); | ||||||
|  | @ -4659,6 +4661,8 @@ do_more: | ||||||
| 
 | 
 | ||||||
| 	ret = ext4_free_group_clusters(sb, gdp) + count_clusters; | 	ret = ext4_free_group_clusters(sb, gdp) + count_clusters; | ||||||
| 	ext4_free_group_clusters_set(sb, gdp, ret); | 	ext4_free_group_clusters_set(sb, gdp, ret); | ||||||
|  | 	ext4_block_bitmap_csum_set(sb, block_group, gdp, bitmap_bh, | ||||||
|  | 				   EXT4_BLOCKS_PER_GROUP(sb) / 8); | ||||||
| 	gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp); | 	gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp); | ||||||
| 	ext4_unlock_group(sb, block_group); | 	ext4_unlock_group(sb, block_group); | ||||||
| 	percpu_counter_add(&sbi->s_freeclusters_counter, count_clusters); | 	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, | ||||||
| 	mb_free_blocks(NULL, &e4b, bit, count); | 	mb_free_blocks(NULL, &e4b, bit, count); | ||||||
| 	blk_free_count = blocks_freed + ext4_free_group_clusters(sb, desc); | 	blk_free_count = blocks_freed + ext4_free_group_clusters(sb, desc); | ||||||
| 	ext4_free_group_clusters_set(sb, desc, blk_free_count); | 	ext4_free_group_clusters_set(sb, desc, blk_free_count); | ||||||
|  | 	ext4_block_bitmap_csum_set(sb, block_group, desc, bitmap_bh, | ||||||
|  | 				   EXT4_BLOCKS_PER_GROUP(sb) / 8); | ||||||
| 	desc->bg_checksum = ext4_group_desc_csum(sbi, block_group, desc); | 	desc->bg_checksum = ext4_group_desc_csum(sbi, block_group, desc); | ||||||
| 	ext4_unlock_group(sb, block_group); | 	ext4_unlock_group(sb, block_group); | ||||||
| 	percpu_counter_add(&sbi->s_freeclusters_counter, | 	percpu_counter_add(&sbi->s_freeclusters_counter, | ||||||
|  |  | ||||||
|  | @ -1107,6 +1107,13 @@ static int ext4_set_bitmap_checksums(struct super_block *sb, | ||||||
| 				   EXT4_INODES_PER_GROUP(sb) / 8); | 				   EXT4_INODES_PER_GROUP(sb) / 8); | ||||||
| 	brelse(bh); | 	brelse(bh); | ||||||
| 
 | 
 | ||||||
|  | 	bh = ext4_get_bitmap(sb, group_data->block_bitmap); | ||||||
|  | 	if (!bh) | ||||||
|  | 		return -EIO; | ||||||
|  | 	ext4_block_bitmap_csum_set(sb, group, gdp, bh, | ||||||
|  | 				   EXT4_BLOCKS_PER_GROUP(sb) / 8); | ||||||
|  | 	brelse(bh); | ||||||
|  | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Darrick J. Wong
				Darrick J. Wong