Commit 63b10fc4 authored by Chris Mason's avatar Chris Mason

Reorder the flags field in struct btrfs_header and record a flag on writeout

This allows detection of blocks that have already been written in the
running transaction so they can be recowed instead of modified again.
It is step one in trusting the transid field of the block pointers.
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 2d2ae547
...@@ -124,6 +124,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans, ...@@ -124,6 +124,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
btrfs_set_header_bytenr(cow, cow->start); btrfs_set_header_bytenr(cow, cow->start);
btrfs_set_header_generation(cow, trans->transid); btrfs_set_header_generation(cow, trans->transid);
btrfs_set_header_owner(cow, new_root_objectid); btrfs_set_header_owner(cow, new_root_objectid);
btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN);
WARN_ON(btrfs_header_generation(buf) > trans->transid); WARN_ON(btrfs_header_generation(buf) > trans->transid);
ret = btrfs_inc_ref(trans, new_root, buf); ret = btrfs_inc_ref(trans, new_root, buf);
...@@ -183,6 +184,7 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans, ...@@ -183,6 +184,7 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
btrfs_set_header_bytenr(cow, cow->start); btrfs_set_header_bytenr(cow, cow->start);
btrfs_set_header_generation(cow, trans->transid); btrfs_set_header_generation(cow, trans->transid);
btrfs_set_header_owner(cow, root->root_key.objectid); btrfs_set_header_owner(cow, root->root_key.objectid);
btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN);
WARN_ON(btrfs_header_generation(buf) > trans->transid); WARN_ON(btrfs_header_generation(buf) > trans->transid);
if (btrfs_header_generation(buf) != trans->transid) { if (btrfs_header_generation(buf) != trans->transid) {
...@@ -245,11 +247,14 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans, ...@@ -245,11 +247,14 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
} }
header_trans = btrfs_header_generation(buf); header_trans = btrfs_header_generation(buf);
if (header_trans == trans->transid) { spin_lock(&root->fs_info->hash_lock);
if (header_trans == trans->transid &&
!btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) {
*cow_ret = buf; *cow_ret = buf;
spin_unlock(&root->fs_info->hash_lock);
return 0; return 0;
} }
spin_unlock(&root->fs_info->hash_lock);
search_start = buf->start & ~((u64)(1024 * 1024 * 1024) - 1); search_start = buf->start & ~((u64)(1024 * 1024 * 1024) - 1);
ret = __btrfs_cow_block(trans, root, buf, parent, ret = __btrfs_cow_block(trans, root, buf, parent,
parent_slot, cow_ret, search_start, 0); parent_slot, cow_ret, search_start, 0);
...@@ -1494,6 +1499,7 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -1494,6 +1499,7 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_set_header_bytenr(split, split->start); btrfs_set_header_bytenr(split, split->start);
btrfs_set_header_generation(split, trans->transid); btrfs_set_header_generation(split, trans->transid);
btrfs_set_header_owner(split, root->root_key.objectid); btrfs_set_header_owner(split, root->root_key.objectid);
btrfs_set_header_flags(split, 0);
write_extent_buffer(split, root->fs_info->fsid, write_extent_buffer(split, root->fs_info->fsid,
(unsigned long)btrfs_header_fsid(split), (unsigned long)btrfs_header_fsid(split),
BTRFS_FSID_SIZE); BTRFS_FSID_SIZE);
......
...@@ -193,6 +193,8 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes) ...@@ -193,6 +193,8 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes)
} }
#define BTRFS_FSID_SIZE 16 #define BTRFS_FSID_SIZE 16
#define BTRFS_HEADER_FLAG_WRITTEN (1 << 0)
/* /*
* every tree block (leaf or node) starts with this header. * every tree block (leaf or node) starts with this header.
*/ */
...@@ -200,10 +202,10 @@ struct btrfs_header { ...@@ -200,10 +202,10 @@ struct btrfs_header {
u8 csum[BTRFS_CSUM_SIZE]; u8 csum[BTRFS_CSUM_SIZE];
u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */ u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
__le64 bytenr; /* which block this node is supposed to live in */ __le64 bytenr; /* which block this node is supposed to live in */
__le64 flags;
__le64 generation; __le64 generation;
__le64 owner; __le64 owner;
__le32 nritems; __le32 nritems;
__le16 flags;
u8 level; u8 level;
} __attribute__ ((__packed__)); } __attribute__ ((__packed__));
...@@ -229,9 +231,10 @@ struct btrfs_header { ...@@ -229,9 +231,10 @@ struct btrfs_header {
*/ */
struct btrfs_super_block { struct btrfs_super_block {
u8 csum[BTRFS_CSUM_SIZE]; u8 csum[BTRFS_CSUM_SIZE];
/* the first 3 fields must match struct btrfs_header */ /* the first 4 fields must match struct btrfs_header */
u8 fsid[16]; /* FS specific uuid */ u8 fsid[16]; /* FS specific uuid */
__le64 bytenr; /* this block number */ __le64 bytenr; /* this block number */
__le64 flags;
__le64 magic; __le64 magic;
__le64 generation; __le64 generation;
__le64 root; __le64 root;
...@@ -1045,9 +1048,28 @@ BTRFS_SETGET_HEADER_FUNCS(header_generation, struct btrfs_header, ...@@ -1045,9 +1048,28 @@ BTRFS_SETGET_HEADER_FUNCS(header_generation, struct btrfs_header,
generation, 64); generation, 64);
BTRFS_SETGET_HEADER_FUNCS(header_owner, struct btrfs_header, owner, 64); BTRFS_SETGET_HEADER_FUNCS(header_owner, struct btrfs_header, owner, 64);
BTRFS_SETGET_HEADER_FUNCS(header_nritems, struct btrfs_header, nritems, 32); BTRFS_SETGET_HEADER_FUNCS(header_nritems, struct btrfs_header, nritems, 32);
BTRFS_SETGET_HEADER_FUNCS(header_flags, struct btrfs_header, flags, 16); BTRFS_SETGET_HEADER_FUNCS(header_flags, struct btrfs_header, flags, 64);
BTRFS_SETGET_HEADER_FUNCS(header_level, struct btrfs_header, level, 8); BTRFS_SETGET_HEADER_FUNCS(header_level, struct btrfs_header, level, 8);
static inline int btrfs_header_flag(struct extent_buffer *eb, u64 flag)
{
return (btrfs_header_flags(eb) & flag) == flag;
}
static inline int btrfs_set_header_flag(struct extent_buffer *eb, u64 flag)
{
u64 flags = btrfs_header_flags(eb);
btrfs_set_header_flags(eb, flags | flag);
return (flags & flag) == flag;
}
static inline int btrfs_clear_header_flag(struct extent_buffer *eb, u64 flag)
{
u64 flags = btrfs_header_flags(eb);
btrfs_set_header_flags(eb, flags & ~flag);
return (flags & flag) == flag;
}
static inline u8 *btrfs_header_fsid(struct extent_buffer *eb) static inline u8 *btrfs_header_fsid(struct extent_buffer *eb)
{ {
unsigned long ptr = offsetof(struct btrfs_header, fsid); unsigned long ptr = offsetof(struct btrfs_header, fsid);
......
...@@ -159,17 +159,19 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, ...@@ -159,17 +159,19 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
from_this_trans = 1; from_this_trans = 1;
/* FIXME, this is not good */ /* FIXME, this is not good */
if (from_this_trans == 0 && if (memcmp_extent_buffer(buf, result, 0, BTRFS_CRC32_SIZE)) {
memcmp_extent_buffer(buf, result, 0, BTRFS_CRC32_SIZE)) {
u32 val; u32 val;
u32 found = 0; u32 found = 0;
memcpy(&found, result, BTRFS_CRC32_SIZE); memcpy(&found, result, BTRFS_CRC32_SIZE);
read_extent_buffer(buf, &val, 0, BTRFS_CRC32_SIZE); read_extent_buffer(buf, &val, 0, BTRFS_CRC32_SIZE);
WARN_ON(1);
printk("btrfs: %s checksum verify failed on %llu " printk("btrfs: %s checksum verify failed on %llu "
"wanted %X found %X from_this_trans %d\n", "wanted %X found %X from_this_trans %d "
"level %d\n",
root->fs_info->sb->s_id, root->fs_info->sb->s_id,
buf->start, val, found, from_this_trans); buf->start, val, found, from_this_trans,
btrfs_header_level(buf));
return 1; return 1;
} }
} else { } else {
...@@ -220,6 +222,9 @@ int csum_dirty_buffer(struct btrfs_root *root, struct page *page) ...@@ -220,6 +222,9 @@ int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
goto err; goto err;
} }
found_level = btrfs_header_level(eb); found_level = btrfs_header_level(eb);
spin_lock(&root->fs_info->hash_lock);
btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
spin_unlock(&root->fs_info->hash_lock);
csum_tree_block(root, eb, 0); csum_tree_block(root, eb, 0);
err: err:
free_extent_buffer(eb); free_extent_buffer(eb);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment