diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-09-05 16:13:11 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:07 -0400 |
commit | e02119d5a7b4396c5a872582fddc8bd6d305a70a (patch) | |
tree | 825efe2a79dbca8d61256183f3526a5b5dc40dc6 /fs/btrfs/ctree.c | |
parent | a1b32a5932cfac7c38b442582285f3da2a09dfd8 (diff) |
Btrfs: Add a write ahead tree log to optimize synchronous operations
File syncs and directory syncs are optimized by copying their
items into a special (copy-on-write) log tree. There is one log tree per
subvolume and the btrfs super block points to a tree of log tree roots.
After a crash, items are copied out of the log tree and back into the
subvolume. See tree-log.c for all the details.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r-- | fs/btrfs/ctree.c | 73 |
1 files changed, 54 insertions, 19 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 7114faafa9d4..579124043d9b 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -60,7 +60,7 @@ void btrfs_free_path(struct btrfs_path *p) | |||
60 | kmem_cache_free(btrfs_path_cachep, p); | 60 | kmem_cache_free(btrfs_path_cachep, p); |
61 | } | 61 | } |
62 | 62 | ||
63 | void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p) | 63 | void noinline btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p) |
64 | { | 64 | { |
65 | int i; | 65 | int i; |
66 | 66 | ||
@@ -176,7 +176,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans, | |||
176 | return 0; | 176 | return 0; |
177 | } | 177 | } |
178 | 178 | ||
179 | int __btrfs_cow_block(struct btrfs_trans_handle *trans, | 179 | int noinline __btrfs_cow_block(struct btrfs_trans_handle *trans, |
180 | struct btrfs_root *root, | 180 | struct btrfs_root *root, |
181 | struct extent_buffer *buf, | 181 | struct extent_buffer *buf, |
182 | struct extent_buffer *parent, int parent_slot, | 182 | struct extent_buffer *parent, int parent_slot, |
@@ -294,7 +294,7 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
294 | return 0; | 294 | return 0; |
295 | } | 295 | } |
296 | 296 | ||
297 | int btrfs_cow_block(struct btrfs_trans_handle *trans, | 297 | int noinline btrfs_cow_block(struct btrfs_trans_handle *trans, |
298 | struct btrfs_root *root, struct extent_buffer *buf, | 298 | struct btrfs_root *root, struct extent_buffer *buf, |
299 | struct extent_buffer *parent, int parent_slot, | 299 | struct extent_buffer *parent, int parent_slot, |
300 | struct extent_buffer **cow_ret, u64 prealloc_dest) | 300 | struct extent_buffer **cow_ret, u64 prealloc_dest) |
@@ -677,9 +677,10 @@ static int noinline check_block(struct btrfs_root *root, | |||
677 | * | 677 | * |
678 | * slot may point to max if the key is bigger than all of the keys | 678 | * slot may point to max if the key is bigger than all of the keys |
679 | */ | 679 | */ |
680 | static int generic_bin_search(struct extent_buffer *eb, unsigned long p, | 680 | static noinline int generic_bin_search(struct extent_buffer *eb, |
681 | int item_size, struct btrfs_key *key, | 681 | unsigned long p, |
682 | int max, int *slot) | 682 | int item_size, struct btrfs_key *key, |
683 | int max, int *slot) | ||
683 | { | 684 | { |
684 | int low = 0; | 685 | int low = 0; |
685 | int high = max; | 686 | int high = max; |
@@ -765,7 +766,7 @@ static int bin_search(struct extent_buffer *eb, struct btrfs_key *key, | |||
765 | return -1; | 766 | return -1; |
766 | } | 767 | } |
767 | 768 | ||
768 | static struct extent_buffer *read_node_slot(struct btrfs_root *root, | 769 | static noinline struct extent_buffer *read_node_slot(struct btrfs_root *root, |
769 | struct extent_buffer *parent, int slot) | 770 | struct extent_buffer *parent, int slot) |
770 | { | 771 | { |
771 | int level = btrfs_header_level(parent); | 772 | int level = btrfs_header_level(parent); |
@@ -781,7 +782,7 @@ static struct extent_buffer *read_node_slot(struct btrfs_root *root, | |||
781 | btrfs_node_ptr_generation(parent, slot)); | 782 | btrfs_node_ptr_generation(parent, slot)); |
782 | } | 783 | } |
783 | 784 | ||
784 | static int balance_level(struct btrfs_trans_handle *trans, | 785 | static noinline int balance_level(struct btrfs_trans_handle *trans, |
785 | struct btrfs_root *root, | 786 | struct btrfs_root *root, |
786 | struct btrfs_path *path, int level) | 787 | struct btrfs_path *path, int level) |
787 | { | 788 | { |
@@ -1128,8 +1129,9 @@ static int noinline push_nodes_for_insert(struct btrfs_trans_handle *trans, | |||
1128 | /* | 1129 | /* |
1129 | * readahead one full node of leaves | 1130 | * readahead one full node of leaves |
1130 | */ | 1131 | */ |
1131 | static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path, | 1132 | static noinline void reada_for_search(struct btrfs_root *root, |
1132 | int level, int slot, u64 objectid) | 1133 | struct btrfs_path *path, |
1134 | int level, int slot, u64 objectid) | ||
1133 | { | 1135 | { |
1134 | struct extent_buffer *node; | 1136 | struct extent_buffer *node; |
1135 | struct btrfs_disk_key disk_key; | 1137 | struct btrfs_disk_key disk_key; |
@@ -1201,7 +1203,8 @@ static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path, | |||
1201 | } | 1203 | } |
1202 | } | 1204 | } |
1203 | 1205 | ||
1204 | static void unlock_up(struct btrfs_path *path, int level, int lowest_unlock) | 1206 | static noinline void unlock_up(struct btrfs_path *path, int level, |
1207 | int lowest_unlock) | ||
1205 | { | 1208 | { |
1206 | int i; | 1209 | int i; |
1207 | int skip_level = level; | 1210 | int skip_level = level; |
@@ -1759,8 +1762,9 @@ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1759 | * | 1762 | * |
1760 | * returns 0 on success and < 0 on failure | 1763 | * returns 0 on success and < 0 on failure |
1761 | */ | 1764 | */ |
1762 | static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root | 1765 | static noinline int split_node(struct btrfs_trans_handle *trans, |
1763 | *root, struct btrfs_path *path, int level) | 1766 | struct btrfs_root *root, |
1767 | struct btrfs_path *path, int level) | ||
1764 | { | 1768 | { |
1765 | u64 root_gen; | 1769 | u64 root_gen; |
1766 | struct extent_buffer *c; | 1770 | struct extent_buffer *c; |
@@ -1874,7 +1878,8 @@ static int leaf_space_used(struct extent_buffer *l, int start, int nr) | |||
1874 | * the start of the leaf data. IOW, how much room | 1878 | * the start of the leaf data. IOW, how much room |
1875 | * the leaf has left for both items and data | 1879 | * the leaf has left for both items and data |
1876 | */ | 1880 | */ |
1877 | int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf) | 1881 | int noinline btrfs_leaf_free_space(struct btrfs_root *root, |
1882 | struct extent_buffer *leaf) | ||
1878 | { | 1883 | { |
1879 | int nritems = btrfs_header_nritems(leaf); | 1884 | int nritems = btrfs_header_nritems(leaf); |
1880 | int ret; | 1885 | int ret; |
@@ -2283,9 +2288,11 @@ out: | |||
2283 | * | 2288 | * |
2284 | * returns 0 if all went well and < 0 on failure. | 2289 | * returns 0 if all went well and < 0 on failure. |
2285 | */ | 2290 | */ |
2286 | static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root | 2291 | static noinline int split_leaf(struct btrfs_trans_handle *trans, |
2287 | *root, struct btrfs_key *ins_key, | 2292 | struct btrfs_root *root, |
2288 | struct btrfs_path *path, int data_size, int extend) | 2293 | struct btrfs_key *ins_key, |
2294 | struct btrfs_path *path, int data_size, | ||
2295 | int extend) | ||
2289 | { | 2296 | { |
2290 | u64 root_gen; | 2297 | u64 root_gen; |
2291 | struct extent_buffer *l; | 2298 | struct extent_buffer *l; |
@@ -3079,6 +3086,7 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path) | |||
3079 | * was nothing in the tree that matched the search criteria. | 3086 | * was nothing in the tree that matched the search criteria. |
3080 | */ | 3087 | */ |
3081 | int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, | 3088 | int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, |
3089 | struct btrfs_key *max_key, | ||
3082 | struct btrfs_path *path, int cache_only, | 3090 | struct btrfs_path *path, int cache_only, |
3083 | u64 min_trans) | 3091 | u64 min_trans) |
3084 | { | 3092 | { |
@@ -3093,6 +3101,7 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, | |||
3093 | again: | 3101 | again: |
3094 | cur = btrfs_lock_root_node(root); | 3102 | cur = btrfs_lock_root_node(root); |
3095 | level = btrfs_header_level(cur); | 3103 | level = btrfs_header_level(cur); |
3104 | WARN_ON(path->nodes[level]); | ||
3096 | path->nodes[level] = cur; | 3105 | path->nodes[level] = cur; |
3097 | path->locks[level] = 1; | 3106 | path->locks[level] = 1; |
3098 | 3107 | ||
@@ -3107,6 +3116,8 @@ again: | |||
3107 | 3116 | ||
3108 | /* at level = 0, we're done, setup the path and exit */ | 3117 | /* at level = 0, we're done, setup the path and exit */ |
3109 | if (level == 0) { | 3118 | if (level == 0) { |
3119 | if (slot >= nritems) | ||
3120 | goto find_next_key; | ||
3110 | ret = 0; | 3121 | ret = 0; |
3111 | path->slots[level] = slot; | 3122 | path->slots[level] = slot; |
3112 | btrfs_item_key_to_cpu(cur, &found_key, slot); | 3123 | btrfs_item_key_to_cpu(cur, &found_key, slot); |
@@ -3123,6 +3134,8 @@ again: | |||
3123 | u64 blockptr; | 3134 | u64 blockptr; |
3124 | u64 gen; | 3135 | u64 gen; |
3125 | struct extent_buffer *tmp; | 3136 | struct extent_buffer *tmp; |
3137 | struct btrfs_disk_key disk_key; | ||
3138 | |||
3126 | blockptr = btrfs_node_blockptr(cur, slot); | 3139 | blockptr = btrfs_node_blockptr(cur, slot); |
3127 | gen = btrfs_node_ptr_generation(cur, slot); | 3140 | gen = btrfs_node_ptr_generation(cur, slot); |
3128 | if (gen < min_trans) { | 3141 | if (gen < min_trans) { |
@@ -3132,6 +3145,14 @@ again: | |||
3132 | if (!cache_only) | 3145 | if (!cache_only) |
3133 | break; | 3146 | break; |
3134 | 3147 | ||
3148 | if (max_key) { | ||
3149 | btrfs_node_key(cur, &disk_key, slot); | ||
3150 | if (comp_keys(&disk_key, max_key) >= 0) { | ||
3151 | ret = 1; | ||
3152 | goto out; | ||
3153 | } | ||
3154 | } | ||
3155 | |||
3135 | tmp = btrfs_find_tree_block(root, blockptr, | 3156 | tmp = btrfs_find_tree_block(root, blockptr, |
3136 | btrfs_level_size(root, level - 1)); | 3157 | btrfs_level_size(root, level - 1)); |
3137 | 3158 | ||
@@ -3143,14 +3164,16 @@ again: | |||
3143 | free_extent_buffer(tmp); | 3164 | free_extent_buffer(tmp); |
3144 | slot++; | 3165 | slot++; |
3145 | } | 3166 | } |
3167 | find_next_key: | ||
3146 | /* | 3168 | /* |
3147 | * we didn't find a candidate key in this node, walk forward | 3169 | * we didn't find a candidate key in this node, walk forward |
3148 | * and find another one | 3170 | * and find another one |
3149 | */ | 3171 | */ |
3150 | if (slot >= nritems) { | 3172 | if (slot >= nritems) { |
3151 | ret = btrfs_find_next_key(root, path, min_key, level, | 3173 | path->slots[level] = slot; |
3174 | sret = btrfs_find_next_key(root, path, min_key, level, | ||
3152 | cache_only, min_trans); | 3175 | cache_only, min_trans); |
3153 | if (ret == 0) { | 3176 | if (sret == 0) { |
3154 | btrfs_release_path(root, path); | 3177 | btrfs_release_path(root, path); |
3155 | goto again; | 3178 | goto again; |
3156 | } else { | 3179 | } else { |
@@ -3351,6 +3374,7 @@ int btrfs_previous_item(struct btrfs_root *root, | |||
3351 | { | 3374 | { |
3352 | struct btrfs_key found_key; | 3375 | struct btrfs_key found_key; |
3353 | struct extent_buffer *leaf; | 3376 | struct extent_buffer *leaf; |
3377 | u32 nritems; | ||
3354 | int ret; | 3378 | int ret; |
3355 | 3379 | ||
3356 | while(1) { | 3380 | while(1) { |
@@ -3362,9 +3386,20 @@ int btrfs_previous_item(struct btrfs_root *root, | |||
3362 | path->slots[0]--; | 3386 | path->slots[0]--; |
3363 | } | 3387 | } |
3364 | leaf = path->nodes[0]; | 3388 | leaf = path->nodes[0]; |
3389 | nritems = btrfs_header_nritems(leaf); | ||
3390 | if (nritems == 0) | ||
3391 | return 1; | ||
3392 | if (path->slots[0] == nritems) | ||
3393 | path->slots[0]--; | ||
3394 | |||
3365 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | 3395 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); |
3366 | if (found_key.type == type) | 3396 | if (found_key.type == type) |
3367 | return 0; | 3397 | return 0; |
3398 | if (found_key.objectid < min_objectid) | ||
3399 | break; | ||
3400 | if (found_key.objectid == min_objectid && | ||
3401 | found_key.type < type) | ||
3402 | break; | ||
3368 | } | 3403 | } |
3369 | return 1; | 3404 | return 1; |
3370 | } | 3405 | } |