From 351d17fca2cf8063f323a060cd3c4af62ef58d15 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Tue, 13 May 2008 13:48:58 -0400 Subject: Verify parent generation number on btree reads --- btrfs-vol.c | 5 ++++- convert.c | 2 +- ctree.c | 2 +- disk-io.c | 47 +++++++++++++++++++++++++++++++++++++++-------- disk-io.h | 2 +- extent-tree.c | 4 ++-- extent_io.c | 8 ++++++++ extent_io.h | 2 ++ 8 files changed, 58 insertions(+), 14 deletions(-) diff --git a/btrfs-vol.c b/btrfs-vol.c index 9eddd782..80697783 100644 --- a/btrfs-vol.c +++ b/btrfs-vol.c @@ -105,7 +105,10 @@ int main(int ac, char **av) print_usage(); mnt = av[optind]; - if (device) { + if (device && strcmp(device, "missing") == 0 && + cmd == BTRFS_IOC_RM_DEV) { + fprintf(stderr, "removing missing devices from %s\n", mnt); + } else if (device) { devfd = open(device, O_RDWR); if (!devfd) { fprintf(stderr, "Unable to open device %s\n", device); diff --git a/convert.c b/convert.c index 219f849b..3c00544c 100644 --- a/convert.c +++ b/convert.c @@ -1094,7 +1094,7 @@ static int create_image_file_range(struct btrfs_trans_handle *trans, u32 blocksize = ext2_fs->blocksize; u32 block = start_byte / blocksize; u32 last_block = (end_byte + blocksize - 1) / blocksize; - int ret; + int ret = 0; struct blk_iterate_data data = { .trans = trans, .root = root, diff --git a/ctree.c b/ctree.c index 87574d9e..881c115b 100644 --- a/ctree.c +++ b/ctree.c @@ -378,7 +378,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, cur = btrfs_find_tree_block(root, blocknr, blocksize); if (cur) - uptodate = btrfs_buffer_uptodate(cur); + uptodate = btrfs_buffer_uptodate(cur, gen); else uptodate = 0; if (!cur || !uptodate) { diff --git a/disk-io.c b/disk-io.c index 687cc61e..f2cbd4af 100644 --- a/disk-io.c +++ b/disk-io.c @@ -106,7 +106,7 @@ int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, struct btrfs_device *device; eb = btrfs_find_tree_block(root, bytenr, blocksize); - if (eb && btrfs_buffer_uptodate(eb)) { + if (eb && btrfs_buffer_uptodate(eb, parent_transid)) { free_extent_buffer(eb); return 0; } @@ -124,6 +124,31 @@ int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, return 0; } +static int verify_parent_transid(struct extent_io_tree *io_tree, + struct extent_buffer *eb, u64 parent_transid) +{ + int ret; + + if (!parent_transid || btrfs_header_generation(eb) == parent_transid) + return 0; + + if (extent_buffer_uptodate(eb) && + btrfs_header_generation(eb) == parent_transid) { + ret = 0; + goto out; + } + printk("parent transid verify failed on %llu wanted %llu found %llu\n", + (unsigned long long)eb->start, + (unsigned long long)parent_transid, + (unsigned long long)btrfs_header_generation(eb)); + ret = 1; +out: + clear_extent_buffer_uptodate(io_tree, eb); + return ret; + +} + + struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, u64 parent_transid) { @@ -140,7 +165,7 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, if (!eb) return NULL; - if (btrfs_buffer_uptodate(eb)) + if (btrfs_buffer_uptodate(eb, parent_transid)) return eb; dev_nr = 0; @@ -156,19 +181,18 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, kfree(multi); ret = read_extent_from_disk(eb); if (ret == 0 && check_tree_block(root, eb) == 0 && - csum_tree_block(root, eb, 1) == 0) { + csum_tree_block(root, eb, 1) == 0 && + verify_parent_transid(eb->tree, eb, parent_transid) == 0) { btrfs_set_buffer_uptodate(eb); return eb; } num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, eb->start, eb->len); if (num_copies == 1) { -printk("reading %Lu failed only one copy\n", eb->start); break; } mirror_num++; if (mirror_num > num_copies) { -printk("bailing at mirror %d of %d\n", mirror_num, num_copies); break; } } @@ -186,7 +210,7 @@ int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, if (check_tree_block(root, eb)) BUG(); - if (!btrfs_buffer_uptodate(eb)) + if (!btrfs_buffer_uptodate(eb, trans->transid)) BUG(); btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN); @@ -773,9 +797,16 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *eb) set_extent_buffer_dirty(eb); } -int btrfs_buffer_uptodate(struct extent_buffer *eb) +int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid) { - return extent_buffer_uptodate(eb); + int ret; + + ret = extent_buffer_uptodate(buf); + if (!ret) + return ret; + + ret = verify_parent_transid(buf->tree, buf, parent_transid); + return !ret; } int btrfs_set_buffer_uptodate(struct extent_buffer *eb) diff --git a/disk-io.h b/disk-io.h index ffb4114b..098f9e33 100644 --- a/disk-io.h +++ b/disk-io.h @@ -46,7 +46,7 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_key *location); int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root); void btrfs_mark_buffer_dirty(struct extent_buffer *buf); -int btrfs_buffer_uptodate(struct extent_buffer *buf); +int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid); int btrfs_set_buffer_uptodate(struct extent_buffer *buf); int wait_on_tree_block_writeback(struct btrfs_root *root, struct extent_buffer *buf); diff --git a/extent-tree.c b/extent-tree.c index 545884a9..767867f9 100644 --- a/extent-tree.c +++ b/extent-tree.c @@ -1253,7 +1253,7 @@ static int pin_down_bytes(struct btrfs_root *root, u64 bytenr, u32 num_bytes, if (!pending) { buf = btrfs_find_tree_block(root, bytenr, num_bytes); if (buf) { - if (btrfs_buffer_uptodate(buf)) { + if (btrfs_buffer_uptodate(buf, 0)) { u64 transid = root->fs_info->running_transaction->transid; if (btrfs_header_generation(buf) == @@ -1967,7 +1967,7 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans, continue; } next = btrfs_find_tree_block(root, bytenr, blocksize); - if (!next || !btrfs_buffer_uptodate(next)) { + if (!next || !btrfs_buffer_uptodate(next, ptr_gen)) { free_extent_buffer(next); reada_walk_down(root, cur, path->slots[*level]); mutex_unlock(&root->fs_info->fs_mutex); diff --git a/extent_io.c b/extent_io.c index ef888d91..4920b291 100644 --- a/extent_io.c +++ b/extent_io.c @@ -1,3 +1,4 @@ + /* * Copyright (C) 2007 Oracle. All rights reserved. * @@ -688,6 +689,13 @@ int set_extent_buffer_uptodate(struct extent_buffer *eb) return 0; } +int clear_extent_buffer_uptodate(struct extent_io_tree *tree, + struct extent_buffer *eb) +{ + eb->flags &= ~EXTENT_UPTODATE; + return 0; +} + int extent_buffer_uptodate(struct extent_buffer *eb) { if (eb->flags & EXTENT_UPTODATE) diff --git a/extent_io.h b/extent_io.h index 2bd4179e..a5d6bf0e 100644 --- a/extent_io.h +++ b/extent_io.h @@ -84,6 +84,8 @@ int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask); int extent_buffer_uptodate(struct extent_buffer *eb); int set_extent_buffer_uptodate(struct extent_buffer *eb); +int clear_extent_buffer_uptodate(struct extent_io_tree *tree, + struct extent_buffer *eb); int set_state_private(struct extent_io_tree *tree, u64 start, u64 private); int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private); struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree, -- cgit v1.2.3