aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/disk-io.c2
-rw-r--r--fs/btrfs/file.c9
-rw-r--r--fs/btrfs/tree-log.c114
-rw-r--r--fs/btrfs/tree-log.h16
5 files changed, 111 insertions, 31 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 70c03f5f0953..906410719acb 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1718,6 +1718,7 @@ struct btrfs_root {
1718 struct mutex log_mutex; 1718 struct mutex log_mutex;
1719 wait_queue_head_t log_writer_wait; 1719 wait_queue_head_t log_writer_wait;
1720 wait_queue_head_t log_commit_wait[2]; 1720 wait_queue_head_t log_commit_wait[2];
1721 struct list_head log_ctxs[2];
1721 atomic_t log_writers; 1722 atomic_t log_writers;
1722 atomic_t log_commit[2]; 1723 atomic_t log_commit[2];
1723 atomic_t log_batch; 1724 atomic_t log_batch;
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index cc1b4237dc62..44f52d280b7d 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1200,6 +1200,8 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
1200 init_waitqueue_head(&root->log_writer_wait); 1200 init_waitqueue_head(&root->log_writer_wait);
1201 init_waitqueue_head(&root->log_commit_wait[0]); 1201 init_waitqueue_head(&root->log_commit_wait[0]);
1202 init_waitqueue_head(&root->log_commit_wait[1]); 1202 init_waitqueue_head(&root->log_commit_wait[1]);
1203 INIT_LIST_HEAD(&root->log_ctxs[0]);
1204 INIT_LIST_HEAD(&root->log_ctxs[1]);
1203 atomic_set(&root->log_commit[0], 0); 1205 atomic_set(&root->log_commit[0], 0);
1204 atomic_set(&root->log_commit[1], 0); 1206 atomic_set(&root->log_commit[1], 0);
1205 atomic_set(&root->log_writers, 0); 1207 atomic_set(&root->log_writers, 0);
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 006af2f4dd98..6acccc4a7f2a 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1864,8 +1864,9 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
1864 struct dentry *dentry = file->f_path.dentry; 1864 struct dentry *dentry = file->f_path.dentry;
1865 struct inode *inode = dentry->d_inode; 1865 struct inode *inode = dentry->d_inode;
1866 struct btrfs_root *root = BTRFS_I(inode)->root; 1866 struct btrfs_root *root = BTRFS_I(inode)->root;
1867 int ret = 0;
1868 struct btrfs_trans_handle *trans; 1867 struct btrfs_trans_handle *trans;
1868 struct btrfs_log_ctx ctx;
1869 int ret = 0;
1869 bool full_sync = 0; 1870 bool full_sync = 0;
1870 1871
1871 trace_btrfs_sync_file(file, datasync); 1872 trace_btrfs_sync_file(file, datasync);
@@ -1959,7 +1960,9 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
1959 } 1960 }
1960 trans->sync = true; 1961 trans->sync = true;
1961 1962
1962 ret = btrfs_log_dentry_safe(trans, root, dentry); 1963 btrfs_init_log_ctx(&ctx);
1964
1965 ret = btrfs_log_dentry_safe(trans, root, dentry, &ctx);
1963 if (ret < 0) { 1966 if (ret < 0) {
1964 /* Fallthrough and commit/free transaction. */ 1967 /* Fallthrough and commit/free transaction. */
1965 ret = 1; 1968 ret = 1;
@@ -1979,7 +1982,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
1979 1982
1980 if (ret != BTRFS_NO_LOG_SYNC) { 1983 if (ret != BTRFS_NO_LOG_SYNC) {
1981 if (!ret) { 1984 if (!ret) {
1982 ret = btrfs_sync_log(trans, root); 1985 ret = btrfs_sync_log(trans, root, &ctx);
1983 if (!ret) { 1986 if (!ret) {
1984 ret = btrfs_end_transaction(trans, root); 1987 ret = btrfs_end_transaction(trans, root);
1985 goto out; 1988 goto out;
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
diff --git a/fs/btrfs/tree-log.h b/fs/btrfs/tree-log.h
index 1d4ae0d15a70..59c1edb31d19 100644
--- a/fs/btrfs/tree-log.h
+++ b/fs/btrfs/tree-log.h
@@ -22,14 +22,26 @@
22/* return value for btrfs_log_dentry_safe that means we don't need to log it at all */ 22/* return value for btrfs_log_dentry_safe that means we don't need to log it at all */
23#define BTRFS_NO_LOG_SYNC 256 23#define BTRFS_NO_LOG_SYNC 256
24 24
25struct btrfs_log_ctx {
26 int log_ret;
27 struct list_head list;
28};
29
30static inline void btrfs_init_log_ctx(struct btrfs_log_ctx *ctx)
31{
32 ctx->log_ret = 0;
33 INIT_LIST_HEAD(&ctx->list);
34}
35
25int btrfs_sync_log(struct btrfs_trans_handle *trans, 36int btrfs_sync_log(struct btrfs_trans_handle *trans,
26 struct btrfs_root *root); 37 struct btrfs_root *root, struct btrfs_log_ctx *ctx);
27int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root); 38int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root);
28int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans, 39int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
29 struct btrfs_fs_info *fs_info); 40 struct btrfs_fs_info *fs_info);
30int btrfs_recover_log_trees(struct btrfs_root *tree_root); 41int btrfs_recover_log_trees(struct btrfs_root *tree_root);
31int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, 42int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans,
32 struct btrfs_root *root, struct dentry *dentry); 43 struct btrfs_root *root, struct dentry *dentry,
44 struct btrfs_log_ctx *ctx);
33int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, 45int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
34 struct btrfs_root *root, 46 struct btrfs_root *root,
35 const char *name, int name_len, 47 const char *name, int name_len,