Btrfs: avoid tree log commit when there are no changes
[linux-2.6-block.git] / fs / btrfs / transaction.c
index 915077725fea24b354de493e21d8dafabf7a1e87..0b8f36d4400a70919d055cac8b467b7a0f9c24d7 100644 (file)
@@ -104,7 +104,6 @@ static noinline int record_root_in_trans(struct btrfs_trans_handle *trans,
 {
        if (root->ref_cows && root->last_trans < trans->transid) {
                WARN_ON(root == root->fs_info->extent_root);
-               WARN_ON(root->root_item.refs == 0);
                WARN_ON(root->commit_root != root->node);
 
                radix_tree_tag_set(&root->fs_info->fs_roots_radix,
@@ -187,6 +186,9 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
        h->alloc_exclude_start = 0;
        h->delayed_ref_updates = 0;
 
+       if (!current->journal_info)
+               current->journal_info = h;
+
        root->fs_info->running_transaction->use_count++;
        record_root_in_trans(h, root);
        mutex_unlock(&root->fs_info->trans_mutex);
@@ -318,6 +320,9 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
                wake_up(&cur_trans->writer_wait);
        put_transaction(cur_trans);
        mutex_unlock(&info->trans_mutex);
+
+       if (current->journal_info == trans)
+               current->journal_info = NULL;
        memset(trans, 0, sizeof(*trans));
        kmem_cache_free(btrfs_trans_handle_cachep, trans);
 
@@ -744,6 +749,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        memcpy(&pending->root_key, &key, sizeof(key));
 fail:
        kfree(new_root_item);
+       btrfs_unreserve_metadata_space(root, 6);
        return ret;
 }
 
@@ -1060,6 +1066,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
        mutex_unlock(&root->fs_info->trans_mutex);
 
+       if (current->journal_info == trans)
+               current->journal_info = NULL;
+
        kmem_cache_free(btrfs_trans_handle_cachep, trans);
        return ret;
 }
@@ -1078,8 +1087,13 @@ int btrfs_clean_old_snapshots(struct btrfs_root *root)
 
        while (!list_empty(&list)) {
                root = list_entry(list.next, struct btrfs_root, root_list);
-               list_del_init(&root->root_list);
-               btrfs_drop_snapshot(root, 0);
+               list_del(&root->root_list);
+
+               if (btrfs_header_backref_rev(root->node) <
+                   BTRFS_MIXED_BACKREF_REV)
+                       btrfs_drop_snapshot(root, 0);
+               else
+                       btrfs_drop_snapshot(root, 1);
        }
        return 0;
 }