aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@us.ibm.com>2012-04-29 18:33:10 -0400
committerTheodore Ts'o <tytso@mit.edu>2012-04-29 18:33:10 -0400
commit41a246d1ff75a95d2be3191ca6e6db139dc0f430 (patch)
tree0b5150f476dd69726ffe7ea1ba83832c42b441be /fs/ext4
parent814525f4df50a196464ce2c7abe91f693203060f (diff)
ext4: calculate and verify checksums for inode bitmaps
Compute and verify the checksum of the inode bitmap; the checkum 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>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/bitmap.c39
-rw-r--r--fs/ext4/ext4.h20
-rw-r--r--fs/ext4/ialloc.c34
-rw-r--r--fs/ext4/resize.c47
4 files changed, 135 insertions, 5 deletions
diff --git a/fs/ext4/bitmap.c b/fs/ext4/bitmap.c
index fa3af81ac565..5813e7f2e2c6 100644
--- a/fs/ext4/bitmap.c
+++ b/fs/ext4/bitmap.c
@@ -29,3 +29,42 @@ unsigned int ext4_count_free(struct buffer_head *map, unsigned int numchars)
29 29
30#endif /* EXT4FS_DEBUG */ 30#endif /* EXT4FS_DEBUG */
31 31
32int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
33 struct ext4_group_desc *gdp,
34 struct buffer_head *bh, int sz)
35{
36 __u32 hi;
37 __u32 provided, calculated;
38 struct ext4_sb_info *sbi = EXT4_SB(sb);
39
40 if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
41 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
42 return 1;
43
44 provided = le16_to_cpu(gdp->bg_inode_bitmap_csum_lo);
45 calculated = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz);
46 if (sbi->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END) {
47 hi = le16_to_cpu(gdp->bg_inode_bitmap_csum_hi);
48 provided |= (hi << 16);
49 } else
50 calculated &= 0xFFFF;
51
52 return provided == calculated;
53}
54
55void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
56 struct ext4_group_desc *gdp,
57 struct buffer_head *bh, int sz)
58{
59 __u32 csum;
60 struct ext4_sb_info *sbi = EXT4_SB(sb);
61
62 if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
63 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
64 return;
65
66 csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz);
67 gdp->bg_inode_bitmap_csum_lo = cpu_to_le16(csum & 0xFFFF);
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);
70}
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index ca96401b4b81..7f0ff88f32ba 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -317,6 +317,13 @@ struct ext4_group_desc
317 __u32 bg_reserved; 317 __u32 bg_reserved;
318}; 318};
319 319
320#define EXT4_BG_INODE_BITMAP_CSUM_HI_END \
321 (offsetof(struct ext4_group_desc, bg_inode_bitmap_csum_hi) + \
322 sizeof(__le16))
323#define EXT4_BG_BLOCK_BITMAP_CSUM_HI_END \
324 (offsetof(struct ext4_group_desc, bg_block_bitmap_csum_hi) + \
325 sizeof(__le16))
326
320/* 327/*
321 * Structure of a flex block group info 328 * Structure of a flex block group info
322 */ 329 */
@@ -1844,6 +1851,12 @@ struct mmpd_data {
1844 1851
1845/* bitmap.c */ 1852/* bitmap.c */
1846extern unsigned int ext4_count_free(struct buffer_head *, unsigned); 1853extern unsigned int ext4_count_free(struct buffer_head *, unsigned);
1854void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
1855 struct ext4_group_desc *gdp,
1856 struct buffer_head *bh, int sz);
1857int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
1858 struct ext4_group_desc *gdp,
1859 struct buffer_head *bh, int sz);
1847 1860
1848/* balloc.c */ 1861/* balloc.c */
1849extern unsigned int ext4_block_group(struct super_block *sb, 1862extern unsigned int ext4_block_group(struct super_block *sb,
@@ -2094,6 +2107,13 @@ extern __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 group,
2094extern int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 group, 2107extern int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 group,
2095 struct ext4_group_desc *gdp); 2108 struct ext4_group_desc *gdp);
2096 2109
2110static inline int ext4_has_group_desc_csum(struct super_block *sb)
2111{
2112 return EXT4_HAS_RO_COMPAT_FEATURE(sb,
2113 EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
2114 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM);
2115}
2116
2097static inline ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es) 2117static inline ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es)
2098{ 2118{
2099 return ((ext4_fsblk_t)le32_to_cpu(es->s_blocks_count_hi) << 32) | 2119 return ((ext4_fsblk_t)le32_to_cpu(es->s_blocks_count_hi) << 32) |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 8207dfab2682..fb897ec183c8 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -82,12 +82,17 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb,
82 ext4_free_inodes_set(sb, gdp, 0); 82 ext4_free_inodes_set(sb, gdp, 0);
83 ext4_itable_unused_set(sb, gdp, 0); 83 ext4_itable_unused_set(sb, gdp, 0);
84 memset(bh->b_data, 0xff, sb->s_blocksize); 84 memset(bh->b_data, 0xff, sb->s_blocksize);
85 ext4_inode_bitmap_csum_set(sb, block_group, gdp, bh,
86 EXT4_INODES_PER_GROUP(sb) / 8);
85 return 0; 87 return 0;
86 } 88 }
87 89
88 memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8); 90 memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
89 ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8, 91 ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8,
90 bh->b_data); 92 bh->b_data);
93 ext4_inode_bitmap_csum_set(sb, block_group, gdp, bh,
94 EXT4_INODES_PER_GROUP(sb) / 8);
95 gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp);
91 96
92 return EXT4_INODES_PER_GROUP(sb); 97 return EXT4_INODES_PER_GROUP(sb);
93} 98}
@@ -128,12 +133,12 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
128 return NULL; 133 return NULL;
129 } 134 }
130 if (bitmap_uptodate(bh)) 135 if (bitmap_uptodate(bh))
131 return bh; 136 goto verify;
132 137
133 lock_buffer(bh); 138 lock_buffer(bh);
134 if (bitmap_uptodate(bh)) { 139 if (bitmap_uptodate(bh)) {
135 unlock_buffer(bh); 140 unlock_buffer(bh);
136 return bh; 141 goto verify;
137 } 142 }
138 143
139 ext4_lock_group(sb, block_group); 144 ext4_lock_group(sb, block_group);
@@ -141,6 +146,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
141 ext4_init_inode_bitmap(sb, bh, block_group, desc); 146 ext4_init_inode_bitmap(sb, bh, block_group, desc);
142 set_bitmap_uptodate(bh); 147 set_bitmap_uptodate(bh);
143 set_buffer_uptodate(bh); 148 set_buffer_uptodate(bh);
149 set_buffer_verified(bh);
144 ext4_unlock_group(sb, block_group); 150 ext4_unlock_group(sb, block_group);
145 unlock_buffer(bh); 151 unlock_buffer(bh);
146 return bh; 152 return bh;
@@ -154,7 +160,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
154 */ 160 */
155 set_bitmap_uptodate(bh); 161 set_bitmap_uptodate(bh);
156 unlock_buffer(bh); 162 unlock_buffer(bh);
157 return bh; 163 goto verify;
158 } 164 }
159 /* 165 /*
160 * submit the buffer_head for reading 166 * submit the buffer_head for reading
@@ -171,6 +177,20 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
171 block_group, bitmap_blk); 177 block_group, bitmap_blk);
172 return NULL; 178 return NULL;
173 } 179 }
180
181verify:
182 ext4_lock_group(sb, block_group);
183 if (!buffer_verified(bh) &&
184 !ext4_inode_bitmap_csum_verify(sb, block_group, desc, bh,
185 EXT4_INODES_PER_GROUP(sb) / 8)) {
186 ext4_unlock_group(sb, block_group);
187 put_bh(bh);
188 ext4_error(sb, "Corrupt inode bitmap - block_group = %u, "
189 "inode_bitmap = %llu", block_group, bitmap_blk);
190 return NULL;
191 }
192 ext4_unlock_group(sb, block_group);
193 set_buffer_verified(bh);
174 return bh; 194 return bh;
175} 195}
176 196
@@ -276,6 +296,8 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
276 ext4_used_dirs_set(sb, gdp, count); 296 ext4_used_dirs_set(sb, gdp, count);
277 percpu_counter_dec(&sbi->s_dirs_counter); 297 percpu_counter_dec(&sbi->s_dirs_counter);
278 } 298 }
299 ext4_inode_bitmap_csum_set(sb, block_group, gdp, bitmap_bh,
300 EXT4_INODES_PER_GROUP(sb) / 8);
279 gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp); 301 gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp);
280 ext4_unlock_group(sb, block_group); 302 ext4_unlock_group(sb, block_group);
281 303
@@ -751,7 +773,7 @@ got:
751 goto fail; 773 goto fail;
752 774
753 /* Update the relevant bg descriptor fields */ 775 /* Update the relevant bg descriptor fields */
754 if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { 776 if (ext4_has_group_desc_csum(sb)) {
755 int free; 777 int free;
756 struct ext4_group_info *grp = ext4_get_group_info(sb, group); 778 struct ext4_group_info *grp = ext4_get_group_info(sb, group);
757 779
@@ -782,7 +804,9 @@ got:
782 atomic_inc(&sbi->s_flex_groups[f].used_dirs); 804 atomic_inc(&sbi->s_flex_groups[f].used_dirs);
783 } 805 }
784 } 806 }
785 if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { 807 if (ext4_has_group_desc_csum(sb)) {
808 ext4_inode_bitmap_csum_set(sb, group, gdp, inode_bitmap_bh,
809 EXT4_INODES_PER_GROUP(sb) / 8);
786 gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp); 810 gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp);
787 ext4_unlock_group(sb, group); 811 ext4_unlock_group(sb, group);
788 } 812 }
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index e0374757a94b..7810cac241e1 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -1069,6 +1069,47 @@ static int ext4_add_new_descs(handle_t *handle, struct super_block *sb,
1069 return err; 1069 return err;
1070} 1070}
1071 1071
1072static struct buffer_head *ext4_get_bitmap(struct super_block *sb, __u64 block)
1073{
1074 struct buffer_head *bh = sb_getblk(sb, block);
1075 if (!bh)
1076 return NULL;
1077
1078 if (bitmap_uptodate(bh))
1079 return bh;
1080
1081 lock_buffer(bh);
1082 if (bh_submit_read(bh) < 0) {
1083 unlock_buffer(bh);
1084 brelse(bh);
1085 return NULL;
1086 }
1087 unlock_buffer(bh);
1088
1089 return bh;
1090}
1091
1092static int ext4_set_bitmap_checksums(struct super_block *sb,
1093 ext4_group_t group,
1094 struct ext4_group_desc *gdp,
1095 struct ext4_new_group_data *group_data)
1096{
1097 struct buffer_head *bh;
1098
1099 if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
1100 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
1101 return 0;
1102
1103 bh = ext4_get_bitmap(sb, group_data->inode_bitmap);
1104 if (!bh)
1105 return -EIO;
1106 ext4_inode_bitmap_csum_set(sb, group, gdp, bh,
1107 EXT4_INODES_PER_GROUP(sb) / 8);
1108 brelse(bh);
1109
1110 return 0;
1111}
1112
1072/* 1113/*
1073 * ext4_setup_new_descs() will set up the group descriptor descriptors of a flex bg 1114 * ext4_setup_new_descs() will set up the group descriptor descriptors of a flex bg
1074 */ 1115 */
@@ -1101,6 +1142,12 @@ static int ext4_setup_new_descs(handle_t *handle, struct super_block *sb,
1101 memset(gdp, 0, EXT4_DESC_SIZE(sb)); 1142 memset(gdp, 0, EXT4_DESC_SIZE(sb));
1102 ext4_block_bitmap_set(sb, gdp, group_data->block_bitmap); 1143 ext4_block_bitmap_set(sb, gdp, group_data->block_bitmap);
1103 ext4_inode_bitmap_set(sb, gdp, group_data->inode_bitmap); 1144 ext4_inode_bitmap_set(sb, gdp, group_data->inode_bitmap);
1145 err = ext4_set_bitmap_checksums(sb, group, gdp, group_data);
1146 if (err) {
1147 ext4_std_error(sb, err);
1148 break;
1149 }
1150
1104 ext4_inode_table_set(sb, gdp, group_data->inode_table); 1151 ext4_inode_table_set(sb, gdp, group_data->inode_table);
1105 ext4_free_group_clusters_set(sb, gdp, 1152 ext4_free_group_clusters_set(sb, gdp,
1106 EXT4_B2C(sbi, group_data->free_blocks_count)); 1153 EXT4_B2C(sbi, group_data->free_blocks_count));