Shaohua Li
2011-Jan-19 01:15 UTC
[PATCH v3 5/5] validate extent_buffer if it''s readahead in btrfs
do validation for extent_buffer if it''s skipped before With metadata readahead, we slightly change the behavior. Before it, we allocate an extent_buffer (so set page->private), do metadata read and btree_readpage_end_io_hook() will do validation. After it, we directly do metadata readahead, and since in this case page hasn''t ->private, btree_readpage_end_io_hook() will not do validation. This patch fixes this. It addes a new flag to indicate if a buffer is validated. If not and even the buffer is uptodated, we will do a validation. Signed-off-by: Shaohua Li <shaohua.li@intel.com> --- fs/btrfs/disk-io.c | 71 ++++++++++++++++++++++++++++++------------------- fs/btrfs/disk-io.h | 2 + fs/btrfs/extent-tree.c | 1 fs/btrfs/extent_io.c | 14 ++++++++- fs/btrfs/extent_io.h | 1 5 files changed, 60 insertions(+), 29 deletions(-) Index: linux/fs/btrfs/disk-io.c ==================================================================--- linux.orig/fs/btrfs/disk-io.c 2011-01-18 10:53:07.000000000 +0800 +++ linux/fs/btrfs/disk-io.c 2011-01-18 11:16:41.000000000 +0800 @@ -424,12 +424,53 @@ void btrfs_set_buffer_lockdep_class(stru } #endif +int btree_validate_extent_buffer(struct btrfs_root *root, + struct extent_buffer *eb) +{ + u64 found_start; + int found_level; + int ret = 0; + + if (!test_bit(EXTENT_BUFFER_UNCHECKED, &eb->bflags)) + return 0; + + found_start = btrfs_header_bytenr(eb); + if (found_start != eb->start) { + if (printk_ratelimit()) { + printk(KERN_INFO "btrfs bad tree block start " + "%llu %llu\n", + (unsigned long long)found_start, + (unsigned long long)eb->start); + } + ret = -EIO; + goto err; + } + + if (check_tree_block_fsid(root, eb)) { + if (printk_ratelimit()) { + printk(KERN_INFO "btrfs bad fsid on block %llu\n", + (unsigned long long)eb->start); + } + ret = -EIO; + goto err; + } + found_level = btrfs_header_level(eb); + + btrfs_set_buffer_lockdep_class(eb, found_level); + + ret = csum_tree_block(root, eb, 1); + if (ret) + ret = -EIO; +err: + if (ret == 0) + clear_bit(EXTENT_BUFFER_UNCHECKED, &eb->bflags); + return ret; +} + static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, struct extent_state *state) { struct extent_io_tree *tree; - u64 found_start; - int found_level; unsigned long len; struct extent_buffer *eb; struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; @@ -450,17 +491,6 @@ static int btree_readpage_end_io_hook(st goto out; } - found_start = btrfs_header_bytenr(eb); - if (found_start != start) { - if (printk_ratelimit()) { - printk(KERN_INFO "btrfs bad tree block start " - "%llu %llu\n", - (unsigned long long)found_start, - (unsigned long long)eb->start); - } - ret = -EIO; - goto err; - } if (eb->first_page != page) { printk(KERN_INFO "btrfs bad first page %lu %lu\n", eb->first_page->index, page->index); @@ -468,21 +498,8 @@ static int btree_readpage_end_io_hook(st ret = -EIO; goto err; } - if (check_tree_block_fsid(root, eb)) { - if (printk_ratelimit()) { - printk(KERN_INFO "btrfs bad fsid on block %llu\n", - (unsigned long long)eb->start); - } - ret = -EIO; - goto err; - } - found_level = btrfs_header_level(eb); - - btrfs_set_buffer_lockdep_class(eb, found_level); - ret = csum_tree_block(root, eb, 1); - if (ret) - ret = -EIO; + ret = btree_validate_extent_buffer(root, eb); end = min_t(u64, eb->len, PAGE_CACHE_SIZE); end = eb->start + end - 1; Index: linux/fs/btrfs/disk-io.h ==================================================================--- linux.orig/fs/btrfs/disk-io.h 2011-01-18 10:53:07.000000000 +0800 +++ linux/fs/btrfs/disk-io.h 2011-01-18 10:57:54.000000000 +0800 @@ -36,6 +36,8 @@ static inline u64 btrfs_sb_offset(int mi struct btrfs_device; struct btrfs_fs_devices; +int btree_validate_extent_buffer(struct btrfs_root *root, + struct extent_buffer *eb); struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, u64 parent_transid); int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, Index: linux/fs/btrfs/extent_io.c ==================================================================--- linux.orig/fs/btrfs/extent_io.c 2011-01-18 10:53:07.000000000 +0800 +++ linux/fs/btrfs/extent_io.c 2011-01-18 10:57:54.000000000 +0800 @@ -14,6 +14,7 @@ #include "extent_map.h" #include "compat.h" #include "ctree.h" +#include "disk-io.h" #include "btrfs_inode.h" static struct kmem_cache *extent_state_cache; @@ -3194,6 +3195,7 @@ struct extent_buffer *alloc_extent_buffe uptodate = 0; unlock_page(p); } + set_bit(EXTENT_BUFFER_UNCHECKED, &eb->bflags); if (uptodate) set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); @@ -3424,9 +3426,10 @@ int read_extent_buffer_pages(struct exte unsigned long num_pages; struct bio *bio = NULL; unsigned long bio_flags = 0; + struct btrfs_root *root = BTRFS_I(tree->mapping->host)->root; if (test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags)) - return 0; + goto out; if (test_range_bit(tree, eb->start, eb->start + eb->len - 1, EXTENT_UPTODATE, 1, NULL)) { @@ -3491,8 +3494,10 @@ int read_extent_buffer_pages(struct exte ret = -EIO; } - if (!ret) + if (!ret) { set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); + goto out; + } return ret; unlock_exit: @@ -3503,6 +3508,11 @@ unlock_exit: unlock_page(page); locked_pages--; } +out: + if (!ret && test_bit(EXTENT_BUFFER_UNCHECKED, &eb->bflags) && + test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags)) + return btree_validate_extent_buffer(root, eb); + return ret; } Index: linux/fs/btrfs/extent_io.h ==================================================================--- linux.orig/fs/btrfs/extent_io.h 2011-01-18 10:53:07.000000000 +0800 +++ linux/fs/btrfs/extent_io.h 2011-01-18 10:57:54.000000000 +0800 @@ -31,6 +31,7 @@ #define EXTENT_BUFFER_UPTODATE 0 #define EXTENT_BUFFER_BLOCKING 1 #define EXTENT_BUFFER_DIRTY 2 +#define EXTENT_BUFFER_UNCHECKED 3 /* these are flags for extent_clear_unlock_delalloc */ #define EXTENT_CLEAR_UNLOCK_PAGE 0x1 Index: linux/fs/btrfs/extent-tree.c ==================================================================--- linux.orig/fs/btrfs/extent-tree.c 2011-01-18 10:53:07.000000000 +0800 +++ linux/fs/btrfs/extent-tree.c 2011-01-18 10:57:54.000000000 +0800 @@ -5606,6 +5606,7 @@ struct extent_buffer *btrfs_init_new_buf clean_tree_block(trans, root, buf); btrfs_set_lock_blocking(buf); + clear_bit(EXTENT_BUFFER_UNCHECKED, &buf->bflags); btrfs_set_buffer_uptodate(buf); if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) { -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html