aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/tree-log.c
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2014-02-20 05:08:58 -0500
committerJosef Bacik <jbacik@fb.com>2014-03-10 15:16:43 -0400
commit8b050d350c7846462a21e9e054c9154ede9b43cf (patch)
tree3e756c4aeefc74fafa7db71293e92dac20832ed3 /fs/btrfs/tree-log.c
parentbb14a59b619d3a9993c3fa04bb10347db35ca550 (diff)
Btrfs: fix skipped error handle when log sync failed
It is possible that many tasks sync the log tree at the same time, but only one task can do the sync work, the others will wait for it. But those wait tasks didn't get the result of the log sync, and returned 0 when they ended the wait. It caused those tasks skipped the error handle, and the serious problem was they told the users the file sync succeeded but in fact they failed. This patch fixes this problem by introducing a log context structure, we insert it into the a global list. When the sync fails, we will set the error number of every log context in the list, then the waiting tasks get the error number of the log context and handle the error if need. Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Josef Bacik <jbacik@fb.com>
Diffstat (limited to 'fs/btrfs/tree-log.c')
-rw-r--r--fs/btrfs/tree-log.c114
1 files changed, 88 insertions, 26 deletions
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 128a904ceac0..da6da274dce3 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -136,8 +136,10 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
136 * syncing the tree wait for us to finish 136 * syncing the tree wait for us to finish
137 */ 137 */
138static int start_log_trans(struct btrfs_trans_handle *trans, 138static int start_log_trans(struct btrfs_trans_handle *trans,
139 struct btrfs_root *root) 139 struct btrfs_root *root,
140 struct btrfs_log_ctx *ctx)
140{ 141{
142 int index;
141 int ret; 143 int ret;
142 144
143 mutex_lock(&root->log_mutex); 145 mutex_lock(&root->log_mutex);
@@ -151,6 +153,10 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
151 153
152 atomic_inc(&root->log_batch); 154 atomic_inc(&root->log_batch);
153 atomic_inc(&root->log_writers); 155 atomic_inc(&root->log_writers);
156 if (ctx) {
157 index = root->log_transid % 2;
158 list_add_tail(&ctx->list, &root->log_ctxs[index]);
159 }
154 mutex_unlock(&root->log_mutex); 160 mutex_unlock(&root->log_mutex);
155 return 0; 161 return 0;
156 } 162 }
@@ -172,6 +178,10 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
172 root->log_start_pid = current->pid; 178 root->log_start_pid = current->pid;
173 atomic_inc(&root->log_batch); 179 atomic_inc(&root->log_batch);
174 atomic_inc(&root->log_writers); 180 atomic_inc(&root->log_writers);
181 if (ctx) {
182 index = root->log_transid % 2;
183 list_add_tail(&ctx->list, &root->log_ctxs[index]);
184 }
175out: 185out:
176 mutex_unlock(&root->log_mutex); 186 mutex_unlock(&root->log_mutex);
177 return ret; 187 return ret;
@@ -2361,12 +2371,11 @@ static int update_log_root(struct btrfs_trans_handle *trans,
2361 return ret; 2371 return ret;
2362} 2372}
2363 2373
2364static int wait_log_commit(struct btrfs_trans_handle *trans, 2374static void wait_log_commit(struct btrfs_trans_handle *trans,
2365 struct btrfs_root *root, int transid) 2375 struct btrfs_root *root, int transid)
2366{ 2376{
2367 DEFINE_WAIT(wait); 2377 DEFINE_WAIT(wait);
2368 int index = transid % 2; 2378 int index = transid % 2;
2369 int ret = 0;
2370 2379
2371 /* 2380 /*
2372 * we only allow two pending log transactions at a time, 2381 * we only allow two pending log transactions at a time,
@@ -2374,12 +2383,6 @@ static int wait_log_commit(struct btrfs_trans_handle *trans,
2374 * current transaction, we're done 2383 * current transaction, we're done
2375 */ 2384 */
2376 do { 2385 do {
2377 if (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) ==
2378 trans->transid) {
2379 ret = -EAGAIN;
2380 break;
2381 }
2382
2383 prepare_to_wait(&root->log_commit_wait[index], 2386 prepare_to_wait(&root->log_commit_wait[index],
2384 &wait, TASK_UNINTERRUPTIBLE); 2387 &wait, TASK_UNINTERRUPTIBLE);
2385 mutex_unlock(&root->log_mutex); 2388 mutex_unlock(&root->log_mutex);
@@ -2392,27 +2395,55 @@ static int wait_log_commit(struct btrfs_trans_handle *trans,
2392 mutex_lock(&root->log_mutex); 2395 mutex_lock(&root->log_mutex);
2393 } while (root->log_transid < transid + 2 && 2396 } while (root->log_transid < transid + 2 &&
2394 atomic_read(&root->log_commit[index])); 2397 atomic_read(&root->log_commit[index]));
2395
2396 return ret;
2397} 2398}
2398 2399
2399static void wait_for_writer(struct btrfs_trans_handle *trans, 2400static void wait_for_writer(struct btrfs_trans_handle *trans,
2400 struct btrfs_root *root) 2401 struct btrfs_root *root)
2401{ 2402{
2402 DEFINE_WAIT(wait); 2403 DEFINE_WAIT(wait);
2403 while (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) != 2404
2404 trans->transid && atomic_read(&root->log_writers)) { 2405 while (atomic_read(&root->log_writers)) {
2405 prepare_to_wait(&root->log_writer_wait, 2406 prepare_to_wait(&root->log_writer_wait,
2406 &wait, TASK_UNINTERRUPTIBLE); 2407 &wait, TASK_UNINTERRUPTIBLE);
2407 mutex_unlock(&root->log_mutex); 2408 mutex_unlock(&root->log_mutex);
2408 if (ACCESS_ONCE(root->fs_info->last_trans_log_full_commit) != 2409 if (atomic_read(&root->log_writers))
2409 trans->transid && atomic_read(&root->log_writers))
2410 schedule(); 2410 schedule();
2411 mutex_lock(&root->log_mutex); 2411 mutex_lock(&root->log_mutex);
2412 finish_wait(&root->log_writer_wait, &wait); 2412 finish_wait(&root->log_writer_wait, &wait);
2413 } 2413 }
2414} 2414}
2415 2415
2416static inline void btrfs_remove_log_ctx(struct btrfs_root *root,
2417 struct btrfs_log_ctx *ctx)
2418{
2419 if (!ctx)
2420 return;
2421
2422 mutex_lock(&root->log_mutex);
2423 list_del_init(&ctx->list);
2424 mutex_unlock(&root->log_mutex);
2425}
2426
2427/*
2428 * Invoked in log mutex context, or be sure there is no other task which
2429 * can access the list.
2430 */
2431static inline void btrfs_remove_all_log_ctxs(struct btrfs_root *root,
2432 int index, int error)
2433{
2434 struct btrfs_log_ctx *ctx;
2435
2436 if (!error) {
2437 INIT_LIST_HEAD(&root->log_ctxs[index]);
2438 return;
2439 }
2440
2441 list_for_each_entry(ctx, &root->log_ctxs[index], list)
2442 ctx->log_ret = error;
2443
2444 INIT_LIST_HEAD(&root->log_ctxs[index]);
2445}
2446
2416/* 2447/*
2417 * btrfs_sync_log does sends a given tree log down to the disk and 2448 * btrfs_sync_log does sends a given tree log down to the disk and
2418 * updates the super blocks to record it. When this call is done, 2449 * updates the super blocks to record it. When this call is done,
@@ -2426,7 +2457,7 @@ static void wait_for_writer(struct btrfs_trans_handle *trans,
2426 * that has happened. 2457 * that has happened.
2427 */ 2458 */
2428int btrfs_sync_log(struct btrfs_trans_handle *trans, 2459int btrfs_sync_log(struct btrfs_trans_handle *trans,
2429 struct btrfs_root *root) 2460 struct btrfs_root *root, struct btrfs_log_ctx *ctx)
2430{ 2461{
2431 int index1; 2462 int index1;
2432 int index2; 2463 int index2;
@@ -2435,15 +2466,16 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
2435 struct btrfs_root *log = root->log_root; 2466 struct btrfs_root *log = root->log_root;
2436 struct btrfs_root *log_root_tree = root->fs_info->log_root_tree; 2467 struct btrfs_root *log_root_tree = root->fs_info->log_root_tree;
2437 int log_transid = 0; 2468 int log_transid = 0;
2469 struct btrfs_log_ctx root_log_ctx;
2438 struct blk_plug plug; 2470 struct blk_plug plug;
2439 2471
2440 mutex_lock(&root->log_mutex); 2472 mutex_lock(&root->log_mutex);
2441 log_transid = root->log_transid; 2473 log_transid = root->log_transid;
2442 index1 = root->log_transid % 2; 2474 index1 = root->log_transid % 2;
2443 if (atomic_read(&root->log_commit[index1])) { 2475 if (atomic_read(&root->log_commit[index1])) {
2444 ret = wait_log_commit(trans, root, root->log_transid); 2476 wait_log_commit(trans, root, root->log_transid);
2445 mutex_unlock(&root->log_mutex); 2477 mutex_unlock(&root->log_mutex);
2446 return ret; 2478 return ctx->log_ret;
2447 } 2479 }
2448 atomic_set(&root->log_commit[index1], 1); 2480 atomic_set(&root->log_commit[index1], 1);
2449 2481
@@ -2534,13 +2566,18 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
2534 } 2566 }
2535 2567
2536 index2 = log_root_tree->log_transid % 2; 2568 index2 = log_root_tree->log_transid % 2;
2569
2570 btrfs_init_log_ctx(&root_log_ctx);
2571 list_add_tail(&root_log_ctx.list, &log_root_tree->log_ctxs[index2]);
2572
2537 if (atomic_read(&log_root_tree->log_commit[index2])) { 2573 if (atomic_read(&log_root_tree->log_commit[index2])) {
2538 blk_finish_plug(&plug); 2574 blk_finish_plug(&plug);
2539 btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); 2575 btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark);
2540 ret = wait_log_commit(trans, log_root_tree, 2576 wait_log_commit(trans, log_root_tree,
2541 log_root_tree->log_transid); 2577 log_root_tree->log_transid);
2542 btrfs_free_logged_extents(log, log_transid); 2578 btrfs_free_logged_extents(log, log_transid);
2543 mutex_unlock(&log_root_tree->log_mutex); 2579 mutex_unlock(&log_root_tree->log_mutex);
2580 ret = root_log_ctx.log_ret;
2544 goto out; 2581 goto out;
2545 } 2582 }
2546 atomic_set(&log_root_tree->log_commit[index2], 1); 2583 atomic_set(&log_root_tree->log_commit[index2], 1);
@@ -2609,12 +2646,31 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
2609 mutex_unlock(&root->log_mutex); 2646 mutex_unlock(&root->log_mutex);
2610 2647
2611out_wake_log_root: 2648out_wake_log_root:
2649 /*
2650 * We needn't get log_mutex here because we are sure all
2651 * the other tasks are blocked.
2652 */
2653 btrfs_remove_all_log_ctxs(log_root_tree, index2, ret);
2654
2655 /*
2656 * It is dangerous if log_commit is changed before we set
2657 * ->log_ret of log ctx. Because the readers may not get
2658 * the return value.
2659 */
2660 smp_wmb();
2661
2612 atomic_set(&log_root_tree->log_commit[index2], 0); 2662 atomic_set(&log_root_tree->log_commit[index2], 0);
2613 smp_mb(); 2663 smp_mb();
2614 if (waitqueue_active(&log_root_tree->log_commit_wait[index2])) 2664 if (waitqueue_active(&log_root_tree->log_commit_wait[index2]))
2615 wake_up(&log_root_tree->log_commit_wait[index2]); 2665 wake_up(&log_root_tree->log_commit_wait[index2]);
2616out: 2666out:
2667 /* See above. */
2668 btrfs_remove_all_log_ctxs(root, index1, ret);
2669
2670 /* See above. */
2671 smp_wmb();
2617 atomic_set(&root->log_commit[index1], 0); 2672 atomic_set(&root->log_commit[index1], 0);
2673
2618 smp_mb(); 2674 smp_mb();
2619 if (waitqueue_active(&root->log_commit_wait[index1])) 2675 if (waitqueue_active(&root->log_commit_wait[index1]))
2620 wake_up(&root->log_commit_wait[index1]); 2676 wake_up(&root->log_commit_wait[index1]);
@@ -4076,7 +4132,8 @@ out:
4076 */ 4132 */
4077static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, 4133static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
4078 struct btrfs_root *root, struct inode *inode, 4134 struct btrfs_root *root, struct inode *inode,
4079 struct dentry *parent, int exists_only) 4135 struct dentry *parent, int exists_only,
4136 struct btrfs_log_ctx *ctx)
4080{ 4137{
4081 int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL; 4138 int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL;
4082 struct super_block *sb; 4139 struct super_block *sb;
@@ -4113,7 +4170,7 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
4113 goto end_no_trans; 4170 goto end_no_trans;
4114 } 4171 }
4115 4172
4116 ret = start_log_trans(trans, root); 4173 ret = start_log_trans(trans, root, ctx);
4117 if (ret) 4174 if (ret)
4118 goto end_no_trans; 4175 goto end_no_trans;
4119 4176
@@ -4163,6 +4220,9 @@ end_trans:
4163 root->fs_info->last_trans_log_full_commit = trans->transid; 4220 root->fs_info->last_trans_log_full_commit = trans->transid;
4164 ret = 1; 4221 ret = 1;
4165 } 4222 }
4223
4224 if (ret)
4225 btrfs_remove_log_ctx(root, ctx);
4166 btrfs_end_log_trans(root); 4226 btrfs_end_log_trans(root);
4167end_no_trans: 4227end_no_trans:
4168 return ret; 4228 return ret;
@@ -4175,12 +4235,14 @@ end_no_trans:
4175 * data on disk. 4235 * data on disk.
4176 */ 4236 */
4177int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, 4237int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
4178 struct btrfs_root *root, struct dentry *dentry) 4238 struct btrfs_root *root, struct dentry *dentry,
4239 struct btrfs_log_ctx *ctx)
4179{ 4240{
4180 struct dentry *parent = dget_parent(dentry); 4241 struct dentry *parent = dget_parent(dentry);
4181 int ret; 4242 int ret;
4182 4243
4183 ret = btrfs_log_inode_parent(trans, root, dentry->d_inode, parent, 0); 4244 ret = btrfs_log_inode_parent(trans, root, dentry->d_inode, parent,
4245 0, ctx);
4184 dput(parent); 4246 dput(parent);
4185 4247
4186 return ret; 4248 return ret;
@@ -4417,6 +4479,6 @@ int btrfs_log_new_name(struct btrfs_trans_handle *trans,
4417 root->fs_info->last_trans_committed)) 4479 root->fs_info->last_trans_committed))
4418 return 0; 4480 return 0;
4419 4481
4420 return btrfs_log_inode_parent(trans, root, inode, parent, 1); 4482 return btrfs_log_inode_parent(trans, root, inode, parent, 1, NULL);
4421} 4483}
4422 4484