Btrfs: Add a per-inode csum mutex to avoid races creating csum items
[safe/jmp/linux-2.6] / fs / btrfs / ordered-data.c
index 411aba8..254da82 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/gfp.h>
 #include <linux/slab.h>
+#include <linux/blkdev.h>
 #include "ctree.h"
 #include "transaction.h"
 #include "btrfs_inode.h"
@@ -25,6 +26,7 @@
 struct tree_entry {
        u64 root_objectid;
        u64 objectid;
+       struct inode *inode;
        struct rb_node rb_node;
 };
 
@@ -144,20 +146,25 @@ int btrfs_add_ordered_inode(struct inode *inode)
        write_lock(&tree->lock);
        entry->objectid = inode->i_ino;
        entry->root_objectid = root_objectid;
+       entry->inode = inode;
 
        node = tree_insert(&tree->tree, root_objectid,
                           inode->i_ino, &entry->rb_node);
 
        BTRFS_I(inode)->ordered_trans = transid;
+       if (!node)
+               igrab(inode);
 
        write_unlock(&tree->lock);
+
        if (node)
                kfree(entry);
        return 0;
 }
 
 int btrfs_find_first_ordered_inode(struct btrfs_ordered_inode_tree *tree,
-                                      u64 *root_objectid, u64 *objectid)
+                                  u64 *root_objectid, u64 *objectid,
+                                  struct inode **inode)
 {
        struct tree_entry *entry;
        struct rb_node *node;
@@ -182,13 +189,16 @@ int btrfs_find_first_ordered_inode(struct btrfs_ordered_inode_tree *tree,
        }
 
        *root_objectid = entry->root_objectid;
+       *inode = entry->inode;
+       atomic_inc(&entry->inode->i_count);
        *objectid = entry->objectid;
        write_unlock(&tree->lock);
        return 1;
 }
 
 int btrfs_find_del_first_ordered_inode(struct btrfs_ordered_inode_tree *tree,
-                                      u64 *root_objectid, u64 *objectid)
+                                      u64 *root_objectid, u64 *objectid,
+                                      struct inode **inode)
 {
        struct tree_entry *entry;
        struct rb_node *node;
@@ -214,8 +224,70 @@ int btrfs_find_del_first_ordered_inode(struct btrfs_ordered_inode_tree *tree,
 
        *root_objectid = entry->root_objectid;
        *objectid = entry->objectid;
+       *inode = entry->inode;
+       atomic_inc(&entry->inode->i_count);
        rb_erase(node, &tree->tree);
        write_unlock(&tree->lock);
        kfree(entry);
        return 1;
 }
+
+static void __btrfs_del_ordered_inode(struct btrfs_ordered_inode_tree *tree,
+                                    struct inode *inode,
+                                    u64 root_objectid, u64 objectid)
+{
+       struct tree_entry *entry;
+       struct rb_node *node;
+       struct rb_node *prev;
+
+       write_lock(&tree->lock);
+       node = __tree_search(&tree->tree, root_objectid, objectid, &prev);
+       if (!node) {
+               write_unlock(&tree->lock);
+               return;
+       }
+       rb_erase(node, &tree->tree);
+       BTRFS_I(inode)->ordered_trans = 0;
+       write_unlock(&tree->lock);
+       atomic_dec(&inode->i_count);
+       entry = rb_entry(node, struct tree_entry, rb_node);
+       kfree(entry);
+       return;
+}
+
+void btrfs_del_ordered_inode(struct inode *inode, int force)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       u64 root_objectid = root->root_key.objectid;
+
+       if (!BTRFS_I(inode)->ordered_trans) {
+               return;
+       }
+
+       if (!force && (mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY) ||
+           mapping_tagged(inode->i_mapping, PAGECACHE_TAG_WRITEBACK)))
+               return;
+
+       spin_lock(&root->fs_info->new_trans_lock);
+       if (root->fs_info->running_transaction) {
+               struct btrfs_ordered_inode_tree *tree;
+               tree = &root->fs_info->running_transaction->ordered_inode_tree;
+                __btrfs_del_ordered_inode(tree, inode, root_objectid,
+                                               inode->i_ino);
+       }
+       spin_unlock(&root->fs_info->new_trans_lock);
+}
+
+int btrfs_ordered_throttle(struct btrfs_root *root, struct inode *inode)
+{
+       struct btrfs_transaction *cur = root->fs_info->running_transaction;
+       while(cur == root->fs_info->running_transaction &&
+             atomic_read(&BTRFS_I(inode)->ordered_writeback)) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
+               congestion_wait(WRITE, HZ/20);
+#else
+               blk_congestion_wait(WRITE, HZ/20);
+#endif
+       }
+       return 0;
+}