Btrfs: still corruption hunting
[linux-2.6-block.git] / fs / btrfs / transaction.c
index 84c4e278ce2e051b00a0b76f3acc3f564c7e1ac6..72b52e1e0b1bce73ce88295c5648264490440648 100644 (file)
@@ -5,13 +5,20 @@
 #include "transaction.h"
 
 static int total_trans = 0;
+extern struct kmem_cache *btrfs_trans_handle_cachep;
+extern struct kmem_cache *btrfs_transaction_cachep;
+
+#define TRANS_MAGIC 0xE1E10E
 static void put_transaction(struct btrfs_transaction *transaction)
 {
+       WARN_ON(transaction->use_count == 0);
        transaction->use_count--;
+       WARN_ON(transaction->magic != TRANS_MAGIC);
        if (transaction->use_count == 0) {
                WARN_ON(total_trans == 0);
                total_trans--;
-               kfree(transaction);
+               memset(transaction, 0, sizeof(*transaction));
+               kmem_cache_free(btrfs_transaction_cachep, transaction);
        }
 }
 
@@ -20,7 +27,8 @@ static int join_transaction(struct btrfs_root *root)
        struct btrfs_transaction *cur_trans;
        cur_trans = root->fs_info->running_transaction;
        if (!cur_trans) {
-               cur_trans = kmalloc(sizeof(*cur_trans), GFP_NOFS);
+               cur_trans = kmem_cache_alloc(btrfs_transaction_cachep,
+                                            GFP_NOFS);
                total_trans++;
                BUG_ON(!cur_trans);
                root->fs_info->running_transaction = cur_trans;
@@ -28,6 +36,7 @@ static int join_transaction(struct btrfs_root *root)
                cur_trans->transid = root->root_key.offset + 1;
                init_waitqueue_head(&cur_trans->writer_wait);
                init_waitqueue_head(&cur_trans->commit_wait);
+               cur_trans->magic = TRANS_MAGIC;
                cur_trans->in_commit = 0;
                cur_trans->use_count = 1;
                cur_trans->commit_done = 0;
@@ -39,7 +48,8 @@ static int join_transaction(struct btrfs_root *root)
 struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
                                                   int num_blocks)
 {
-       struct btrfs_trans_handle *h = kmalloc(sizeof(*h), GFP_NOFS);
+       struct btrfs_trans_handle *h =
+               kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS);
        int ret;
 
        mutex_lock(&root->fs_info->trans_mutex);
@@ -51,6 +61,7 @@ struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
        h->blocks_used = 0;
        root->fs_info->running_transaction->use_count++;
        mutex_unlock(&root->fs_info->trans_mutex);
+       h->magic = h->magic2 = TRANS_MAGIC;
        return h;
 }
 
@@ -58,6 +69,8 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root)
 {
        struct btrfs_transaction *cur_trans;
+       WARN_ON(trans->magic != TRANS_MAGIC);
+       WARN_ON(trans->magic2 != TRANS_MAGIC);
        mutex_lock(&root->fs_info->trans_mutex);
        cur_trans = root->fs_info->running_transaction;
        WARN_ON(cur_trans->num_writers < 1);
@@ -67,7 +80,7 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans,
        put_transaction(cur_trans);
        mutex_unlock(&root->fs_info->trans_mutex);
        memset(trans, 0, sizeof(*trans));
-       kfree(trans);
+       kmem_cache_free(btrfs_trans_handle_cachep, trans);
        return 0;
 }
 
@@ -75,7 +88,7 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans,
 int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
                                     struct btrfs_root *root)
 {
-       filemap_write_and_wait(root->fs_info->btree_inode->i_mapping);
+       filemap_write_and_wait(root->fs_info->sb->s_bdev->bd_inode->i_mapping);
        return 0;
 }
 
@@ -137,6 +150,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
        mutex_lock(&root->fs_info->trans_mutex);
        if (trans->transaction->in_commit) {
+printk("already in commit!, waiting\n");
                cur_trans = trans->transaction;
                trans->transaction->use_count++;
                btrfs_end_transaction(trans, root);
@@ -146,7 +160,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                mutex_unlock(&root->fs_info->trans_mutex);
                return 0;
        }
+       cur_trans = trans->transaction;
+       trans->transaction->in_commit = 1;
        while (trans->transaction->num_writers > 1) {
+               WARN_ON(cur_trans != trans->transaction);
                prepare_to_wait(&trans->transaction->writer_wait, &wait,
                                TASK_UNINTERRUPTIBLE);
                if (trans->transaction->num_writers <= 1)
@@ -154,15 +171,15 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                mutex_unlock(&root->fs_info->trans_mutex);
                schedule();
                mutex_lock(&root->fs_info->trans_mutex);
+               finish_wait(&trans->transaction->writer_wait, &wait);
        }
        finish_wait(&trans->transaction->writer_wait, &wait);
-
+       WARN_ON(cur_trans != trans->transaction);
        if (root->node != root->commit_root) {
                memcpy(&snap_key, &root->root_key, sizeof(snap_key));
                root->root_key.offset++;
        }
 
-
        if (btrfs_root_blocknr(&root->root_item) != root->node->b_blocknr) {
                btrfs_set_root_blocknr(&root->root_item, root->node->b_blocknr);
                ret = btrfs_insert_root(trans, root->fs_info->tree_root,
@@ -172,22 +189,21 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
        ret = btrfs_commit_tree_roots(trans, root);
        BUG_ON(ret);
-
        cur_trans = root->fs_info->running_transaction;
        root->fs_info->running_transaction = NULL;
        mutex_unlock(&root->fs_info->trans_mutex);
-
        ret = btrfs_write_and_wait_transaction(trans, root);
        BUG_ON(ret);
 
        write_ctree_super(trans, root);
        btrfs_finish_extent_commit(trans, root);
        mutex_lock(&root->fs_info->trans_mutex);
+       cur_trans->commit_done = 1;
+       wake_up(&cur_trans->commit_wait);
        put_transaction(cur_trans);
        put_transaction(cur_trans);
        mutex_unlock(&root->fs_info->trans_mutex);
-       kfree(trans);
-
+       kmem_cache_free(btrfs_trans_handle_cachep, trans);
        if (root->node != root->commit_root) {
                trans = btrfs_start_transaction(root, 1);
                snap = root->commit_root;
@@ -203,7 +219,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                ret = btrfs_end_transaction(trans, root);
                BUG_ON(ret);
        }
-
        return ret;
 }