Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4d5e74bc authored by Chris Mason's avatar Chris Mason
Browse files

Btrfs: Fix data=ordered vs wait_on_inode deadlock on older kernels



Using ilookup5 during data=ordered writeback could deadlock on I_LOCK.  This
saves a pointer to the inode instead.

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 2da98f00
Loading
Loading
Loading
Loading
+10 −2
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
struct tree_entry {
	u64 root_objectid;
	u64 objectid;
	struct inode *inode;
	struct rb_node rb_node;
};

@@ -144,6 +145,7 @@ 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);
@@ -159,7 +161,8 @@ int btrfs_add_ordered_inode(struct inode *inode)
}

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;
@@ -184,13 +187,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;
@@ -216,6 +222,8 @@ 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);
+4 −2
Original line number Diff line number Diff line
@@ -33,8 +33,10 @@ btrfs_ordered_inode_tree_init(struct btrfs_ordered_inode_tree *t)

int btrfs_add_ordered_inode(struct inode *inode);
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);
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);
int btrfs_del_ordered_inode(struct inode *inode);
#endif
+13 −17
Original line number Diff line number Diff line
@@ -490,19 +490,17 @@ int btrfs_write_ordered_inodes(struct btrfs_trans_handle *trans,
	while(1) {
		ret = btrfs_find_first_ordered_inode(
				&cur_trans->ordered_inode_tree,
				&root_objectid, &objectid);
				&root_objectid, &objectid, &inode);
		if (!ret)
			break;

		mutex_unlock(&root->fs_info->trans_mutex);
		mutex_unlock(&root->fs_info->fs_mutex);
		inode = btrfs_ilookup(root->fs_info->sb, objectid,
				      root_objectid);
		if (inode) {

		if (S_ISREG(inode->i_mode))
			filemap_fdatawrite(inode->i_mapping);
		iput(inode);
		}

		mutex_lock(&root->fs_info->fs_mutex);
		mutex_lock(&root->fs_info->trans_mutex);
	}
@@ -511,19 +509,17 @@ int btrfs_write_ordered_inodes(struct btrfs_trans_handle *trans,
		objectid = 0;
		ret = btrfs_find_del_first_ordered_inode(
				&cur_trans->ordered_inode_tree,
				&root_objectid, &objectid);
				&root_objectid, &objectid, &inode);
		if (!ret)
			break;
		mutex_unlock(&root->fs_info->trans_mutex);
		mutex_unlock(&root->fs_info->fs_mutex);
		inode = btrfs_ilookup(root->fs_info->sb, objectid,
				      root_objectid);
		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);
		mutex_lock(&root->fs_info->trans_mutex);
	}