aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2009-03-13 11:00:37 -0400
committerChris Mason <chris.mason@oracle.com>2009-03-24 16:14:28 -0400
commitb9473439d3e84d9fc1a0a83faca69cc1b7566341 (patch)
treebef8321b80589026b617d61d0fabaf545d459269 /fs/btrfs/extent-tree.c
parent89573b9c516b24af8a3b9958dd5afca8fa874e3d (diff)
Btrfs: leave btree locks spinning more often
btrfs_mark_buffer dirty would set dirty bits in the extent_io tree for the buffers it was dirtying. This may require a kmalloc and it was not atomic. So, anyone who called btrfs_mark_buffer_dirty had to set any btree locks they were holding to blocking first. This commit changes dirty tracking for extent buffers to just use a flag in the extent buffer. Now that we have one and only one extent buffer per page, this can be safely done without losing dirty bits along the way. This also introduces a path->leave_spinning flag that callers of btrfs_search_slot can use to indicate they will properly deal with a path returned where all the locks are spinning instead of blocking. Many of the btree search callers now expect spinning paths, resulting in better btree concurrency overall. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c69
1 files changed, 50 insertions, 19 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index a421c32c6cfe..8933d15a240f 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -56,9 +56,6 @@ static int __btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
56 int ref_mod); 56 int ref_mod);
57static int update_reserved_extents(struct btrfs_root *root, 57static int update_reserved_extents(struct btrfs_root *root,
58 u64 bytenr, u64 num, int reserve); 58 u64 bytenr, u64 num, int reserve);
59static int pin_down_bytes(struct btrfs_trans_handle *trans,
60 struct btrfs_root *root,
61 u64 bytenr, u64 num_bytes, int is_data);
62static int update_block_group(struct btrfs_trans_handle *trans, 59static int update_block_group(struct btrfs_trans_handle *trans,
63 struct btrfs_root *root, 60 struct btrfs_root *root,
64 u64 bytenr, u64 num_bytes, int alloc, 61 u64 bytenr, u64 num_bytes, int alloc,
@@ -618,6 +615,7 @@ static noinline int insert_extent_backref(struct btrfs_trans_handle *trans,
618 } else { 615 } else {
619 goto out; 616 goto out;
620 } 617 }
618 btrfs_unlock_up_safe(path, 1);
621 btrfs_mark_buffer_dirty(path->nodes[0]); 619 btrfs_mark_buffer_dirty(path->nodes[0]);
622out: 620out:
623 btrfs_release_path(root, path); 621 btrfs_release_path(root, path);
@@ -760,6 +758,7 @@ static noinline_for_stack int add_extent_ref(struct btrfs_trans_handle *trans,
760 return -ENOMEM; 758 return -ENOMEM;
761 759
762 path->reada = 1; 760 path->reada = 1;
761 path->leave_spinning = 1;
763 key.objectid = bytenr; 762 key.objectid = bytenr;
764 key.type = BTRFS_EXTENT_ITEM_KEY; 763 key.type = BTRFS_EXTENT_ITEM_KEY;
765 key.offset = num_bytes; 764 key.offset = num_bytes;
@@ -767,8 +766,10 @@ static noinline_for_stack int add_extent_ref(struct btrfs_trans_handle *trans,
767 /* first find the extent item and update its reference count */ 766 /* first find the extent item and update its reference count */
768 ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, 767 ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key,
769 path, 0, 1); 768 path, 0, 1);
770 if (ret < 0) 769 if (ret < 0) {
770 btrfs_set_path_blocking(path);
771 return ret; 771 return ret;
772 }
772 773
773 if (ret > 0) { 774 if (ret > 0) {
774 WARN_ON(1); 775 WARN_ON(1);
@@ -791,11 +792,15 @@ static noinline_for_stack int add_extent_ref(struct btrfs_trans_handle *trans,
791 792
792 refs = btrfs_extent_refs(l, item); 793 refs = btrfs_extent_refs(l, item);
793 btrfs_set_extent_refs(l, item, refs + refs_to_add); 794 btrfs_set_extent_refs(l, item, refs + refs_to_add);
795 btrfs_unlock_up_safe(path, 1);
796
794 btrfs_mark_buffer_dirty(path->nodes[0]); 797 btrfs_mark_buffer_dirty(path->nodes[0]);
795 798
796 btrfs_release_path(root->fs_info->extent_root, path); 799 btrfs_release_path(root->fs_info->extent_root, path);
797 800
798 path->reada = 1; 801 path->reada = 1;
802 path->leave_spinning = 1;
803
799 /* now insert the actual backref */ 804 /* now insert the actual backref */
800 ret = insert_extent_backref(trans, root->fs_info->extent_root, 805 ret = insert_extent_backref(trans, root->fs_info->extent_root,
801 path, bytenr, parent, 806 path, bytenr, parent,
@@ -2050,6 +2055,8 @@ int btrfs_update_pinned_extents(struct btrfs_root *root,
2050 clear_extent_dirty(&fs_info->pinned_extents, 2055 clear_extent_dirty(&fs_info->pinned_extents,
2051 bytenr, bytenr + num - 1, GFP_NOFS); 2056 bytenr, bytenr + num - 1, GFP_NOFS);
2052 } 2057 }
2058 mutex_unlock(&root->fs_info->pinned_mutex);
2059
2053 while (num > 0) { 2060 while (num > 0) {
2054 cache = btrfs_lookup_block_group(fs_info, bytenr); 2061 cache = btrfs_lookup_block_group(fs_info, bytenr);
2055 BUG_ON(!cache); 2062 BUG_ON(!cache);
@@ -2141,8 +2148,8 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
2141 u64 end; 2148 u64 end;
2142 int ret; 2149 int ret;
2143 2150
2144 mutex_lock(&root->fs_info->pinned_mutex);
2145 while (1) { 2151 while (1) {
2152 mutex_lock(&root->fs_info->pinned_mutex);
2146 ret = find_first_extent_bit(unpin, 0, &start, &end, 2153 ret = find_first_extent_bit(unpin, 0, &start, &end,
2147 EXTENT_DIRTY); 2154 EXTENT_DIRTY);
2148 if (ret) 2155 if (ret)
@@ -2150,14 +2157,11 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
2150 2157
2151 ret = btrfs_discard_extent(root, start, end + 1 - start); 2158 ret = btrfs_discard_extent(root, start, end + 1 - start);
2152 2159
2160 /* unlocks the pinned mutex */
2153 btrfs_update_pinned_extents(root, start, end + 1 - start, 0); 2161 btrfs_update_pinned_extents(root, start, end + 1 - start, 0);
2154 clear_extent_dirty(unpin, start, end, GFP_NOFS); 2162 clear_extent_dirty(unpin, start, end, GFP_NOFS);
2155 2163
2156 if (need_resched()) { 2164 cond_resched();
2157 mutex_unlock(&root->fs_info->pinned_mutex);
2158 cond_resched();
2159 mutex_lock(&root->fs_info->pinned_mutex);
2160 }
2161 } 2165 }
2162 mutex_unlock(&root->fs_info->pinned_mutex); 2166 mutex_unlock(&root->fs_info->pinned_mutex);
2163 return ret; 2167 return ret;
@@ -2165,7 +2169,9 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
2165 2169
2166static int pin_down_bytes(struct btrfs_trans_handle *trans, 2170static int pin_down_bytes(struct btrfs_trans_handle *trans,
2167 struct btrfs_root *root, 2171 struct btrfs_root *root,
2168 u64 bytenr, u64 num_bytes, int is_data) 2172 struct btrfs_path *path,
2173 u64 bytenr, u64 num_bytes, int is_data,
2174 struct extent_buffer **must_clean)
2169{ 2175{
2170 int err = 0; 2176 int err = 0;
2171 struct extent_buffer *buf; 2177 struct extent_buffer *buf;
@@ -2191,15 +2197,16 @@ static int pin_down_bytes(struct btrfs_trans_handle *trans,
2191 header_owner != BTRFS_DATA_RELOC_TREE_OBJECTID && 2197 header_owner != BTRFS_DATA_RELOC_TREE_OBJECTID &&
2192 header_transid == trans->transid && 2198 header_transid == trans->transid &&
2193 !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) { 2199 !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) {
2194 clean_tree_block(NULL, root, buf); 2200 *must_clean = buf;
2195 btrfs_tree_unlock(buf);
2196 free_extent_buffer(buf);
2197 return 1; 2201 return 1;
2198 } 2202 }
2199 btrfs_tree_unlock(buf); 2203 btrfs_tree_unlock(buf);
2200 } 2204 }
2201 free_extent_buffer(buf); 2205 free_extent_buffer(buf);
2202pinit: 2206pinit:
2207 btrfs_set_path_blocking(path);
2208 mutex_lock(&root->fs_info->pinned_mutex);
2209 /* unlocks the pinned mutex */
2203 btrfs_update_pinned_extents(root, bytenr, num_bytes, 1); 2210 btrfs_update_pinned_extents(root, bytenr, num_bytes, 1);
2204 2211
2205 BUG_ON(err < 0); 2212 BUG_ON(err < 0);
@@ -2236,6 +2243,7 @@ static int __free_extent(struct btrfs_trans_handle *trans,
2236 return -ENOMEM; 2243 return -ENOMEM;
2237 2244
2238 path->reada = 1; 2245 path->reada = 1;
2246 path->leave_spinning = 1;
2239 ret = lookup_extent_backref(trans, extent_root, path, 2247 ret = lookup_extent_backref(trans, extent_root, path,
2240 bytenr, parent, root_objectid, 2248 bytenr, parent, root_objectid,
2241 ref_generation, owner_objectid, 1); 2249 ref_generation, owner_objectid, 1);
@@ -2261,6 +2269,7 @@ static int __free_extent(struct btrfs_trans_handle *trans,
2261 refs_to_drop); 2269 refs_to_drop);
2262 BUG_ON(ret); 2270 BUG_ON(ret);
2263 btrfs_release_path(extent_root, path); 2271 btrfs_release_path(extent_root, path);
2272 path->leave_spinning = 1;
2264 ret = btrfs_search_slot(trans, extent_root, 2273 ret = btrfs_search_slot(trans, extent_root,
2265 &key, path, -1, 1); 2274 &key, path, -1, 1);
2266 if (ret) { 2275 if (ret) {
@@ -2318,6 +2327,7 @@ static int __free_extent(struct btrfs_trans_handle *trans,
2318 /* if refs are 0, we need to setup the path for deletion */ 2327 /* if refs are 0, we need to setup the path for deletion */
2319 if (refs == 0) { 2328 if (refs == 0) {
2320 btrfs_release_path(extent_root, path); 2329 btrfs_release_path(extent_root, path);
2330 path->leave_spinning = 1;
2321 ret = btrfs_search_slot(trans, extent_root, &key, path, 2331 ret = btrfs_search_slot(trans, extent_root, &key, path,
2322 -1, 1); 2332 -1, 1);
2323 BUG_ON(ret); 2333 BUG_ON(ret);
@@ -2327,16 +2337,18 @@ static int __free_extent(struct btrfs_trans_handle *trans,
2327 if (refs == 0) { 2337 if (refs == 0) {
2328 u64 super_used; 2338 u64 super_used;
2329 u64 root_used; 2339 u64 root_used;
2340 struct extent_buffer *must_clean = NULL;
2330 2341
2331 if (pin) { 2342 if (pin) {
2332 mutex_lock(&root->fs_info->pinned_mutex); 2343 ret = pin_down_bytes(trans, root, path,
2333 ret = pin_down_bytes(trans, root, bytenr, num_bytes, 2344 bytenr, num_bytes,
2334 owner_objectid >= BTRFS_FIRST_FREE_OBJECTID); 2345 owner_objectid >= BTRFS_FIRST_FREE_OBJECTID,
2335 mutex_unlock(&root->fs_info->pinned_mutex); 2346 &must_clean);
2336 if (ret > 0) 2347 if (ret > 0)
2337 mark_free = 1; 2348 mark_free = 1;
2338 BUG_ON(ret < 0); 2349 BUG_ON(ret < 0);
2339 } 2350 }
2351
2340 /* block accounting for super block */ 2352 /* block accounting for super block */
2341 spin_lock(&info->delalloc_lock); 2353 spin_lock(&info->delalloc_lock);
2342 super_used = btrfs_super_bytes_used(&info->super_copy); 2354 super_used = btrfs_super_bytes_used(&info->super_copy);
@@ -2348,11 +2360,27 @@ static int __free_extent(struct btrfs_trans_handle *trans,
2348 btrfs_set_root_used(&root->root_item, 2360 btrfs_set_root_used(&root->root_item,
2349 root_used - num_bytes); 2361 root_used - num_bytes);
2350 spin_unlock(&info->delalloc_lock); 2362 spin_unlock(&info->delalloc_lock);
2363
2364 /*
2365 * it is going to be very rare for someone to be waiting
2366 * on the block we're freeing. del_items might need to
2367 * schedule, so rather than get fancy, just force it
2368 * to blocking here
2369 */
2370 if (must_clean)
2371 btrfs_set_lock_blocking(must_clean);
2372
2351 ret = btrfs_del_items(trans, extent_root, path, path->slots[0], 2373 ret = btrfs_del_items(trans, extent_root, path, path->slots[0],
2352 num_to_del); 2374 num_to_del);
2353 BUG_ON(ret); 2375 BUG_ON(ret);
2354 btrfs_release_path(extent_root, path); 2376 btrfs_release_path(extent_root, path);
2355 2377
2378 if (must_clean) {
2379 clean_tree_block(NULL, root, must_clean);
2380 btrfs_tree_unlock(must_clean);
2381 free_extent_buffer(must_clean);
2382 }
2383
2356 if (owner_objectid >= BTRFS_FIRST_FREE_OBJECTID) { 2384 if (owner_objectid >= BTRFS_FIRST_FREE_OBJECTID) {
2357 ret = btrfs_del_csums(trans, root, bytenr, num_bytes); 2385 ret = btrfs_del_csums(trans, root, bytenr, num_bytes);
2358 BUG_ON(ret); 2386 BUG_ON(ret);
@@ -2480,8 +2508,9 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans,
2480 if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID && 2508 if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID &&
2481 owner_objectid < BTRFS_FIRST_FREE_OBJECTID) { 2509 owner_objectid < BTRFS_FIRST_FREE_OBJECTID) {
2482 mutex_lock(&root->fs_info->pinned_mutex); 2510 mutex_lock(&root->fs_info->pinned_mutex);
2511
2512 /* unlocks the pinned mutex */
2483 btrfs_update_pinned_extents(root, bytenr, num_bytes, 1); 2513 btrfs_update_pinned_extents(root, bytenr, num_bytes, 1);
2484 mutex_unlock(&root->fs_info->pinned_mutex);
2485 update_reserved_extents(root, bytenr, num_bytes, 0); 2514 update_reserved_extents(root, bytenr, num_bytes, 0);
2486 ret = 0; 2515 ret = 0;
2487 } else { 2516 } else {
@@ -2931,6 +2960,7 @@ static int __btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
2931 path = btrfs_alloc_path(); 2960 path = btrfs_alloc_path();
2932 BUG_ON(!path); 2961 BUG_ON(!path);
2933 2962
2963 path->leave_spinning = 1;
2934 ret = btrfs_insert_empty_items(trans, extent_root, path, keys, 2964 ret = btrfs_insert_empty_items(trans, extent_root, path, keys,
2935 sizes, 2); 2965 sizes, 2);
2936 BUG_ON(ret); 2966 BUG_ON(ret);
@@ -5435,6 +5465,7 @@ static int __insert_orphan_inode(struct btrfs_trans_handle *trans,
5435 if (!path) 5465 if (!path)
5436 return -ENOMEM; 5466 return -ENOMEM;
5437 5467
5468 path->leave_spinning = 1;
5438 ret = btrfs_insert_empty_inode(trans, root, path, objectid); 5469 ret = btrfs_insert_empty_inode(trans, root, path, objectid);
5439 if (ret) 5470 if (ret)
5440 goto out; 5471 goto out;