aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2014-02-20 05:08:59 -0500
committerJosef Bacik <jbacik@fb.com>2014-03-10 15:16:43 -0400
commitd1433debe7f4346cf9fc0dafc71c3137d2a97bc4 (patch)
tree1cc86b5bc4a40a9ffc568ae0dbfd78bae4360c54
parent8b050d350c7846462a21e9e054c9154ede9b43cf (diff)
Btrfs: just wait or commit our own log sub-transaction
We might commit the log sub-transaction which didn't contain the metadata we logged. It was because we didn't record the log transid and just select the current log sub-transaction to commit, but the right one might be committed by the other task already. Actually, we needn't do anything and it is safe that we go back directly in this case. This patch improves the log sync by the above idea. We record the transid of the log sub-transaction in which we log the metadata, and the transid of the log sub-transaction we have committed. If the committed transid is >= the transid we record when logging the metadata, we just go back. Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Josef Bacik <jbacik@fb.com>
-rw-r--r--fs/btrfs/ctree.h3
-rw-r--r--fs/btrfs/disk-io.c2
-rw-r--r--fs/btrfs/tree-log.c63
-rw-r--r--fs/btrfs/tree-log.h2
4 files changed, 47 insertions, 23 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 906410719acb..b2c0336db691 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1723,6 +1723,9 @@ struct btrfs_root {
1723 atomic_t log_commit[2]; 1723 atomic_t log_commit[2];
1724 atomic_t log_batch; 1724 atomic_t log_batch;
1725 int log_transid; 1725 int log_transid;
1726 /* No matter the commit succeeds or not*/
1727 int log_transid_committed;
1728 /* Just be updated when the commit succeeds. */
1726 int last_log_commit; 1729 int last_log_commit;
1727 pid_t log_start_pid; 1730 pid_t log_start_pid;
1728 bool log_multiple_pids; 1731 bool log_multiple_pids;
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 44f52d280b7d..dd52146035b3 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1209,6 +1209,7 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
1209 atomic_set(&root->orphan_inodes, 0); 1209 atomic_set(&root->orphan_inodes, 0);
1210 atomic_set(&root->refs, 1); 1210 atomic_set(&root->refs, 1);
1211 root->log_transid = 0; 1211 root->log_transid = 0;
1212 root->log_transid_committed = -1;
1212 root->last_log_commit = 0; 1213 root->last_log_commit = 0;
1213 if (fs_info) 1214 if (fs_info)
1214 extent_io_tree_init(&root->dirty_log_pages, 1215 extent_io_tree_init(&root->dirty_log_pages,
@@ -1422,6 +1423,7 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
1422 WARN_ON(root->log_root); 1423 WARN_ON(root->log_root);
1423 root->log_root = log_root; 1424 root->log_root = log_root;
1424 root->log_transid = 0; 1425 root->log_transid = 0;
1426 root->log_transid_committed = -1;
1425 root->last_log_commit = 0; 1427 root->last_log_commit = 0;
1426 return 0; 1428 return 0;
1427} 1429}
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index da6da274dce3..57d4ca7fd555 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -156,6 +156,7 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
156 if (ctx) { 156 if (ctx) {
157 index = root->log_transid % 2; 157 index = root->log_transid % 2;
158 list_add_tail(&ctx->list, &root->log_ctxs[index]); 158 list_add_tail(&ctx->list, &root->log_ctxs[index]);
159 ctx->log_transid = root->log_transid;
159 } 160 }
160 mutex_unlock(&root->log_mutex); 161 mutex_unlock(&root->log_mutex);
161 return 0; 162 return 0;
@@ -181,6 +182,7 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
181 if (ctx) { 182 if (ctx) {
182 index = root->log_transid % 2; 183 index = root->log_transid % 2;
183 list_add_tail(&ctx->list, &root->log_ctxs[index]); 184 list_add_tail(&ctx->list, &root->log_ctxs[index]);
185 ctx->log_transid = root->log_transid;
184 } 186 }
185out: 187out:
186 mutex_unlock(&root->log_mutex); 188 mutex_unlock(&root->log_mutex);
@@ -2387,13 +2389,13 @@ static void wait_log_commit(struct btrfs_trans_handle *trans,
2387 &wait, TASK_UNINTERRUPTIBLE); 2389 &wait, TASK_UNINTERRUPTIBLE);
2388 mutex_unlock(&root->log_mutex); 2390 mutex_unlock(&root->log_mutex);
2389 2391
2390 if (root->log_transid < transid + 2 && 2392 if (root->log_transid_committed < transid &&
2391 atomic_read(&root->log_commit[index])) 2393 atomic_read(&root->log_commit[index]))
2392 schedule(); 2394 schedule();
2393 2395
2394 finish_wait(&root->log_commit_wait[index], &wait); 2396 finish_wait(&root->log_commit_wait[index], &wait);
2395 mutex_lock(&root->log_mutex); 2397 mutex_lock(&root->log_mutex);
2396 } while (root->log_transid < transid + 2 && 2398 } while (root->log_transid_committed < transid &&
2397 atomic_read(&root->log_commit[index])); 2399 atomic_read(&root->log_commit[index]));
2398} 2400}
2399 2401
@@ -2470,18 +2472,24 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
2470 struct blk_plug plug; 2472 struct blk_plug plug;
2471 2473
2472 mutex_lock(&root->log_mutex); 2474 mutex_lock(&root->log_mutex);
2473 log_transid = root->log_transid; 2475 log_transid = ctx->log_transid;
2474 index1 = root->log_transid % 2; 2476 if (root->log_transid_committed >= log_transid) {
2477 mutex_unlock(&root->log_mutex);
2478 return ctx->log_ret;
2479 }
2480
2481 index1 = log_transid % 2;
2475 if (atomic_read(&root->log_commit[index1])) { 2482 if (atomic_read(&root->log_commit[index1])) {
2476 wait_log_commit(trans, root, root->log_transid); 2483 wait_log_commit(trans, root, log_transid);
2477 mutex_unlock(&root->log_mutex); 2484 mutex_unlock(&root->log_mutex);
2478 return ctx->log_ret; 2485 return ctx->log_ret;
2479 } 2486 }
2487 ASSERT(log_transid == root->log_transid);
2480 atomic_set(&root->log_commit[index1], 1); 2488 atomic_set(&root->log_commit[index1], 1);
2481 2489
2482 /* wait for previous tree log sync to complete */ 2490 /* wait for previous tree log sync to complete */
2483 if (atomic_read(&root->log_commit[(index1 + 1) % 2])) 2491 if (atomic_read(&root->log_commit[(index1 + 1) % 2]))
2484 wait_log_commit(trans, root, root->log_transid - 1); 2492 wait_log_commit(trans, root, log_transid - 1);
2485 2493
2486 while (1) { 2494 while (1) {
2487 int batch = atomic_read(&root->log_batch); 2495 int batch = atomic_read(&root->log_batch);
@@ -2535,9 +2543,16 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
2535 */ 2543 */
2536 mutex_unlock(&root->log_mutex); 2544 mutex_unlock(&root->log_mutex);
2537 2545
2546 btrfs_init_log_ctx(&root_log_ctx);
2547
2538 mutex_lock(&log_root_tree->log_mutex); 2548 mutex_lock(&log_root_tree->log_mutex);
2539 atomic_inc(&log_root_tree->log_batch); 2549 atomic_inc(&log_root_tree->log_batch);
2540 atomic_inc(&log_root_tree->log_writers); 2550 atomic_inc(&log_root_tree->log_writers);
2551
2552 index2 = log_root_tree->log_transid % 2;
2553 list_add_tail(&root_log_ctx.list, &log_root_tree->log_ctxs[index2]);
2554 root_log_ctx.log_transid = log_root_tree->log_transid;
2555
2541 mutex_unlock(&log_root_tree->log_mutex); 2556 mutex_unlock(&log_root_tree->log_mutex);
2542 2557
2543 ret = update_log_root(trans, log); 2558 ret = update_log_root(trans, log);
@@ -2550,6 +2565,9 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
2550 } 2565 }
2551 2566
2552 if (ret) { 2567 if (ret) {
2568 if (!list_empty(&root_log_ctx.list))
2569 list_del_init(&root_log_ctx.list);
2570
2553 blk_finish_plug(&plug); 2571 blk_finish_plug(&plug);
2554 if (ret != -ENOSPC) { 2572 if (ret != -ENOSPC) {
2555 btrfs_abort_transaction(trans, root, ret); 2573 btrfs_abort_transaction(trans, root, ret);
@@ -2565,26 +2583,29 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
2565 goto out; 2583 goto out;
2566 } 2584 }
2567 2585
2568 index2 = log_root_tree->log_transid % 2; 2586 if (log_root_tree->log_transid_committed >= root_log_ctx.log_transid) {
2569 2587 mutex_unlock(&log_root_tree->log_mutex);
2570 btrfs_init_log_ctx(&root_log_ctx); 2588 ret = root_log_ctx.log_ret;
2571 list_add_tail(&root_log_ctx.list, &log_root_tree->log_ctxs[index2]); 2589 goto out;
2590 }
2572 2591
2592 index2 = root_log_ctx.log_transid % 2;
2573 if (atomic_read(&log_root_tree->log_commit[index2])) { 2593 if (atomic_read(&log_root_tree->log_commit[index2])) {
2574 blk_finish_plug(&plug); 2594 blk_finish_plug(&plug);
2575 btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); 2595 btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
2576 wait_log_commit(trans, log_root_tree, 2596 wait_log_commit(trans, log_root_tree,
2577 log_root_tree->log_transid); 2597 root_log_ctx.log_transid);
2578 btrfs_free_logged_extents(log, log_transid); 2598 btrfs_free_logged_extents(log, log_transid);
2579 mutex_unlock(&log_root_tree->log_mutex); 2599 mutex_unlock(&log_root_tree->log_mutex);
2580 ret = root_log_ctx.log_ret; 2600 ret = root_log_ctx.log_ret;
2581 goto out; 2601 goto out;
2582 } 2602 }
2603 ASSERT(root_log_ctx.log_transid == log_root_tree->log_transid);
2583 atomic_set(&log_root_tree->log_commit[index2], 1); 2604 atomic_set(&log_root_tree->log_commit[index2], 1);
2584 2605
2585 if (atomic_read(&log_root_tree->log_commit[(index2 + 1) % 2])) { 2606 if (atomic_read(&log_root_tree->log_commit[(index2 + 1) % 2])) {
2586 wait_log_commit(trans, log_root_tree, 2607 wait_log_commit(trans, log_root_tree,
2587 log_root_tree->log_transid - 1); 2608 root_log_ctx.log_transid - 1);
2588 } 2609 }
2589 2610
2590 wait_for_writer(trans, log_root_tree); 2611 wait_for_writer(trans, log_root_tree);
@@ -2652,26 +2673,22 @@ out_wake_log_root:
2652 */ 2673 */
2653 btrfs_remove_all_log_ctxs(log_root_tree, index2, ret); 2674 btrfs_remove_all_log_ctxs(log_root_tree, index2, ret);
2654 2675
2655 /* 2676 mutex_lock(&log_root_tree->log_mutex);
2656 * It is dangerous if log_commit is changed before we set 2677 log_root_tree->log_transid_committed++;
2657 * ->log_ret of log ctx. Because the readers may not get
2658 * the return value.
2659 */
2660 smp_wmb();
2661
2662 atomic_set(&log_root_tree->log_commit[index2], 0); 2678 atomic_set(&log_root_tree->log_commit[index2], 0);
2663 smp_mb(); 2679 mutex_unlock(&log_root_tree->log_mutex);
2680
2664 if (waitqueue_active(&log_root_tree->log_commit_wait[index2])) 2681 if (waitqueue_active(&log_root_tree->log_commit_wait[index2]))
2665 wake_up(&log_root_tree->log_commit_wait[index2]); 2682 wake_up(&log_root_tree->log_commit_wait[index2]);
2666out: 2683out:
2667 /* See above. */ 2684 /* See above. */
2668 btrfs_remove_all_log_ctxs(root, index1, ret); 2685 btrfs_remove_all_log_ctxs(root, index1, ret);
2669 2686
2670 /* See above. */ 2687 mutex_lock(&root->log_mutex);
2671 smp_wmb(); 2688 root->log_transid_committed++;
2672 atomic_set(&root->log_commit[index1], 0); 2689 atomic_set(&root->log_commit[index1], 0);
2690 mutex_unlock(&root->log_mutex);
2673 2691
2674 smp_mb();
2675 if (waitqueue_active(&root->log_commit_wait[index1])) 2692 if (waitqueue_active(&root->log_commit_wait[index1]))
2676 wake_up(&root->log_commit_wait[index1]); 2693 wake_up(&root->log_commit_wait[index1]);
2677 return ret; 2694 return ret;
diff --git a/fs/btrfs/tree-log.h b/fs/btrfs/tree-log.h
index 59c1edb31d19..91b145fce333 100644
--- a/fs/btrfs/tree-log.h
+++ b/fs/btrfs/tree-log.h
@@ -24,12 +24,14 @@
24 24
25struct btrfs_log_ctx { 25struct btrfs_log_ctx {
26 int log_ret; 26 int log_ret;
27 int log_transid;
27 struct list_head list; 28 struct list_head list;
28}; 29};
29 30
30static inline void btrfs_init_log_ctx(struct btrfs_log_ctx *ctx) 31static inline void btrfs_init_log_ctx(struct btrfs_log_ctx *ctx)
31{ 32{
32 ctx->log_ret = 0; 33 ctx->log_ret = 0;
34 ctx->log_transid = 0;
33 INIT_LIST_HEAD(&ctx->list); 35 INIT_LIST_HEAD(&ctx->list);
34} 36}
35 37