diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-04-01 13:48:14 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:01 -0400 |
commit | 0999df54f850fe1aba29b10d5c869493af107478 (patch) | |
tree | c67e0ca38e89d0872f6246093d962ce598b49ec7 /fs/btrfs/disk-io.c | |
parent | ecbe2402cb4e4e7413544dc392c1a78d0f290292 (diff) |
Btrfs: Verify checksums on tree blocks found without read_tree_block
Checksums were only verified by btrfs_read_tree_block, which meant the
functions to probe the page cache for blocks were not validating checksums.
Normally this is fine because the buffers will only be in cache if they
have already been validated.
But, there is a window while the buffer is being read from disk where
it could be up to date in the cache but not yet verified. This patch
makes sure all buffers go through checksum verification before they
are used.
This is safer, and it prevents modification of buffers before they go
through the csum code.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r-- | fs/btrfs/disk-io.c | 86 |
1 files changed, 50 insertions, 36 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 5547607681f4..e40fb318ad99 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -46,27 +46,6 @@ static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf) | |||
46 | 46 | ||
47 | static struct extent_io_ops btree_extent_io_ops; | 47 | static struct extent_io_ops btree_extent_io_ops; |
48 | 48 | ||
49 | struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, | ||
50 | u64 bytenr, u32 blocksize) | ||
51 | { | ||
52 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
53 | struct extent_buffer *eb; | ||
54 | eb = find_extent_buffer(&BTRFS_I(btree_inode)->io_tree, | ||
55 | bytenr, blocksize, GFP_NOFS); | ||
56 | return eb; | ||
57 | } | ||
58 | |||
59 | struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, | ||
60 | u64 bytenr, u32 blocksize) | ||
61 | { | ||
62 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
63 | struct extent_buffer *eb; | ||
64 | |||
65 | eb = alloc_extent_buffer(&BTRFS_I(btree_inode)->io_tree, | ||
66 | bytenr, blocksize, NULL, GFP_NOFS); | ||
67 | return eb; | ||
68 | } | ||
69 | |||
70 | struct extent_map *btree_get_extent(struct inode *inode, struct page *page, | 49 | struct extent_map *btree_get_extent(struct inode *inode, struct page *page, |
71 | size_t page_offset, u64 start, u64 len, | 50 | size_t page_offset, u64 start, u64 len, |
72 | int create) | 51 | int create) |
@@ -380,36 +359,29 @@ static int close_all_devices(struct btrfs_fs_info *fs_info) | |||
380 | return 0; | 359 | return 0; |
381 | } | 360 | } |
382 | 361 | ||
383 | struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, | 362 | int btrfs_verify_block_csum(struct btrfs_root *root, |
384 | u32 blocksize) | 363 | struct extent_buffer *buf) |
385 | { | 364 | { |
386 | struct extent_buffer *buf = NULL; | ||
387 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
388 | struct extent_io_tree *io_tree; | 365 | struct extent_io_tree *io_tree; |
389 | u64 end; | 366 | u64 end; |
390 | int ret; | 367 | int ret; |
391 | 368 | ||
392 | io_tree = &BTRFS_I(btree_inode)->io_tree; | 369 | io_tree = &BTRFS_I(root->fs_info->btree_inode)->io_tree; |
393 | |||
394 | buf = btrfs_find_create_tree_block(root, bytenr, blocksize); | ||
395 | if (!buf) | ||
396 | return NULL; | ||
397 | read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree, buf, 0, 1, | ||
398 | btree_get_extent); | ||
399 | |||
400 | if (buf->flags & EXTENT_CSUM) | 370 | if (buf->flags & EXTENT_CSUM) |
401 | return buf; | 371 | return 0; |
402 | 372 | ||
403 | end = buf->start + PAGE_CACHE_SIZE - 1; | 373 | end = min_t(u64, buf->len, PAGE_CACHE_SIZE); |
374 | end = buf->start + end - 1; | ||
404 | if (test_range_bit(io_tree, buf->start, end, EXTENT_CSUM, 1)) { | 375 | if (test_range_bit(io_tree, buf->start, end, EXTENT_CSUM, 1)) { |
405 | buf->flags |= EXTENT_CSUM; | 376 | buf->flags |= EXTENT_CSUM; |
406 | return buf; | 377 | return 0; |
407 | } | 378 | } |
408 | 379 | ||
409 | lock_extent(io_tree, buf->start, end, GFP_NOFS); | 380 | lock_extent(io_tree, buf->start, end, GFP_NOFS); |
410 | 381 | ||
411 | if (test_range_bit(io_tree, buf->start, end, EXTENT_CSUM, 1)) { | 382 | if (test_range_bit(io_tree, buf->start, end, EXTENT_CSUM, 1)) { |
412 | buf->flags |= EXTENT_CSUM; | 383 | buf->flags |= EXTENT_CSUM; |
384 | ret = 0; | ||
413 | goto out_unlock; | 385 | goto out_unlock; |
414 | } | 386 | } |
415 | 387 | ||
@@ -419,6 +391,48 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, | |||
419 | 391 | ||
420 | out_unlock: | 392 | out_unlock: |
421 | unlock_extent(io_tree, buf->start, end, GFP_NOFS); | 393 | unlock_extent(io_tree, buf->start, end, GFP_NOFS); |
394 | return ret; | ||
395 | } | ||
396 | |||
397 | struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, | ||
398 | u64 bytenr, u32 blocksize) | ||
399 | { | ||
400 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
401 | struct extent_buffer *eb; | ||
402 | eb = find_extent_buffer(&BTRFS_I(btree_inode)->io_tree, | ||
403 | bytenr, blocksize, GFP_NOFS); | ||
404 | return eb; | ||
405 | } | ||
406 | |||
407 | struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, | ||
408 | u64 bytenr, u32 blocksize) | ||
409 | { | ||
410 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
411 | struct extent_buffer *eb; | ||
412 | |||
413 | eb = alloc_extent_buffer(&BTRFS_I(btree_inode)->io_tree, | ||
414 | bytenr, blocksize, NULL, GFP_NOFS); | ||
415 | return eb; | ||
416 | } | ||
417 | |||
418 | |||
419 | struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, | ||
420 | u32 blocksize) | ||
421 | { | ||
422 | struct extent_buffer *buf = NULL; | ||
423 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
424 | struct extent_io_tree *io_tree; | ||
425 | int ret; | ||
426 | |||
427 | io_tree = &BTRFS_I(btree_inode)->io_tree; | ||
428 | |||
429 | buf = btrfs_find_create_tree_block(root, bytenr, blocksize); | ||
430 | if (!buf) | ||
431 | return NULL; | ||
432 | read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree, buf, 0, 1, | ||
433 | btree_get_extent); | ||
434 | |||
435 | ret = btrfs_verify_block_csum(root, buf); | ||
422 | return buf; | 436 | return buf; |
423 | } | 437 | } |
424 | 438 | ||