aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2013-02-20 04:17:06 -0500
committerJosef Bacik <jbacik@fusionio.com>2013-02-20 13:00:05 -0500
commitd4edf39bd5db443151efc993dac67ec9d6b5b8c1 (patch)
treed4f8e5df30152d5bb166918ba4e24aaff789812f
parent178260b2c14969f29ba39a78df74ed485abc6203 (diff)
Btrfs: fix uncompleted transaction
In some cases, we need commit the current transaction, but don't want to start a new one if there is no running transaction, so we introduce the function - btrfs_attach_transaction(), which can catch the current transaction, and return -ENOENT if there is no running transaction. But no running transaction doesn't mean the current transction completely, because we removed the running transaction before it completes. In some cases, it doesn't matter. But in some special cases, such as freeze fs, we hope the transaction is fully on disk, it will introduce some bugs, for example, we may feeze the fs and dump the data in the disk, if the transction doesn't complete, we would dump inconsistent data. So we need fix the above problem for those cases. We fixes this problem by introducing a function: btrfs_attach_transaction_barrier() if we hope all the transaction is fully on the disk, even they are not running, we can use this function. Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Josef Bacik <jbacik@fusionio.com>
-rw-r--r--fs/btrfs/ioctl.c2
-rw-r--r--fs/btrfs/super.c4
-rw-r--r--fs/btrfs/transaction.c32
-rw-r--r--fs/btrfs/transaction.h2
4 files changed, 37 insertions, 3 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 0f68729f261e..e0893036da08 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -3114,7 +3114,7 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,
3114 u64 transid; 3114 u64 transid;
3115 int ret; 3115 int ret;
3116 3116
3117 trans = btrfs_attach_transaction(root); 3117 trans = btrfs_attach_transaction_barrier(root);
3118 if (IS_ERR(trans)) { 3118 if (IS_ERR(trans)) {
3119 if (PTR_ERR(trans) != -ENOENT) 3119 if (PTR_ERR(trans) != -ENOENT)
3120 return PTR_ERR(trans); 3120 return PTR_ERR(trans);
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index e0ea1278377a..db1ba9a2ed64 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -878,7 +878,7 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
878 878
879 btrfs_wait_ordered_extents(root, 0); 879 btrfs_wait_ordered_extents(root, 0);
880 880
881 trans = btrfs_attach_transaction(root); 881 trans = btrfs_attach_transaction_barrier(root);
882 if (IS_ERR(trans)) { 882 if (IS_ERR(trans)) {
883 /* no transaction, don't bother */ 883 /* no transaction, don't bother */
884 if (PTR_ERR(trans) == -ENOENT) 884 if (PTR_ERR(trans) == -ENOENT)
@@ -1563,7 +1563,7 @@ static int btrfs_freeze(struct super_block *sb)
1563 struct btrfs_trans_handle *trans; 1563 struct btrfs_trans_handle *trans;
1564 struct btrfs_root *root = btrfs_sb(sb)->tree_root; 1564 struct btrfs_root *root = btrfs_sb(sb)->tree_root;
1565 1565
1566 trans = btrfs_attach_transaction(root); 1566 trans = btrfs_attach_transaction_barrier(root);
1567 if (IS_ERR(trans)) { 1567 if (IS_ERR(trans)) {
1568 /* no transaction, don't bother */ 1568 /* no transaction, don't bother */
1569 if (PTR_ERR(trans) == -ENOENT) 1569 if (PTR_ERR(trans) == -ENOENT)
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 5767ea1c0150..c1ce664c0c39 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -469,11 +469,43 @@ struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root
469 return start_transaction(root, 0, TRANS_USERSPACE, 0); 469 return start_transaction(root, 0, TRANS_USERSPACE, 0);
470} 470}
471 471
472/*
473 * btrfs_attach_transaction() - catch the running transaction
474 *
475 * It is used when we want to commit the current the transaction, but
476 * don't want to start a new one.
477 *
478 * Note: If this function return -ENOENT, it just means there is no
479 * running transaction. But it is possible that the inactive transaction
480 * is still in the memory, not fully on disk. If you hope there is no
481 * inactive transaction in the fs when -ENOENT is returned, you should
482 * invoke
483 * btrfs_attach_transaction_barrier()
484 */
472struct btrfs_trans_handle *btrfs_attach_transaction(struct btrfs_root *root) 485struct btrfs_trans_handle *btrfs_attach_transaction(struct btrfs_root *root)
473{ 486{
474 return start_transaction(root, 0, TRANS_ATTACH, 0); 487 return start_transaction(root, 0, TRANS_ATTACH, 0);
475} 488}
476 489
490/*
491 * btrfs_attach_transaction() - catch the running transaction
492 *
493 * It is similar to the above function, the differentia is this one
494 * will wait for all the inactive transactions until they fully
495 * complete.
496 */
497struct btrfs_trans_handle *
498btrfs_attach_transaction_barrier(struct btrfs_root *root)
499{
500 struct btrfs_trans_handle *trans;
501
502 trans = start_transaction(root, 0, TRANS_ATTACH, 0);
503 if (IS_ERR(trans) && PTR_ERR(trans) == -ENOENT)
504 btrfs_wait_for_commit(root, 0);
505
506 return trans;
507}
508
477/* wait for a transaction commit to be fully complete */ 509/* wait for a transaction commit to be fully complete */
478static noinline void wait_for_commit(struct btrfs_root *root, 510static noinline void wait_for_commit(struct btrfs_root *root,
479 struct btrfs_transaction *commit) 511 struct btrfs_transaction *commit)
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index 3f772fd0191a..5afd7b1dceac 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -112,6 +112,8 @@ struct btrfs_trans_handle *btrfs_start_transaction_lflush(
112struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root); 112struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root);
113struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root); 113struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root);
114struct btrfs_trans_handle *btrfs_attach_transaction(struct btrfs_root *root); 114struct btrfs_trans_handle *btrfs_attach_transaction(struct btrfs_root *root);
115struct btrfs_trans_handle *btrfs_attach_transaction_barrier(
116 struct btrfs_root *root);
115struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root); 117struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root);
116int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid); 118int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid);
117int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, 119int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,