aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2012-09-20 03:54:00 -0400
committerChris Mason <chris.mason@fusionio.com>2012-10-09 09:15:39 -0400
commit354aa0fb6d5b97b262e056f7ad7bfc88d7ce0004 (patch)
tree3f10ebc7209b412a776250922449bb138c861e15
parenta698d0755adb6f27289d1e6610b2240595d27e8c (diff)
Btrfs: fix orphan transaction on the freezed filesystem
With the following debug patch: static int btrfs_freeze(struct super_block *sb) { + struct btrfs_fs_info *fs_info = btrfs_sb(sb); + struct btrfs_transaction *trans; + + spin_lock(&fs_info->trans_lock); + trans = fs_info->running_transaction; + if (trans) { + printk("Transid %llu, use_count %d, num_writer %d\n", + trans->transid, atomic_read(&trans->use_count), + atomic_read(&trans->num_writers)); + } + spin_unlock(&fs_info->trans_lock); return 0; } I found there was a orphan transaction after the freeze operation was done. It is because the transaction may not be committed when the transaction handle end even though it is the last handle of the current transaction. This design avoid committing the transaction frequently, but also introduce the above problem. So I add btrfs_attach_transaction() which can catch the current transaction and commit it. If there is no transaction, it will return ENOENT, and do not anything. This function also can be used to instead of btrfs_join_transaction_freeze() because it don't increase the writer counter and don't start a new transaction, so it also can fix the deadlock between sync and freeze. Besides that, it is used to instead of btrfs_join_transaction() in transaction_kthread(), because if there is no transaction, the transaction kthread needn't anything. Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
-rw-r--r--fs/btrfs/disk-io.c5
-rw-r--r--fs/btrfs/super.c18
-rw-r--r--fs/btrfs/transaction.c45
-rw-r--r--fs/btrfs/transaction.h4
4 files changed, 49 insertions, 23 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 2c18a4eb4d5..dcaf55695e6 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1657,9 +1657,10 @@ static int transaction_kthread(void *arg)
1657 spin_unlock(&root->fs_info->trans_lock); 1657 spin_unlock(&root->fs_info->trans_lock);
1658 1658
1659 /* If the file system is aborted, this will always fail. */ 1659 /* If the file system is aborted, this will always fail. */
1660 trans = btrfs_join_transaction(root); 1660 trans = btrfs_attach_transaction(root);
1661 if (IS_ERR(trans)) { 1661 if (IS_ERR(trans)) {
1662 cannot_commit = true; 1662 if (PTR_ERR(trans) != -ENOENT)
1663 cannot_commit = true;
1663 goto sleep; 1664 goto sleep;
1664 } 1665 }
1665 if (transid == trans->transid) { 1666 if (transid == trans->transid) {
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index fb260bbf59c..f8b803f30ed 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -854,10 +854,10 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
854 854
855 btrfs_wait_ordered_extents(root, 0); 855 btrfs_wait_ordered_extents(root, 0);
856 856
857 trans = btrfs_join_transaction_freeze(root); 857 trans = btrfs_attach_transaction(root);
858 if (IS_ERR(trans)) { 858 if (IS_ERR(trans)) {
859 /* Frozen, don't bother */ 859 /* no transaction, don't bother */
860 if (PTR_ERR(trans) == -EPERM) 860 if (PTR_ERR(trans) == -ENOENT)
861 return 0; 861 return 0;
862 return PTR_ERR(trans); 862 return PTR_ERR(trans);
863 } 863 }
@@ -1511,7 +1511,17 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
1511 1511
1512static int btrfs_freeze(struct super_block *sb) 1512static int btrfs_freeze(struct super_block *sb)
1513{ 1513{
1514 return 0; 1514 struct btrfs_trans_handle *trans;
1515 struct btrfs_root *root = btrfs_sb(sb)->tree_root;
1516
1517 trans = btrfs_attach_transaction(root);
1518 if (IS_ERR(trans)) {
1519 /* no transaction, don't bother */
1520 if (PTR_ERR(trans) == -ENOENT)
1521 return 0;
1522 return PTR_ERR(trans);
1523 }
1524 return btrfs_commit_transaction(trans, root);
1515} 1525}
1516 1526
1517static int btrfs_unfreeze(struct super_block *sb) 1527static int btrfs_unfreeze(struct super_block *sb)
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index d0a2b7e4938..69139a356f7 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -53,7 +53,7 @@ static noinline void switch_commit_root(struct btrfs_root *root)
53/* 53/*
54 * either allocate a new transaction or hop into the existing one 54 * either allocate a new transaction or hop into the existing one
55 */ 55 */
56static noinline int join_transaction(struct btrfs_root *root, int nofail) 56static noinline int join_transaction(struct btrfs_root *root, int type)
57{ 57{
58 struct btrfs_transaction *cur_trans; 58 struct btrfs_transaction *cur_trans;
59 struct btrfs_fs_info *fs_info = root->fs_info; 59 struct btrfs_fs_info *fs_info = root->fs_info;
@@ -67,7 +67,13 @@ loop:
67 } 67 }
68 68
69 if (fs_info->trans_no_join) { 69 if (fs_info->trans_no_join) {
70 if (!nofail) { 70 /*
71 * If we are JOIN_NOLOCK we're already committing a current
72 * transaction, we just need a handle to deal with something
73 * when committing the transaction, such as inode cache and
74 * space cache. It is a special case.
75 */
76 if (type != TRANS_JOIN_NOLOCK) {
71 spin_unlock(&fs_info->trans_lock); 77 spin_unlock(&fs_info->trans_lock);
72 return -EBUSY; 78 return -EBUSY;
73 } 79 }
@@ -87,6 +93,13 @@ loop:
87 } 93 }
88 spin_unlock(&fs_info->trans_lock); 94 spin_unlock(&fs_info->trans_lock);
89 95
96 /*
97 * If we are ATTACH, we just want to catch the current transaction,
98 * and commit it. If there is no transaction, just return ENOENT.
99 */
100 if (type == TRANS_ATTACH)
101 return -ENOENT;
102
90 cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, GFP_NOFS); 103 cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, GFP_NOFS);
91 if (!cur_trans) 104 if (!cur_trans)
92 return -ENOMEM; 105 return -ENOMEM;
@@ -340,27 +353,28 @@ again:
340 * because we're already holding a ref. We need this because we could 353 * because we're already holding a ref. We need this because we could
341 * have raced in and did an fsync() on a file which can kick a commit 354 * have raced in and did an fsync() on a file which can kick a commit
342 * and then we deadlock with somebody doing a freeze. 355 * and then we deadlock with somebody doing a freeze.
356 *
357 * If we are ATTACH, it means we just want to catch the current
358 * transaction and commit it, so we needn't do sb_start_intwrite().
343 */ 359 */
344 if (type != TRANS_JOIN_NOLOCK && 360 if (type < TRANS_JOIN_NOLOCK)
345 !__sb_start_write(root->fs_info->sb, SB_FREEZE_FS, false)) {
346 if (type == TRANS_JOIN_FREEZE) {
347 kmem_cache_free(btrfs_trans_handle_cachep, h);
348 return ERR_PTR(-EPERM);
349 }
350 sb_start_intwrite(root->fs_info->sb); 361 sb_start_intwrite(root->fs_info->sb);
351 }
352 362
353 if (may_wait_transaction(root, type)) 363 if (may_wait_transaction(root, type))
354 wait_current_trans(root); 364 wait_current_trans(root);
355 365
356 do { 366 do {
357 ret = join_transaction(root, type == TRANS_JOIN_NOLOCK); 367 ret = join_transaction(root, type);
358 if (ret == -EBUSY) 368 if (ret == -EBUSY)
359 wait_current_trans(root); 369 wait_current_trans(root);
360 } while (ret == -EBUSY); 370 } while (ret == -EBUSY);
361 371
362 if (ret < 0) { 372 if (ret < 0) {
363 sb_end_intwrite(root->fs_info->sb); 373 /* We must get the transaction if we are JOIN_NOLOCK. */
374 BUG_ON(type == TRANS_JOIN_NOLOCK);
375
376 if (type < TRANS_JOIN_NOLOCK)
377 sb_end_intwrite(root->fs_info->sb);
364 kmem_cache_free(btrfs_trans_handle_cachep, h); 378 kmem_cache_free(btrfs_trans_handle_cachep, h);
365 return ERR_PTR(ret); 379 return ERR_PTR(ret);
366 } 380 }
@@ -432,9 +446,9 @@ struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root
432 return start_transaction(root, 0, TRANS_USERSPACE, 0); 446 return start_transaction(root, 0, TRANS_USERSPACE, 0);
433} 447}
434 448
435struct btrfs_trans_handle *btrfs_join_transaction_freeze(struct btrfs_root *root) 449struct btrfs_trans_handle *btrfs_attach_transaction(struct btrfs_root *root)
436{ 450{
437 return start_transaction(root, 0, TRANS_JOIN_FREEZE, 0); 451 return start_transaction(root, 0, TRANS_ATTACH, 0);
438} 452}
439 453
440/* wait for a transaction commit to be fully complete */ 454/* wait for a transaction commit to be fully complete */
@@ -605,7 +619,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
605 } 619 }
606 } 620 }
607 621
608 if (lock) 622 if (trans->type < TRANS_JOIN_NOLOCK)
609 sb_end_intwrite(root->fs_info->sb); 623 sb_end_intwrite(root->fs_info->sb);
610 624
611 WARN_ON(cur_trans != info->running_transaction); 625 WARN_ON(cur_trans != info->running_transaction);
@@ -1678,7 +1692,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
1678 put_transaction(cur_trans); 1692 put_transaction(cur_trans);
1679 put_transaction(cur_trans); 1693 put_transaction(cur_trans);
1680 1694
1681 sb_end_intwrite(root->fs_info->sb); 1695 if (trans->type < TRANS_JOIN_NOLOCK)
1696 sb_end_intwrite(root->fs_info->sb);
1682 1697
1683 trace_btrfs_transaction_commit(root); 1698 trace_btrfs_transaction_commit(root);
1684 1699
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index 0630bd19396..80961947a6b 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -52,7 +52,7 @@ enum btrfs_trans_type {
52 TRANS_JOIN, 52 TRANS_JOIN,
53 TRANS_USERSPACE, 53 TRANS_USERSPACE,
54 TRANS_JOIN_NOLOCK, 54 TRANS_JOIN_NOLOCK,
55 TRANS_JOIN_FREEZE, 55 TRANS_ATTACH,
56}; 56};
57 57
58struct btrfs_trans_handle { 58struct btrfs_trans_handle {
@@ -109,7 +109,7 @@ struct btrfs_trans_handle *btrfs_start_transaction_noflush(
109 struct btrfs_root *root, int num_items); 109 struct btrfs_root *root, int num_items);
110struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root); 110struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root);
111struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root); 111struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root);
112struct btrfs_trans_handle *btrfs_join_transaction_freeze(struct btrfs_root *root); 112struct btrfs_trans_handle *btrfs_attach_transaction(struct btrfs_root *root);
113struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root); 113struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root);
114int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid); 114int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid);
115int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, 115int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,