aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/disk-io.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-04-01 13:48:14 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:01 -0400
commit0999df54f850fe1aba29b10d5c869493af107478 (patch)
treec67e0ca38e89d0872f6246093d962ce598b49ec7 /fs/btrfs/disk-io.c
parentecbe2402cb4e4e7413544dc392c1a78d0f290292 (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.c86
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
47static struct extent_io_ops btree_extent_io_ops; 47static struct extent_io_ops btree_extent_io_ops;
48 48
49struct 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
59struct 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
70struct extent_map *btree_get_extent(struct inode *inode, struct page *page, 49struct 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
383struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, 362int 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
420out_unlock: 392out_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
397struct 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
407struct 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
419struct 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