Browse Source

Btrfs: Run igrab on data=ordered inodes to prevent deadlocks during writeout

Signed-off-by: Chris Mason <chris.mason@oracle.com>
Chris Mason 17 years ago
parent
commit
2da98f003f
5 changed files with 37 additions and 10 deletions
  1. 1 1
      fs/btrfs/ctree.h
  2. 26 6
      fs/btrfs/inode.c
  3. 8 2
      fs/btrfs/ordered-data.c
  4. 1 1
      fs/btrfs/super.c
  5. 1 0
      fs/btrfs/transaction.c

+ 1 - 1
fs/btrfs/ctree.h

@@ -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);

+ 26 - 6
fs/btrfs/inode.c

@@ -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)

+ 8 - 2
fs/btrfs/ordered-data.c

@@ -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;
 }
 

+ 1 - 1
fs/btrfs/super.c

@@ -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,

+ 1 - 0
fs/btrfs/transaction.c

@@ -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);