mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	Btrfs: Run igrab on data=ordered inodes to prevent deadlocks during writeout
Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
		
							parent
							
								
									9cce6c3bfc
								
							
						
					
					
						commit
						2da98f003f
					
				
					 5 changed files with 37 additions and 10 deletions
				
			
		| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
 | 
			
		|||
	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;
 | 
			
		||||
	}
 | 
			
		||||
	/* FIXME, make sure this delete actually ends up in the transaction */
 | 
			
		||||
	btrfs_del_ordered_inode(inode);
 | 
			
		||||
	generic_drop_inode(inode);
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void btrfs_delete_inode(struct inode *inode)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue