Btrfs: Run igrab on data=ordered inodes to prevent deadlocks during writeout
authorChris Mason <chris.mason@oracle.com>
Wed, 16 Jan 2008 16:44:43 +0000 (11:44 -0500)
committerChris Mason <chris.mason@oracle.com>
Thu, 25 Sep 2008 15:03:59 +0000 (11:03 -0400)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/ctree.h
fs/btrfs/inode.c
fs/btrfs/ordered-data.c
fs/btrfs/super.c
fs/btrfs/transaction.c

index 1e19f2d86334c673bd60df793b4e4708d87c671d..fa65fe027e45ec205c73d99f62f21dde1d9fde32 100644 (file)
@@ -1145,7 +1145,7 @@ int btrfs_check_free_space(struct btrfs_root *root, u64 num_required,
 int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page);
 int btrfs_readpage(struct file *file, struct page *page);
 void btrfs_delete_inode(struct inode *inode);
-void btrfs_drop_inode(struct inode *inode);
+void btrfs_put_inode(struct inode *inode);
 void btrfs_read_locked_inode(struct inode *inode);
 int btrfs_write_inode(struct inode *inode, int wait);
 void btrfs_dirty_inode(struct inode *inode);
index f83f88ca8ac749dc569d0641574382ad4d63b5f8..c1ac0bcbb462b59fde84551a0ba13046d8be4035 100644 (file)
@@ -601,6 +601,7 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
 {
        struct btrfs_root *root;
        struct btrfs_trans_handle *trans;
+       struct inode *inode = dentry->d_inode;
        int ret;
        unsigned long nr = 0;
 
@@ -617,6 +618,18 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
        ret = btrfs_unlink_trans(trans, root, dir, dentry);
        nr = trans->blocks_used;
 
+       if (inode->i_nlink == 0) {
+               int found;
+               /* if the inode isn't linked anywhere,
+                * we don't need to worry about
+                * data=ordered
+                */
+               found = btrfs_del_ordered_inode(inode);
+               if (found == 1) {
+                       atomic_dec(&inode->i_count);
+               }
+       }
+
        btrfs_end_transaction(trans, root);
 fail:
        mutex_unlock(&root->fs_info->fs_mutex);
@@ -993,15 +1006,22 @@ fail:
        return err;
 }
 
-void btrfs_drop_inode(struct inode *inode)
+void btrfs_put_inode(struct inode *inode)
 {
-       if (!BTRFS_I(inode)->ordered_trans || inode->i_nlink) {
-               generic_drop_inode(inode);
+       int ret;
+
+       if (!BTRFS_I(inode)->ordered_trans) {
+               return;
+       }
+
+       if (mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY) ||
+           mapping_tagged(inode->i_mapping, PAGECACHE_TAG_WRITEBACK))
                return;
+
+       ret = btrfs_del_ordered_inode(inode);
+       if (ret == 1) {
+               atomic_dec(&inode->i_count);
        }
-       /* FIXME, make sure this delete actually ends up in the transaction */
-       btrfs_del_ordered_inode(inode);
-       generic_drop_inode(inode);
 }
 
 void btrfs_delete_inode(struct inode *inode)
index b56011baa17cc88d6ec8784bdb46644112b7de98..cba2b623d02e8114cc32f6b3452e0651e64c2775 100644 (file)
@@ -153,6 +153,8 @@ int btrfs_add_ordered_inode(struct inode *inode)
        write_unlock(&tree->lock);
        if (node)
                kfree(entry);
+       else
+               igrab(inode);
        return 0;
 }
 
@@ -221,6 +223,7 @@ int btrfs_find_del_first_ordered_inode(struct btrfs_ordered_inode_tree *tree,
 }
 
 static int __btrfs_del_ordered_inode(struct btrfs_ordered_inode_tree *tree,
+                                    struct inode *inode,
                                     u64 root_objectid, u64 objectid)
 {
        struct tree_entry *entry;
@@ -234,6 +237,7 @@ static int __btrfs_del_ordered_inode(struct btrfs_ordered_inode_tree *tree,
                return 0;
        }
        rb_erase(node, &tree->tree);
+       BTRFS_I(inode)->ordered_trans = 0;
        write_unlock(&tree->lock);
        entry = rb_entry(node, struct tree_entry, rb_node);
        kfree(entry);
@@ -244,14 +248,16 @@ int btrfs_del_ordered_inode(struct inode *inode)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        u64 root_objectid = root->root_key.objectid;
+       int ret = 0;
 
        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, root_objectid, inode->i_ino);
+               ret = __btrfs_del_ordered_inode(tree, inode, root_objectid,
+                                               inode->i_ino);
        }
        spin_unlock(&root->fs_info->new_trans_lock);
-       return 0;
+       return ret;
 }
 
index 4deea393ca94048638512f7a27fcbe4f5c1774b3..e506de3168bc5610569fae6c5c1589a3b30ea626 100644 (file)
@@ -425,7 +425,7 @@ static struct file_system_type btrfs_fs_type = {
 
 static struct super_operations btrfs_super_ops = {
        .delete_inode   = btrfs_delete_inode,
-       .drop_inode     = btrfs_drop_inode,
+       .put_inode      = btrfs_put_inode,
        .put_super      = btrfs_put_super,
        .read_inode     = btrfs_read_locked_inode,
        .write_super    = btrfs_write_super,
index a3205808ab2b9851c0cdd0007ded8caaaa13040b..08f7a188dc3e3867857ade7a9463bcf47fd5d1e6 100644 (file)
@@ -521,6 +521,7 @@ int btrfs_write_ordered_inodes(struct btrfs_trans_handle *trans,
                if (inode) {
                        if (S_ISREG(inode->i_mode))
                                filemap_write_and_wait(inode->i_mapping);
+                       atomic_dec(&inode->i_count);
                        iput(inode);
                }
                mutex_lock(&root->fs_info->fs_mutex);