aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/super.c
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 /fs/btrfs/super.c
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>
Diffstat (limited to 'fs/btrfs/super.c')
-rw-r--r--fs/btrfs/super.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index fb260bbf59c6..f8b803f30ed8 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)