summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-05-13 13:48:58 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2008-05-13 13:48:58 -0400
commit351d17fca2cf8063f323a060cd3c4af62ef58d15 (patch)
treed91b63f25ae45260b9b89f7c70b6af7c34bede79
parent9a9bdd6047a378dbe5a65a79cb8537f797d4fd5c (diff)
Verify parent generation number on btree reads
-rw-r--r--btrfs-vol.c5
-rw-r--r--convert.c2
-rw-r--r--ctree.c2
-rw-r--r--disk-io.c47
-rw-r--r--disk-io.h2
-rw-r--r--extent-tree.c4
-rw-r--r--extent_io.c8
-rw-r--r--extent_io.h2
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,