diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-12-11 09:25:06 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:58 -0400 |
commit | 74493f7a59bfd4d1c7029c74ab2cd0e400612c6b (patch) | |
tree | b5fc75b08d2edcf8218c814ea02ab6c548e73652 /fs/btrfs | |
parent | 17636e03f42a1a42fed3834859de4702bd655fd1 (diff) |
Btrfs: Implement generation numbers in block pointers
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/ctree.c | 16 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 47 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 60 |
3 files changed, 115 insertions, 8 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 3b16051b121b..5697705f7530 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -114,6 +114,9 @@ static int __btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
114 | } else { | 114 | } else { |
115 | btrfs_set_node_blockptr(parent, parent_slot, | 115 | btrfs_set_node_blockptr(parent, parent_slot, |
116 | cow->start); | 116 | cow->start); |
117 | WARN_ON(trans->transid == 0); | ||
118 | btrfs_set_node_ptr_generation(parent, parent_slot, | ||
119 | trans->transid); | ||
117 | btrfs_mark_buffer_dirty(parent); | 120 | btrfs_mark_buffer_dirty(parent); |
118 | WARN_ON(btrfs_header_generation(parent) != trans->transid); | 121 | WARN_ON(btrfs_header_generation(parent) != trans->transid); |
119 | btrfs_free_extent(trans, root, buf->start, buf->len, 1); | 122 | btrfs_free_extent(trans, root, buf->start, buf->len, 1); |
@@ -967,6 +970,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root | |||
967 | { | 970 | { |
968 | struct extent_buffer *b; | 971 | struct extent_buffer *b; |
969 | u64 bytenr; | 972 | u64 bytenr; |
973 | u64 ptr_gen; | ||
970 | int slot; | 974 | int slot; |
971 | int ret; | 975 | int ret; |
972 | int level; | 976 | int level; |
@@ -1031,10 +1035,18 @@ again: | |||
1031 | if (level == lowest_level) | 1035 | if (level == lowest_level) |
1032 | break; | 1036 | break; |
1033 | bytenr = btrfs_node_blockptr(b, slot); | 1037 | bytenr = btrfs_node_blockptr(b, slot); |
1038 | ptr_gen = btrfs_node_ptr_generation(b, slot); | ||
1034 | if (should_reada) | 1039 | if (should_reada) |
1035 | reada_for_search(root, p, level, slot); | 1040 | reada_for_search(root, p, level, slot); |
1036 | b = read_tree_block(root, bytenr, | 1041 | b = read_tree_block(root, bytenr, |
1037 | btrfs_level_size(root, level - 1)); | 1042 | btrfs_level_size(root, level - 1)); |
1043 | if (ptr_gen != btrfs_header_generation(b)) { | ||
1044 | printk("block %llu bad gen wanted %llu " | ||
1045 | "found %llu\n", | ||
1046 | (unsigned long long)b->start, | ||
1047 | (unsigned long long)ptr_gen, | ||
1048 | (unsigned long long)btrfs_header_generation(b)); | ||
1049 | } | ||
1038 | } else { | 1050 | } else { |
1039 | p->slots[level] = slot; | 1051 | p->slots[level] = slot; |
1040 | if (ins_len > 0 && btrfs_leaf_free_space(root, b) < | 1052 | if (ins_len > 0 && btrfs_leaf_free_space(root, b) < |
@@ -1218,6 +1230,8 @@ static int insert_new_root(struct btrfs_trans_handle *trans, | |||
1218 | btrfs_node_key(lower, &lower_key, 0); | 1230 | btrfs_node_key(lower, &lower_key, 0); |
1219 | btrfs_set_node_key(c, &lower_key, 0); | 1231 | btrfs_set_node_key(c, &lower_key, 0); |
1220 | btrfs_set_node_blockptr(c, 0, lower->start); | 1232 | btrfs_set_node_blockptr(c, 0, lower->start); |
1233 | WARN_ON(btrfs_header_generation(lower) == 0); | ||
1234 | btrfs_set_node_ptr_generation(c, 0, btrfs_header_generation(lower)); | ||
1221 | 1235 | ||
1222 | btrfs_mark_buffer_dirty(c); | 1236 | btrfs_mark_buffer_dirty(c); |
1223 | 1237 | ||
@@ -1261,6 +1275,8 @@ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1261 | } | 1275 | } |
1262 | btrfs_set_node_key(lower, key, slot); | 1276 | btrfs_set_node_key(lower, key, slot); |
1263 | btrfs_set_node_blockptr(lower, slot, bytenr); | 1277 | btrfs_set_node_blockptr(lower, slot, bytenr); |
1278 | WARN_ON(trans->transid == 0); | ||
1279 | btrfs_set_node_ptr_generation(lower, slot, trans->transid); | ||
1264 | btrfs_set_header_nritems(lower, nritems + 1); | 1280 | btrfs_set_header_nritems(lower, nritems + 1); |
1265 | btrfs_mark_buffer_dirty(lower); | 1281 | btrfs_mark_buffer_dirty(lower); |
1266 | return 0; | 1282 | return 0; |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 9bc1b0a8615f..fd58dd846e61 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -110,7 +110,7 @@ struct btrfs_header { | |||
110 | #define BTRFS_MAX_LEVEL 8 | 110 | #define BTRFS_MAX_LEVEL 8 |
111 | #define BTRFS_NODEPTRS_PER_BLOCK(r) (((r)->nodesize - \ | 111 | #define BTRFS_NODEPTRS_PER_BLOCK(r) (((r)->nodesize - \ |
112 | sizeof(struct btrfs_header)) / \ | 112 | sizeof(struct btrfs_header)) / \ |
113 | (sizeof(struct btrfs_disk_key) + sizeof(u64))) | 113 | sizeof(struct btrfs_key_ptr)) |
114 | #define __BTRFS_LEAF_DATA_SIZE(bs) ((bs) - sizeof(struct btrfs_header)) | 114 | #define __BTRFS_LEAF_DATA_SIZE(bs) ((bs) - sizeof(struct btrfs_header)) |
115 | #define BTRFS_LEAF_DATA_SIZE(r) (__BTRFS_LEAF_DATA_SIZE(r->leafsize)) | 115 | #define BTRFS_LEAF_DATA_SIZE(r) (__BTRFS_LEAF_DATA_SIZE(r->leafsize)) |
116 | #define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \ | 116 | #define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \ |
@@ -168,6 +168,7 @@ struct btrfs_leaf { | |||
168 | struct btrfs_key_ptr { | 168 | struct btrfs_key_ptr { |
169 | struct btrfs_disk_key key; | 169 | struct btrfs_disk_key key; |
170 | __le64 blockptr; | 170 | __le64 blockptr; |
171 | __le64 generation; | ||
171 | } __attribute__ ((__packed__)); | 172 | } __attribute__ ((__packed__)); |
172 | 173 | ||
173 | struct btrfs_node { | 174 | struct btrfs_node { |
@@ -196,7 +197,13 @@ struct btrfs_path { | |||
196 | */ | 197 | */ |
197 | struct btrfs_extent_item { | 198 | struct btrfs_extent_item { |
198 | __le32 refs; | 199 | __le32 refs; |
199 | __le64 owner; | 200 | } __attribute__ ((__packed__)); |
201 | |||
202 | struct btrfs_extent_ref { | ||
203 | __le64 root; | ||
204 | __le64 generation; | ||
205 | __le64 objectid; | ||
206 | __le64 offset; | ||
200 | } __attribute__ ((__packed__)); | 207 | } __attribute__ ((__packed__)); |
201 | 208 | ||
202 | struct btrfs_inode_timespec { | 209 | struct btrfs_inode_timespec { |
@@ -402,12 +409,13 @@ struct btrfs_root { | |||
402 | * are used, and how many references there are to each block | 409 | * are used, and how many references there are to each block |
403 | */ | 410 | */ |
404 | #define BTRFS_EXTENT_ITEM_KEY 33 | 411 | #define BTRFS_EXTENT_ITEM_KEY 33 |
412 | #define BTRFS_EXTENT_REF_KEY 34 | ||
405 | 413 | ||
406 | /* | 414 | /* |
407 | * block groups give us hints into the extent allocation trees. Which | 415 | * block groups give us hints into the extent allocation trees. Which |
408 | * blocks are free etc etc | 416 | * blocks are free etc etc |
409 | */ | 417 | */ |
410 | #define BTRFS_BLOCK_GROUP_ITEM_KEY 34 | 418 | #define BTRFS_BLOCK_GROUP_ITEM_KEY 50 |
411 | 419 | ||
412 | /* | 420 | /* |
413 | * string items are for debugging. They just store a short string of | 421 | * string items are for debugging. They just store a short string of |
@@ -529,15 +537,25 @@ BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_inode_timespec, nsec, 32); | |||
529 | 537 | ||
530 | /* struct btrfs_extent_item */ | 538 | /* struct btrfs_extent_item */ |
531 | BTRFS_SETGET_FUNCS(extent_refs, struct btrfs_extent_item, refs, 32); | 539 | BTRFS_SETGET_FUNCS(extent_refs, struct btrfs_extent_item, refs, 32); |
532 | BTRFS_SETGET_FUNCS(extent_owner, struct btrfs_extent_item, owner, 64); | 540 | |
541 | /* struct btrfs_extent_ref */ | ||
542 | BTRFS_SETGET_FUNCS(ref_root, struct btrfs_extent_ref, root, 64); | ||
543 | BTRFS_SETGET_FUNCS(ref_generation, struct btrfs_extent_ref, generation, 64); | ||
544 | BTRFS_SETGET_FUNCS(ref_objectid, struct btrfs_extent_ref, objectid, 64); | ||
545 | BTRFS_SETGET_FUNCS(ref_offset, struct btrfs_extent_ref, offset, 64); | ||
546 | |||
547 | BTRFS_SETGET_STACK_FUNCS(ref_root, struct btrfs_extent_ref, root, 64); | ||
548 | BTRFS_SETGET_STACK_FUNCS(ref_generation, struct btrfs_extent_ref, | ||
549 | generation, 64); | ||
550 | BTRFS_SETGET_STACK_FUNCS(ref_objectid, struct btrfs_extent_ref, objectid, 64); | ||
551 | BTRFS_SETGET_STACK_FUNCS(ref_offset, struct btrfs_extent_ref, offset, 64); | ||
533 | 552 | ||
534 | BTRFS_SETGET_STACK_FUNCS(stack_extent_refs, struct btrfs_extent_item, | 553 | BTRFS_SETGET_STACK_FUNCS(stack_extent_refs, struct btrfs_extent_item, |
535 | refs, 32); | 554 | refs, 32); |
536 | BTRFS_SETGET_STACK_FUNCS(stack_extent_owner, struct btrfs_extent_item, | ||
537 | owner, 64); | ||
538 | 555 | ||
539 | /* struct btrfs_node */ | 556 | /* struct btrfs_node */ |
540 | BTRFS_SETGET_FUNCS(key_blockptr, struct btrfs_key_ptr, blockptr, 64); | 557 | BTRFS_SETGET_FUNCS(key_blockptr, struct btrfs_key_ptr, blockptr, 64); |
558 | BTRFS_SETGET_FUNCS(key_generation, struct btrfs_key_ptr, generation, 64); | ||
541 | 559 | ||
542 | static inline u64 btrfs_node_blockptr(struct extent_buffer *eb, int nr) | 560 | static inline u64 btrfs_node_blockptr(struct extent_buffer *eb, int nr) |
543 | { | 561 | { |
@@ -556,6 +574,23 @@ static inline void btrfs_set_node_blockptr(struct extent_buffer *eb, | |||
556 | btrfs_set_key_blockptr(eb, (struct btrfs_key_ptr *)ptr, val); | 574 | btrfs_set_key_blockptr(eb, (struct btrfs_key_ptr *)ptr, val); |
557 | } | 575 | } |
558 | 576 | ||
577 | static inline u64 btrfs_node_ptr_generation(struct extent_buffer *eb, int nr) | ||
578 | { | ||
579 | unsigned long ptr; | ||
580 | ptr = offsetof(struct btrfs_node, ptrs) + | ||
581 | sizeof(struct btrfs_key_ptr) * nr; | ||
582 | return btrfs_key_generation(eb, (struct btrfs_key_ptr *)ptr); | ||
583 | } | ||
584 | |||
585 | static inline void btrfs_set_node_ptr_generation(struct extent_buffer *eb, | ||
586 | int nr, u64 val) | ||
587 | { | ||
588 | unsigned long ptr; | ||
589 | ptr = offsetof(struct btrfs_node, ptrs) + | ||
590 | sizeof(struct btrfs_key_ptr) * nr; | ||
591 | btrfs_set_key_generation(eb, (struct btrfs_key_ptr *)ptr, val); | ||
592 | } | ||
593 | |||
559 | static inline unsigned long btrfs_node_key_ptr_offset(int nr) | 594 | static inline unsigned long btrfs_node_key_ptr_offset(int nr) |
560 | { | 595 | { |
561 | return offsetof(struct btrfs_node, ptrs) + | 596 | return offsetof(struct btrfs_node, ptrs) + |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 8ab4954f6ad0..0f1ebdd4e925 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -17,6 +17,7 @@ | |||
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
20 | #include "hash.h" | ||
20 | #include "ctree.h" | 21 | #include "ctree.h" |
21 | #include "disk-io.h" | 22 | #include "disk-io.h" |
22 | #include "print-tree.h" | 23 | #include "print-tree.h" |
@@ -352,9 +353,63 @@ found: | |||
352 | return found_group; | 353 | return found_group; |
353 | } | 354 | } |
354 | 355 | ||
356 | static u64 hash_extent_ref(u64 root_objectid, u64 root_generation, | ||
357 | u64 owner, u64 owner_offset) | ||
358 | { | ||
359 | u32 high_crc = ~(u32)0; | ||
360 | u32 low_crc = ~(u32)0; | ||
361 | __le64 lenum; | ||
362 | |||
363 | lenum = cpu_to_le64(root_objectid); | ||
364 | high_crc = crc32c(high_crc, &lenum, sizeof(lenum)); | ||
365 | lenum = cpu_to_le64(root_generation); | ||
366 | high_crc = crc32c(high_crc, &lenum, sizeof(lenum)); | ||
367 | |||
368 | lenum = cpu_to_le64(owner); | ||
369 | low_crc = crc32c(low_crc, &lenum, sizeof(lenum)); | ||
370 | |||
371 | lenum = cpu_to_le64(owner_offset); | ||
372 | low_crc = crc32c(low_crc, &lenum, sizeof(lenum)); | ||
373 | |||
374 | return ((u64)high_crc << 32) | (u64)low_crc; | ||
375 | } | ||
376 | |||
377 | int insert_extent_ref(struct btrfs_trans_handle *trans, | ||
378 | struct btrfs_root *root, | ||
379 | struct btrfs_path *path, | ||
380 | u64 bytenr, | ||
381 | u64 root_objectid, u64 root_generation, | ||
382 | u64 owner, u64 owner_offset) | ||
383 | { | ||
384 | u64 hash; | ||
385 | struct btrfs_key key; | ||
386 | struct btrfs_extent_ref ref; | ||
387 | struct extent_buffer *l; | ||
388 | struct btrfs_extent_item *item; | ||
389 | int ret; | ||
390 | |||
391 | btrfs_set_stack_ref_root(&ref, root_objectid); | ||
392 | btrfs_set_stack_ref_generation(&ref, root_generation); | ||
393 | btrfs_set_stack_ref_objectid(&ref, owner); | ||
394 | btrfs_set_stack_ref_offset(&ref, owner_offset); | ||
395 | |||
396 | ret = btrfs_name_hash(&ref, sizeof(ref), &hash); | ||
397 | key.offset = hash; | ||
398 | key.objectid = bytenr; | ||
399 | key.type = BTRFS_EXTENT_REF_KEY; | ||
400 | |||
401 | ret = btrfs_insert_empty_item(trans, root, path, &key, sizeof(ref)); | ||
402 | while (ret == -EEXIST) { | ||
403 | |||
404 | } | ||
405 | |||
406 | } | ||
407 | |||
355 | int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, | 408 | int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, |
356 | struct btrfs_root *root, | 409 | struct btrfs_root *root, |
357 | u64 bytenr, u64 num_bytes) | 410 | u64 bytenr, u64 num_bytes, |
411 | u64 root_objectid, u64 root_generation, | ||
412 | u64 owner, u64 owner_offset) | ||
358 | { | 413 | { |
359 | struct btrfs_path *path; | 414 | struct btrfs_path *path; |
360 | int ret; | 415 | int ret; |
@@ -386,9 +441,10 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, | |||
386 | btrfs_mark_buffer_dirty(path->nodes[0]); | 441 | btrfs_mark_buffer_dirty(path->nodes[0]); |
387 | 442 | ||
388 | btrfs_release_path(root->fs_info->extent_root, path); | 443 | btrfs_release_path(root->fs_info->extent_root, path); |
389 | btrfs_free_path(path); | ||
390 | finish_current_insert(trans, root->fs_info->extent_root); | 444 | finish_current_insert(trans, root->fs_info->extent_root); |
391 | del_pending_extents(trans, root->fs_info->extent_root); | 445 | del_pending_extents(trans, root->fs_info->extent_root); |
446 | |||
447 | btrfs_free_path(path); | ||
392 | return 0; | 448 | return 0; |
393 | } | 449 | } |
394 | 450 | ||