diff options
| -rw-r--r-- | fs/btrfs/ctree.c | 10 | ||||
| -rw-r--r-- | fs/btrfs/ctree.h | 28 | ||||
| -rw-r--r-- | fs/btrfs/disk-io.c | 13 |
3 files changed, 42 insertions, 9 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 70b6ddfe15a1..6ba5394834be 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
| @@ -124,6 +124,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans, | |||
| 124 | btrfs_set_header_bytenr(cow, cow->start); | 124 | btrfs_set_header_bytenr(cow, cow->start); |
| 125 | btrfs_set_header_generation(cow, trans->transid); | 125 | btrfs_set_header_generation(cow, trans->transid); |
| 126 | btrfs_set_header_owner(cow, new_root_objectid); | 126 | btrfs_set_header_owner(cow, new_root_objectid); |
| 127 | btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN); | ||
| 127 | 128 | ||
| 128 | WARN_ON(btrfs_header_generation(buf) > trans->transid); | 129 | WARN_ON(btrfs_header_generation(buf) > trans->transid); |
| 129 | ret = btrfs_inc_ref(trans, new_root, buf); | 130 | ret = btrfs_inc_ref(trans, new_root, buf); |
| @@ -183,6 +184,7 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
| 183 | btrfs_set_header_bytenr(cow, cow->start); | 184 | btrfs_set_header_bytenr(cow, cow->start); |
| 184 | btrfs_set_header_generation(cow, trans->transid); | 185 | btrfs_set_header_generation(cow, trans->transid); |
| 185 | btrfs_set_header_owner(cow, root->root_key.objectid); | 186 | btrfs_set_header_owner(cow, root->root_key.objectid); |
| 187 | btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN); | ||
| 186 | 188 | ||
| 187 | WARN_ON(btrfs_header_generation(buf) > trans->transid); | 189 | WARN_ON(btrfs_header_generation(buf) > trans->transid); |
| 188 | if (btrfs_header_generation(buf) != trans->transid) { | 190 | if (btrfs_header_generation(buf) != trans->transid) { |
| @@ -245,11 +247,14 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
| 245 | } | 247 | } |
| 246 | 248 | ||
| 247 | header_trans = btrfs_header_generation(buf); | 249 | header_trans = btrfs_header_generation(buf); |
| 248 | if (header_trans == trans->transid) { | 250 | spin_lock(&root->fs_info->hash_lock); |
| 251 | if (header_trans == trans->transid && | ||
| 252 | !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) { | ||
| 249 | *cow_ret = buf; | 253 | *cow_ret = buf; |
| 254 | spin_unlock(&root->fs_info->hash_lock); | ||
| 250 | return 0; | 255 | return 0; |
| 251 | } | 256 | } |
| 252 | 257 | spin_unlock(&root->fs_info->hash_lock); | |
| 253 | search_start = buf->start & ~((u64)(1024 * 1024 * 1024) - 1); | 258 | search_start = buf->start & ~((u64)(1024 * 1024 * 1024) - 1); |
| 254 | ret = __btrfs_cow_block(trans, root, buf, parent, | 259 | ret = __btrfs_cow_block(trans, root, buf, parent, |
| 255 | parent_slot, cow_ret, search_start, 0); | 260 | parent_slot, cow_ret, search_start, 0); |
| @@ -1494,6 +1499,7 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root | |||
| 1494 | btrfs_set_header_bytenr(split, split->start); | 1499 | btrfs_set_header_bytenr(split, split->start); |
| 1495 | btrfs_set_header_generation(split, trans->transid); | 1500 | btrfs_set_header_generation(split, trans->transid); |
| 1496 | btrfs_set_header_owner(split, root->root_key.objectid); | 1501 | btrfs_set_header_owner(split, root->root_key.objectid); |
| 1502 | btrfs_set_header_flags(split, 0); | ||
| 1497 | write_extent_buffer(split, root->fs_info->fsid, | 1503 | write_extent_buffer(split, root->fs_info->fsid, |
| 1498 | (unsigned long)btrfs_header_fsid(split), | 1504 | (unsigned long)btrfs_header_fsid(split), |
| 1499 | BTRFS_FSID_SIZE); | 1505 | BTRFS_FSID_SIZE); |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index fec96ba7c23b..67d533cf8f47 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
| @@ -193,6 +193,8 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes) | |||
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | #define BTRFS_FSID_SIZE 16 | 195 | #define BTRFS_FSID_SIZE 16 |
| 196 | #define BTRFS_HEADER_FLAG_WRITTEN (1 << 0) | ||
| 197 | |||
| 196 | /* | 198 | /* |
| 197 | * every tree block (leaf or node) starts with this header. | 199 | * every tree block (leaf or node) starts with this header. |
| 198 | */ | 200 | */ |
| @@ -200,10 +202,10 @@ struct btrfs_header { | |||
| 200 | u8 csum[BTRFS_CSUM_SIZE]; | 202 | u8 csum[BTRFS_CSUM_SIZE]; |
| 201 | u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */ | 203 | u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */ |
| 202 | __le64 bytenr; /* which block this node is supposed to live in */ | 204 | __le64 bytenr; /* which block this node is supposed to live in */ |
| 205 | __le64 flags; | ||
| 203 | __le64 generation; | 206 | __le64 generation; |
| 204 | __le64 owner; | 207 | __le64 owner; |
| 205 | __le32 nritems; | 208 | __le32 nritems; |
| 206 | __le16 flags; | ||
| 207 | u8 level; | 209 | u8 level; |
| 208 | } __attribute__ ((__packed__)); | 210 | } __attribute__ ((__packed__)); |
| 209 | 211 | ||
| @@ -229,9 +231,10 @@ struct btrfs_header { | |||
| 229 | */ | 231 | */ |
| 230 | struct btrfs_super_block { | 232 | struct btrfs_super_block { |
| 231 | u8 csum[BTRFS_CSUM_SIZE]; | 233 | u8 csum[BTRFS_CSUM_SIZE]; |
| 232 | /* the first 3 fields must match struct btrfs_header */ | 234 | /* the first 4 fields must match struct btrfs_header */ |
| 233 | u8 fsid[16]; /* FS specific uuid */ | 235 | u8 fsid[16]; /* FS specific uuid */ |
| 234 | __le64 bytenr; /* this block number */ | 236 | __le64 bytenr; /* this block number */ |
| 237 | __le64 flags; | ||
| 235 | __le64 magic; | 238 | __le64 magic; |
| 236 | __le64 generation; | 239 | __le64 generation; |
| 237 | __le64 root; | 240 | __le64 root; |
| @@ -1045,9 +1048,28 @@ BTRFS_SETGET_HEADER_FUNCS(header_generation, struct btrfs_header, | |||
| 1045 | generation, 64); | 1048 | generation, 64); |
| 1046 | BTRFS_SETGET_HEADER_FUNCS(header_owner, struct btrfs_header, owner, 64); | 1049 | BTRFS_SETGET_HEADER_FUNCS(header_owner, struct btrfs_header, owner, 64); |
| 1047 | BTRFS_SETGET_HEADER_FUNCS(header_nritems, struct btrfs_header, nritems, 32); | 1050 | BTRFS_SETGET_HEADER_FUNCS(header_nritems, struct btrfs_header, nritems, 32); |
| 1048 | BTRFS_SETGET_HEADER_FUNCS(header_flags, struct btrfs_header, flags, 16); | 1051 | BTRFS_SETGET_HEADER_FUNCS(header_flags, struct btrfs_header, flags, 64); |
| 1049 | BTRFS_SETGET_HEADER_FUNCS(header_level, struct btrfs_header, level, 8); | 1052 | BTRFS_SETGET_HEADER_FUNCS(header_level, struct btrfs_header, level, 8); |
| 1050 | 1053 | ||
| 1054 | static inline int btrfs_header_flag(struct extent_buffer *eb, u64 flag) | ||
| 1055 | { | ||
| 1056 | return (btrfs_header_flags(eb) & flag) == flag; | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | static inline int btrfs_set_header_flag(struct extent_buffer *eb, u64 flag) | ||
| 1060 | { | ||
| 1061 | u64 flags = btrfs_header_flags(eb); | ||
| 1062 | btrfs_set_header_flags(eb, flags | flag); | ||
| 1063 | return (flags & flag) == flag; | ||
| 1064 | } | ||
| 1065 | |||
| 1066 | static inline int btrfs_clear_header_flag(struct extent_buffer *eb, u64 flag) | ||
| 1067 | { | ||
| 1068 | u64 flags = btrfs_header_flags(eb); | ||
| 1069 | btrfs_set_header_flags(eb, flags & ~flag); | ||
| 1070 | return (flags & flag) == flag; | ||
| 1071 | } | ||
| 1072 | |||
| 1051 | static inline u8 *btrfs_header_fsid(struct extent_buffer *eb) | 1073 | static inline u8 *btrfs_header_fsid(struct extent_buffer *eb) |
| 1052 | { | 1074 | { |
| 1053 | unsigned long ptr = offsetof(struct btrfs_header, fsid); | 1075 | unsigned long ptr = offsetof(struct btrfs_header, fsid); |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 1c5e097a4df2..709e33d08bb5 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
| @@ -159,17 +159,19 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, | |||
| 159 | from_this_trans = 1; | 159 | from_this_trans = 1; |
| 160 | 160 | ||
| 161 | /* FIXME, this is not good */ | 161 | /* FIXME, this is not good */ |
| 162 | if (from_this_trans == 0 && | 162 | if (memcmp_extent_buffer(buf, result, 0, BTRFS_CRC32_SIZE)) { |
| 163 | memcmp_extent_buffer(buf, result, 0, BTRFS_CRC32_SIZE)) { | ||
| 164 | u32 val; | 163 | u32 val; |
| 165 | u32 found = 0; | 164 | u32 found = 0; |
| 166 | memcpy(&found, result, BTRFS_CRC32_SIZE); | 165 | memcpy(&found, result, BTRFS_CRC32_SIZE); |
| 167 | 166 | ||
| 168 | read_extent_buffer(buf, &val, 0, BTRFS_CRC32_SIZE); | 167 | read_extent_buffer(buf, &val, 0, BTRFS_CRC32_SIZE); |
| 168 | WARN_ON(1); | ||
| 169 | printk("btrfs: %s checksum verify failed on %llu " | 169 | printk("btrfs: %s checksum verify failed on %llu " |
| 170 | "wanted %X found %X from_this_trans %d\n", | 170 | "wanted %X found %X from_this_trans %d " |
| 171 | "level %d\n", | ||
| 171 | root->fs_info->sb->s_id, | 172 | root->fs_info->sb->s_id, |
| 172 | buf->start, val, found, from_this_trans); | 173 | buf->start, val, found, from_this_trans, |
| 174 | btrfs_header_level(buf)); | ||
| 173 | return 1; | 175 | return 1; |
| 174 | } | 176 | } |
| 175 | } else { | 177 | } else { |
| @@ -220,6 +222,9 @@ int csum_dirty_buffer(struct btrfs_root *root, struct page *page) | |||
| 220 | goto err; | 222 | goto err; |
| 221 | } | 223 | } |
| 222 | found_level = btrfs_header_level(eb); | 224 | found_level = btrfs_header_level(eb); |
| 225 | spin_lock(&root->fs_info->hash_lock); | ||
| 226 | btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN); | ||
| 227 | spin_unlock(&root->fs_info->hash_lock); | ||
| 223 | csum_tree_block(root, eb, 0); | 228 | csum_tree_block(root, eb, 0); |
| 224 | err: | 229 | err: |
| 225 | free_extent_buffer(eb); | 230 | free_extent_buffer(eb); |
