aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJan Schmidt <list.btrfs@jan-o-sch.net>2011-12-12 10:10:07 -0500
committerJan Schmidt <list.btrfs@jan-o-sch.net>2012-01-04 10:12:48 -0500
commita168650c08300434e1456abe7b6451f1448230d3 (patch)
treeaddddb060b018eb569e97c11e1a1451feef11c7a /fs
parentd1270cd91f308c9d22b2804720c36ccd32dbc35e (diff)
Btrfs: add waitqueue instead of doing busy waiting for more delayed refs
Now that we may be holding back delayed refs for a limited period, we might end up having no runnable delayed refs. Without this commit, we'd do busy waiting in that thread until another (runnable) ref arives. Instead, we're detecting this situation and use a waitqueue, such that we only try to run more refs after a) another runnable ref was added or b) delayed refs are no longer held back Signed-off-by: Jan Schmidt <list.btrfs@jan-o-sch.net>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/delayed-ref.c8
-rw-r--r--fs/btrfs/delayed-ref.h7
-rw-r--r--fs/btrfs/extent-tree.c59
-rw-r--r--fs/btrfs/transaction.c1
4 files changed, 74 insertions, 1 deletions
diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c
index ee181989d444..66e4f29505a3 100644
--- a/fs/btrfs/delayed-ref.c
+++ b/fs/btrfs/delayed-ref.c
@@ -664,6 +664,9 @@ int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
664 num_bytes, parent, ref_root, level, action, 664 num_bytes, parent, ref_root, level, action,
665 for_cow); 665 for_cow);
666 BUG_ON(ret); 666 BUG_ON(ret);
667 if (!need_ref_seq(for_cow, ref_root) &&
668 waitqueue_active(&delayed_refs->seq_wait))
669 wake_up(&delayed_refs->seq_wait);
667 spin_unlock(&delayed_refs->lock); 670 spin_unlock(&delayed_refs->lock);
668 return 0; 671 return 0;
669} 672}
@@ -712,6 +715,9 @@ int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info,
712 num_bytes, parent, ref_root, owner, offset, 715 num_bytes, parent, ref_root, owner, offset,
713 action, for_cow); 716 action, for_cow);
714 BUG_ON(ret); 717 BUG_ON(ret);
718 if (!need_ref_seq(for_cow, ref_root) &&
719 waitqueue_active(&delayed_refs->seq_wait))
720 wake_up(&delayed_refs->seq_wait);
715 spin_unlock(&delayed_refs->lock); 721 spin_unlock(&delayed_refs->lock);
716 return 0; 722 return 0;
717} 723}
@@ -739,6 +745,8 @@ int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info,
739 extent_op->is_data); 745 extent_op->is_data);
740 BUG_ON(ret); 746 BUG_ON(ret);
741 747
748 if (waitqueue_active(&delayed_refs->seq_wait))
749 wake_up(&delayed_refs->seq_wait);
742 spin_unlock(&delayed_refs->lock); 750 spin_unlock(&delayed_refs->lock);
743 return 0; 751 return 0;
744} 752}
diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h
index 174416f7882b..d8f244d94925 100644
--- a/fs/btrfs/delayed-ref.h
+++ b/fs/btrfs/delayed-ref.h
@@ -153,6 +153,12 @@ struct btrfs_delayed_ref_root {
153 * as it might influence the outcome of the walk. 153 * as it might influence the outcome of the walk.
154 */ 154 */
155 struct list_head seq_head; 155 struct list_head seq_head;
156
157 /*
158 * when the only refs we have in the list must not be processed, we want
159 * to wait for more refs to show up or for the end of backref walking.
160 */
161 wait_queue_head_t seq_wait;
156}; 162};
157 163
158static inline void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref) 164static inline void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref)
@@ -216,6 +222,7 @@ btrfs_put_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs,
216{ 222{
217 spin_lock(&delayed_refs->lock); 223 spin_lock(&delayed_refs->lock);
218 list_del(&elem->list); 224 list_del(&elem->list);
225 wake_up(&delayed_refs->seq_wait);
219 spin_unlock(&delayed_refs->lock); 226 spin_unlock(&delayed_refs->lock);
220} 227}
221 228
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index bbcca12fbbba..0a435e2e143e 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -2300,7 +2300,12 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
2300 ref->in_tree = 0; 2300 ref->in_tree = 0;
2301 rb_erase(&ref->rb_node, &delayed_refs->root); 2301 rb_erase(&ref->rb_node, &delayed_refs->root);
2302 delayed_refs->num_entries--; 2302 delayed_refs->num_entries--;
2303 2303 /*
2304 * we modified num_entries, but as we're currently running
2305 * delayed refs, skip
2306 * wake_up(&delayed_refs->seq_wait);
2307 * here.
2308 */
2304 spin_unlock(&delayed_refs->lock); 2309 spin_unlock(&delayed_refs->lock);
2305 2310
2306 ret = run_one_delayed_ref(trans, root, ref, extent_op, 2311 ret = run_one_delayed_ref(trans, root, ref, extent_op,
@@ -2317,6 +2322,23 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
2317 return count; 2322 return count;
2318} 2323}
2319 2324
2325
2326static void wait_for_more_refs(struct btrfs_delayed_ref_root *delayed_refs,
2327 unsigned long num_refs)
2328{
2329 struct list_head *first_seq = delayed_refs->seq_head.next;
2330
2331 spin_unlock(&delayed_refs->lock);
2332 pr_debug("waiting for more refs (num %ld, first %p)\n",
2333 num_refs, first_seq);
2334 wait_event(delayed_refs->seq_wait,
2335 num_refs != delayed_refs->num_entries ||
2336 delayed_refs->seq_head.next != first_seq);
2337 pr_debug("done waiting for more refs (num %ld, first %p)\n",
2338 delayed_refs->num_entries, delayed_refs->seq_head.next);
2339 spin_lock(&delayed_refs->lock);
2340}
2341
2320/* 2342/*
2321 * this starts processing the delayed reference count updates and 2343 * this starts processing the delayed reference count updates and
2322 * extent insertions we have queued up so far. count can be 2344 * extent insertions we have queued up so far. count can be
@@ -2332,8 +2354,11 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
2332 struct btrfs_delayed_ref_node *ref; 2354 struct btrfs_delayed_ref_node *ref;
2333 struct list_head cluster; 2355 struct list_head cluster;
2334 int ret; 2356 int ret;
2357 u64 delayed_start;
2335 int run_all = count == (unsigned long)-1; 2358 int run_all = count == (unsigned long)-1;
2336 int run_most = 0; 2359 int run_most = 0;
2360 unsigned long num_refs = 0;
2361 int consider_waiting;
2337 2362
2338 if (root == root->fs_info->extent_root) 2363 if (root == root->fs_info->extent_root)
2339 root = root->fs_info->tree_root; 2364 root = root->fs_info->tree_root;
@@ -2341,6 +2366,7 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
2341 delayed_refs = &trans->transaction->delayed_refs; 2366 delayed_refs = &trans->transaction->delayed_refs;
2342 INIT_LIST_HEAD(&cluster); 2367 INIT_LIST_HEAD(&cluster);
2343again: 2368again:
2369 consider_waiting = 0;
2344 spin_lock(&delayed_refs->lock); 2370 spin_lock(&delayed_refs->lock);
2345 if (count == 0) { 2371 if (count == 0) {
2346 count = delayed_refs->num_entries * 2; 2372 count = delayed_refs->num_entries * 2;
@@ -2357,11 +2383,35 @@ again:
2357 * of refs to process starting at the first one we are able to 2383 * of refs to process starting at the first one we are able to
2358 * lock 2384 * lock
2359 */ 2385 */
2386 delayed_start = delayed_refs->run_delayed_start;
2360 ret = btrfs_find_ref_cluster(trans, &cluster, 2387 ret = btrfs_find_ref_cluster(trans, &cluster,
2361 delayed_refs->run_delayed_start); 2388 delayed_refs->run_delayed_start);
2362 if (ret) 2389 if (ret)
2363 break; 2390 break;
2364 2391
2392 if (delayed_start >= delayed_refs->run_delayed_start) {
2393 if (consider_waiting == 0) {
2394 /*
2395 * btrfs_find_ref_cluster looped. let's do one
2396 * more cycle. if we don't run any delayed ref
2397 * during that cycle (because we can't because
2398 * all of them are blocked) and if the number of
2399 * refs doesn't change, we avoid busy waiting.
2400 */
2401 consider_waiting = 1;
2402 num_refs = delayed_refs->num_entries;
2403 } else {
2404 wait_for_more_refs(delayed_refs, num_refs);
2405 /*
2406 * after waiting, things have changed. we
2407 * dropped the lock and someone else might have
2408 * run some refs, built new clusters and so on.
2409 * therefore, we restart staleness detection.
2410 */
2411 consider_waiting = 0;
2412 }
2413 }
2414
2365 ret = run_clustered_refs(trans, root, &cluster); 2415 ret = run_clustered_refs(trans, root, &cluster);
2366 BUG_ON(ret < 0); 2416 BUG_ON(ret < 0);
2367 2417
@@ -2369,6 +2419,11 @@ again:
2369 2419
2370 if (count == 0) 2420 if (count == 0)
2371 break; 2421 break;
2422
2423 if (ret || delayed_refs->run_delayed_start == 0) {
2424 /* refs were run, let's reset staleness detection */
2425 consider_waiting = 0;
2426 }
2372 } 2427 }
2373 2428
2374 if (run_all) { 2429 if (run_all) {
@@ -4933,6 +4988,8 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans,
4933 rb_erase(&head->node.rb_node, &delayed_refs->root); 4988 rb_erase(&head->node.rb_node, &delayed_refs->root);
4934 4989
4935 delayed_refs->num_entries--; 4990 delayed_refs->num_entries--;
4991 if (waitqueue_active(&delayed_refs->seq_wait))
4992 wake_up(&delayed_refs->seq_wait);
4936 4993
4937 /* 4994 /*
4938 * we don't take a ref on the node because we're removing it from the 4995 * we don't take a ref on the node because we're removing it from the
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 31a7393af64e..04c5c7c2c32f 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -111,6 +111,7 @@ loop:
111 cur_trans->delayed_refs.flushing = 0; 111 cur_trans->delayed_refs.flushing = 0;
112 cur_trans->delayed_refs.run_delayed_start = 0; 112 cur_trans->delayed_refs.run_delayed_start = 0;
113 cur_trans->delayed_refs.seq = 1; 113 cur_trans->delayed_refs.seq = 1;
114 init_waitqueue_head(&cur_trans->delayed_refs.seq_wait);
114 spin_lock_init(&cur_trans->commit_lock); 115 spin_lock_init(&cur_trans->commit_lock);
115 spin_lock_init(&cur_trans->delayed_refs.lock); 116 spin_lock_init(&cur_trans->delayed_refs.lock);
116 INIT_LIST_HEAD(&cur_trans->delayed_refs.seq_head); 117 INIT_LIST_HEAD(&cur_trans->delayed_refs.seq_head);