aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/disk-io.c
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2011-04-11 17:25:13 -0400
committerJosef Bacik <josef@redhat.com>2011-05-23 13:00:57 -0400
commita4abeea41adfa3c143c289045f4625dfaeba2212 (patch)
tree792e2a398d8ba77447ba3f9f2c4266a1ce2f611c /fs/btrfs/disk-io.c
parent2a1eb4614d984d5cd4c928784e9afcf5c07f93be (diff)
Btrfs: kill trans_mutex
We use trans_mutex for lots of things, here's a basic list 1) To serialize trans_handles joining the currently running transaction 2) To make sure that no new trans handles are started while we are committing 3) To protect the dead_roots list and the transaction lists Really the serializing trans_handles joining is not too hard, and can really get bogged down in acquiring a reference to the transaction. So replace the trans_mutex with a trans_lock spinlock and use it to do the following 1) Protect fs_info->running_transaction. All trans handles have to do is check this, and then take a reference of the transaction and keep on going. 2) Protect the fs_info->trans_list. This doesn't get used too much, basically it just holds the current transactions, which will usually just be the currently committing transaction and the currently running transaction at most. 3) Protect the dead roots list. This is only ever processed by splicing the list so this is relatively simple. 4) Protect the fs_info->reloc_ctl stuff. This is very lightweight and was using the trans_mutex before, so this is a pretty straightforward change. 5) Protect fs_info->no_trans_join. Because we don't hold the trans_lock over the entirety of the commit we need to have a way to block new people from creating a new transaction while we're doing our work. So we set no_trans_join and in join_transaction we test to see if that is set, and if it is we do a wait_on_commit. 6) Make the transaction use count atomic so we don't need to take locks to modify it when we're dropping references. 7) Add a commit_lock to the transaction to make sure multiple people trying to commit the same transaction don't race and commit at the same time. 8) Make open_ioctl_trans an atomic so we don't have to take any locks for ioctl trans. I have tested this with xfstests, but obviously it is a pretty hairy change so lots of testing is greatly appreciated. Thanks, Signed-off-by: Josef Bacik <josef@redhat.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r--fs/btrfs/disk-io.c30
1 files changed, 15 insertions, 15 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 9d6c9e332ca3..93ef254ec432 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1551,22 +1551,22 @@ static int transaction_kthread(void *arg)
1551 vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE); 1551 vfs_check_frozen(root->fs_info->sb, SB_FREEZE_WRITE);
1552 mutex_lock(&root->fs_info->transaction_kthread_mutex); 1552 mutex_lock(&root->fs_info->transaction_kthread_mutex);
1553 1553
1554 spin_lock(&root->fs_info->new_trans_lock); 1554 spin_lock(&root->fs_info->trans_lock);
1555 cur = root->fs_info->running_transaction; 1555 cur = root->fs_info->running_transaction;
1556 if (!cur) { 1556 if (!cur) {
1557 spin_unlock(&root->fs_info->new_trans_lock); 1557 spin_unlock(&root->fs_info->trans_lock);
1558 goto sleep; 1558 goto sleep;
1559 } 1559 }
1560 1560
1561 now = get_seconds(); 1561 now = get_seconds();
1562 if (!cur->blocked && 1562 if (!cur->blocked &&
1563 (now < cur->start_time || now - cur->start_time < 30)) { 1563 (now < cur->start_time || now - cur->start_time < 30)) {
1564 spin_unlock(&root->fs_info->new_trans_lock); 1564 spin_unlock(&root->fs_info->trans_lock);
1565 delay = HZ * 5; 1565 delay = HZ * 5;
1566 goto sleep; 1566 goto sleep;
1567 } 1567 }
1568 transid = cur->transid; 1568 transid = cur->transid;
1569 spin_unlock(&root->fs_info->new_trans_lock); 1569 spin_unlock(&root->fs_info->trans_lock);
1570 1570
1571 trans = btrfs_join_transaction(root); 1571 trans = btrfs_join_transaction(root);
1572 BUG_ON(IS_ERR(trans)); 1572 BUG_ON(IS_ERR(trans));
@@ -1658,7 +1658,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
1658 INIT_LIST_HEAD(&fs_info->ordered_operations); 1658 INIT_LIST_HEAD(&fs_info->ordered_operations);
1659 INIT_LIST_HEAD(&fs_info->caching_block_groups); 1659 INIT_LIST_HEAD(&fs_info->caching_block_groups);
1660 spin_lock_init(&fs_info->delalloc_lock); 1660 spin_lock_init(&fs_info->delalloc_lock);
1661 spin_lock_init(&fs_info->new_trans_lock); 1661 spin_lock_init(&fs_info->trans_lock);
1662 spin_lock_init(&fs_info->ref_cache_lock); 1662 spin_lock_init(&fs_info->ref_cache_lock);
1663 spin_lock_init(&fs_info->fs_roots_radix_lock); 1663 spin_lock_init(&fs_info->fs_roots_radix_lock);
1664 spin_lock_init(&fs_info->delayed_iput_lock); 1664 spin_lock_init(&fs_info->delayed_iput_lock);
@@ -1687,6 +1687,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
1687 fs_info->sb = sb; 1687 fs_info->sb = sb;
1688 fs_info->max_inline = 8192 * 1024; 1688 fs_info->max_inline = 8192 * 1024;
1689 fs_info->metadata_ratio = 0; 1689 fs_info->metadata_ratio = 0;
1690 fs_info->trans_no_join = 0;
1690 1691
1691 fs_info->thread_pool_size = min_t(unsigned long, 1692 fs_info->thread_pool_size = min_t(unsigned long,
1692 num_online_cpus() + 2, 8); 1693 num_online_cpus() + 2, 8);
@@ -1735,7 +1736,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,
1735 fs_info->do_barriers = 1; 1736 fs_info->do_barriers = 1;
1736 1737
1737 1738
1738 mutex_init(&fs_info->trans_mutex);
1739 mutex_init(&fs_info->ordered_operations_mutex); 1739 mutex_init(&fs_info->ordered_operations_mutex);
1740 mutex_init(&fs_info->tree_log_mutex); 1740 mutex_init(&fs_info->tree_log_mutex);
1741 mutex_init(&fs_info->chunk_mutex); 1741 mutex_init(&fs_info->chunk_mutex);
@@ -3006,10 +3006,13 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root)
3006 3006
3007 WARN_ON(1); 3007 WARN_ON(1);
3008 3008
3009 mutex_lock(&root->fs_info->trans_mutex);
3010 mutex_lock(&root->fs_info->transaction_kthread_mutex); 3009 mutex_lock(&root->fs_info->transaction_kthread_mutex);
3011 3010
3011 spin_lock(&root->fs_info->trans_lock);
3012 list_splice_init(&root->fs_info->trans_list, &list); 3012 list_splice_init(&root->fs_info->trans_list, &list);
3013 root->fs_info->trans_no_join = 1;
3014 spin_unlock(&root->fs_info->trans_lock);
3015
3013 while (!list_empty(&list)) { 3016 while (!list_empty(&list)) {
3014 t = list_entry(list.next, struct btrfs_transaction, list); 3017 t = list_entry(list.next, struct btrfs_transaction, list);
3015 if (!t) 3018 if (!t)
@@ -3034,23 +3037,18 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root)
3034 t->blocked = 0; 3037 t->blocked = 0;
3035 if (waitqueue_active(&root->fs_info->transaction_wait)) 3038 if (waitqueue_active(&root->fs_info->transaction_wait))
3036 wake_up(&root->fs_info->transaction_wait); 3039 wake_up(&root->fs_info->transaction_wait);
3037 mutex_unlock(&root->fs_info->trans_mutex);
3038 3040
3039 mutex_lock(&root->fs_info->trans_mutex);
3040 t->commit_done = 1; 3041 t->commit_done = 1;
3041 if (waitqueue_active(&t->commit_wait)) 3042 if (waitqueue_active(&t->commit_wait))
3042 wake_up(&t->commit_wait); 3043 wake_up(&t->commit_wait);
3043 mutex_unlock(&root->fs_info->trans_mutex);
3044
3045 mutex_lock(&root->fs_info->trans_mutex);
3046 3044
3047 btrfs_destroy_pending_snapshots(t); 3045 btrfs_destroy_pending_snapshots(t);
3048 3046
3049 btrfs_destroy_delalloc_inodes(root); 3047 btrfs_destroy_delalloc_inodes(root);
3050 3048
3051 spin_lock(&root->fs_info->new_trans_lock); 3049 spin_lock(&root->fs_info->trans_lock);
3052 root->fs_info->running_transaction = NULL; 3050 root->fs_info->running_transaction = NULL;
3053 spin_unlock(&root->fs_info->new_trans_lock); 3051 spin_unlock(&root->fs_info->trans_lock);
3054 3052
3055 btrfs_destroy_marked_extents(root, &t->dirty_pages, 3053 btrfs_destroy_marked_extents(root, &t->dirty_pages,
3056 EXTENT_DIRTY); 3054 EXTENT_DIRTY);
@@ -3064,8 +3062,10 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root)
3064 kmem_cache_free(btrfs_transaction_cachep, t); 3062 kmem_cache_free(btrfs_transaction_cachep, t);
3065 } 3063 }
3066 3064
3065 spin_lock(&root->fs_info->trans_lock);
3066 root->fs_info->trans_no_join = 0;
3067 spin_unlock(&root->fs_info->trans_lock);
3067 mutex_unlock(&root->fs_info->transaction_kthread_mutex); 3068 mutex_unlock(&root->fs_info->transaction_kthread_mutex);
3068 mutex_unlock(&root->fs_info->trans_mutex);
3069 3069
3070 return 0; 3070 return 0;
3071} 3071}