diff options
author | Darrick J. Wong <djwong@us.ibm.com> | 2012-04-29 18:33:10 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2012-04-29 18:33:10 -0400 |
commit | 41a246d1ff75a95d2be3191ca6e6db139dc0f430 (patch) | |
tree | 0b5150f476dd69726ffe7ea1ba83832c42b441be /fs/ext4 | |
parent | 814525f4df50a196464ce2c7abe91f693203060f (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.c | 39 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 20 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 34 | ||||
-rw-r--r-- | fs/ext4/resize.c | 47 |
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 | ||
32 | int 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 | |||
55 | void 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 */ |
1846 | extern unsigned int ext4_count_free(struct buffer_head *, unsigned); | 1853 | extern unsigned int ext4_count_free(struct buffer_head *, unsigned); |
1854 | void 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); | ||
1857 | int 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 */ |
1849 | extern unsigned int ext4_block_group(struct super_block *sb, | 1862 | extern 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, | |||
2094 | extern int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 group, | 2107 | extern 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 | ||
2110 | static 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 | |||
2097 | static inline ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es) | 2117 | static 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 | |||
181 | verify: | ||
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 | ||
1072 | static 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 | |||
1092 | static 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)); |