diff options
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r-- | fs/btrfs/disk-io.c | 25 |
1 files changed, 20 insertions, 5 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index dfd5ba05ce45..3eb7c2576fe5 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -176,7 +176,9 @@ void btrfs_csum_final(u32 crc, char *result) | |||
176 | static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, | 176 | static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, |
177 | int verify) | 177 | int verify) |
178 | { | 178 | { |
179 | char result[BTRFS_CRC32_SIZE]; | 179 | u16 csum_size = |
180 | btrfs_super_csum_size(&root->fs_info->super_copy); | ||
181 | char *result = NULL; | ||
180 | unsigned long len; | 182 | unsigned long len; |
181 | unsigned long cur_len; | 183 | unsigned long cur_len; |
182 | unsigned long offset = BTRFS_CSUM_SIZE; | 184 | unsigned long offset = BTRFS_CSUM_SIZE; |
@@ -186,6 +188,7 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, | |||
186 | unsigned long map_len; | 188 | unsigned long map_len; |
187 | int err; | 189 | int err; |
188 | u32 crc = ~(u32)0; | 190 | u32 crc = ~(u32)0; |
191 | unsigned long inline_result; | ||
189 | 192 | ||
190 | len = buf->len - offset; | 193 | len = buf->len - offset; |
191 | while(len > 0) { | 194 | while(len > 0) { |
@@ -204,25 +207,37 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, | |||
204 | offset += cur_len; | 207 | offset += cur_len; |
205 | unmap_extent_buffer(buf, map_token, KM_USER0); | 208 | unmap_extent_buffer(buf, map_token, KM_USER0); |
206 | } | 209 | } |
210 | if (csum_size > sizeof(inline_result)) { | ||
211 | result = kzalloc(csum_size * sizeof(char), GFP_NOFS); | ||
212 | if (!result) | ||
213 | return 1; | ||
214 | } else { | ||
215 | result = (char *)&inline_result; | ||
216 | } | ||
217 | |||
207 | btrfs_csum_final(crc, result); | 218 | btrfs_csum_final(crc, result); |
208 | 219 | ||
209 | if (verify) { | 220 | if (verify) { |
210 | /* FIXME, this is not good */ | 221 | /* FIXME, this is not good */ |
211 | if (memcmp_extent_buffer(buf, result, 0, BTRFS_CRC32_SIZE)) { | 222 | if (memcmp_extent_buffer(buf, result, 0, csum_size)) { |
212 | u32 val; | 223 | u32 val; |
213 | u32 found = 0; | 224 | u32 found = 0; |
214 | memcpy(&found, result, BTRFS_CRC32_SIZE); | 225 | memcpy(&found, result, csum_size); |
215 | 226 | ||
216 | read_extent_buffer(buf, &val, 0, BTRFS_CRC32_SIZE); | 227 | read_extent_buffer(buf, &val, 0, csum_size); |
217 | printk("btrfs: %s checksum verify failed on %llu " | 228 | printk("btrfs: %s checksum verify failed on %llu " |
218 | "wanted %X found %X level %d\n", | 229 | "wanted %X found %X level %d\n", |
219 | root->fs_info->sb->s_id, | 230 | root->fs_info->sb->s_id, |
220 | buf->start, val, found, btrfs_header_level(buf)); | 231 | buf->start, val, found, btrfs_header_level(buf)); |
232 | if (result != (char *)&inline_result) | ||
233 | kfree(result); | ||
221 | return 1; | 234 | return 1; |
222 | } | 235 | } |
223 | } else { | 236 | } else { |
224 | write_extent_buffer(buf, result, 0, BTRFS_CRC32_SIZE); | 237 | write_extent_buffer(buf, result, 0, csum_size); |
225 | } | 238 | } |
239 | if (result != (char *)&inline_result) | ||
240 | kfree(result); | ||
226 | return 0; | 241 | return 0; |
227 | } | 242 | } |
228 | 243 | ||