diff options
author | Miao Xie <miaox@cn.fujitsu.com> | 2012-09-20 03:54:00 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2012-10-09 09:15:39 -0400 |
commit | 354aa0fb6d5b97b262e056f7ad7bfc88d7ce0004 (patch) | |
tree | 3f10ebc7209b412a776250922449bb138c861e15 /fs/btrfs/super.c | |
parent | a698d0755adb6f27289d1e6610b2240595d27e8c (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.c | 18 |
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 | ||
1512 | static int btrfs_freeze(struct super_block *sb) | 1512 | static 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 | ||
1517 | static int btrfs_unfreeze(struct super_block *sb) | 1527 | static int btrfs_unfreeze(struct super_block *sb) |