Merge branch 'bug-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/josef/btrfs...
[pandora-kernel.git] / fs / btrfs / transaction.c
index 66e4c66..325d9a5 100644 (file)
@@ -163,6 +163,7 @@ enum btrfs_trans_type {
        TRANS_START,
        TRANS_JOIN,
        TRANS_USERSPACE,
+       TRANS_JOIN_NOLOCK,
 };
 
 static int may_wait_transaction(struct btrfs_root *root, int type)
@@ -179,14 +180,14 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
 {
        struct btrfs_trans_handle *h;
        struct btrfs_transaction *cur_trans;
-       int retries = 0;
        int ret;
 again:
        h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS);
        if (!h)
                return ERR_PTR(-ENOMEM);
 
-       mutex_lock(&root->fs_info->trans_mutex);
+       if (type != TRANS_JOIN_NOLOCK)
+               mutex_lock(&root->fs_info->trans_mutex);
        if (may_wait_transaction(root, type))
                wait_current_trans(root);
 
@@ -195,7 +196,8 @@ again:
 
        cur_trans = root->fs_info->running_transaction;
        cur_trans->use_count++;
-       mutex_unlock(&root->fs_info->trans_mutex);
+       if (type != TRANS_JOIN_NOLOCK)
+               mutex_unlock(&root->fs_info->trans_mutex);
 
        h->transid = cur_trans->transid;
        h->transaction = cur_trans;
@@ -212,8 +214,7 @@ again:
        }
 
        if (num_items > 0) {
-               ret = btrfs_trans_reserve_metadata(h, root, num_items,
-                                                  &retries);
+               ret = btrfs_trans_reserve_metadata(h, root, num_items);
                if (ret == -EAGAIN) {
                        btrfs_commit_transaction(h, root);
                        goto again;
@@ -224,9 +225,11 @@ again:
                }
        }
 
-       mutex_lock(&root->fs_info->trans_mutex);
+       if (type != TRANS_JOIN_NOLOCK)
+               mutex_lock(&root->fs_info->trans_mutex);
        record_root_in_trans(h, root);
-       mutex_unlock(&root->fs_info->trans_mutex);
+       if (type != TRANS_JOIN_NOLOCK)
+               mutex_unlock(&root->fs_info->trans_mutex);
 
        if (!current->journal_info && type != TRANS_USERSPACE)
                current->journal_info = h;
@@ -244,6 +247,12 @@ struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root,
        return start_transaction(root, 0, TRANS_JOIN);
 }
 
+struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root,
+                                                         int num_blocks)
+{
+       return start_transaction(root, 0, TRANS_JOIN_NOLOCK);
+}
+
 struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *r,
                                                         int num_blocks)
 {
@@ -348,7 +357,7 @@ int btrfs_should_end_transaction(struct btrfs_trans_handle *trans,
 }
 
 static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
-                         struct btrfs_root *root, int throttle)
+                         struct btrfs_root *root, int throttle, int lock)
 {
        struct btrfs_transaction *cur_trans = trans->transaction;
        struct btrfs_fs_info *info = root->fs_info;
@@ -376,18 +385,19 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
 
        btrfs_trans_release_metadata(trans, root);
 
-       if (!root->fs_info->open_ioctl_trans &&
+       if (lock && !root->fs_info->open_ioctl_trans &&
            should_end_transaction(trans, root))
                trans->transaction->blocked = 1;
 
-       if (cur_trans->blocked && !cur_trans->in_commit) {
+       if (lock && cur_trans->blocked && !cur_trans->in_commit) {
                if (throttle)
                        return btrfs_commit_transaction(trans, root);
                else
                        wake_up_process(info->transaction_kthread);
        }
 
-       mutex_lock(&info->trans_mutex);
+       if (lock)
+               mutex_lock(&info->trans_mutex);
        WARN_ON(cur_trans != info->running_transaction);
        WARN_ON(cur_trans->num_writers < 1);
        cur_trans->num_writers--;
@@ -395,7 +405,8 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
        if (waitqueue_active(&cur_trans->writer_wait))
                wake_up(&cur_trans->writer_wait);
        put_transaction(cur_trans);
-       mutex_unlock(&info->trans_mutex);
+       if (lock)
+               mutex_unlock(&info->trans_mutex);
 
        if (current->journal_info == trans)
                current->journal_info = NULL;
@@ -411,13 +422,19 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
 int btrfs_end_transaction(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root)
 {
-       return __btrfs_end_transaction(trans, root, 0);
+       return __btrfs_end_transaction(trans, root, 0, 1);
 }
 
 int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root)
 {
-       return __btrfs_end_transaction(trans, root, 1);
+       return __btrfs_end_transaction(trans, root, 1, 1);
+}
+
+int btrfs_end_transaction_nolock(struct btrfs_trans_handle *trans,
+                                struct btrfs_root *root)
+{
+       return __btrfs_end_transaction(trans, root, 0, 0);
 }
 
 /*
@@ -836,7 +853,6 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        struct extent_buffer *tmp;
        struct extent_buffer *old;
        int ret;
-       int retries = 0;
        u64 to_reserve = 0;
        u64 index = 0;
        u64 objectid;
@@ -858,7 +874,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
 
        if (to_reserve > 0) {
                ret = btrfs_block_rsv_add(trans, root, &pending->block_rsv,
-                                         to_reserve, &retries);
+                                         to_reserve);
                if (ret) {
                        pending->error = ret;
                        goto fail;
@@ -966,6 +982,8 @@ static void update_super_roots(struct btrfs_root *root)
        super->root = root_item->bytenr;
        super->generation = root_item->generation;
        super->root_level = root_item->level;
+       if (super->cache_generation != 0 || btrfs_test_opt(root, SPACE_CACHE))
+               super->cache_generation = root_item->generation;
 }
 
 int btrfs_transaction_in_commit(struct btrfs_fs_info *info)