diff options
Diffstat (limited to 'fs/btrfs/inode.c')
| -rw-r--r-- | fs/btrfs/inode.c | 32 | 
1 files changed, 26 insertions, 6 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 6bfc4343c98d..5082b9c70f8c 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1128,7 +1128,6 @@ static noinline int cow_file_range(struct btrfs_inode *inode,  	int ret = 0;  	if (btrfs_is_free_space_inode(inode)) { -		WARN_ON_ONCE(1);  		ret = -EINVAL;  		goto out_unlock;  	} @@ -2017,8 +2016,7 @@ int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct page *locked_page  		 * to use run_delalloc_nocow() here, like for  regular  		 * preallocated inodes.  		 */ -		ASSERT(!zoned || -		       (zoned && btrfs_is_data_reloc_root(inode->root))); +		ASSERT(!zoned || btrfs_is_data_reloc_root(inode->root));  		ret = run_delalloc_nocow(inode, locked_page, start, end,  					 page_started, nr_written);  	} else if (!inode_can_compress(inode) || @@ -4488,6 +4486,13 @@ int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry)  			   dest->root_key.objectid);  		return -EPERM;  	} +	if (atomic_read(&dest->nr_swapfiles)) { +		spin_unlock(&dest->root_item_lock); +		btrfs_warn(fs_info, +			   "attempt to delete subvolume %llu with active swapfile", +			   root->root_key.objectid); +		return -EPERM; +	}  	root_flags = btrfs_root_flags(&dest->root_item);  	btrfs_set_root_flags(&dest->root_item,  			     root_flags | BTRFS_ROOT_SUBVOL_DEAD); @@ -7438,6 +7443,7 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,  	u64 block_start, orig_start, orig_block_len, ram_bytes;  	bool can_nocow = false;  	bool space_reserved = false; +	u64 prev_len;  	int ret = 0;  	/* @@ -7465,6 +7471,7 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,  			can_nocow = true;  	} +	prev_len = len;  	if (can_nocow) {  		struct extent_map *em2; @@ -7494,8 +7501,6 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,  			goto out;  		}  	} else { -		const u64 prev_len = len; -  		/* Our caller expects us to free the input extent map. */  		free_extent_map(em);  		*map = NULL; @@ -7526,7 +7531,7 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,  	 * We have created our ordered extent, so we can now release our reservation  	 * for an outstanding extent.  	 */ -	btrfs_delalloc_release_extents(BTRFS_I(inode), len); +	btrfs_delalloc_release_extents(BTRFS_I(inode), prev_len);  	/*  	 * Need to update the i_size under the extent lock so buffered @@ -11107,8 +11112,23 @@ static int btrfs_swap_activate(struct swap_info_struct *sis, struct file *file,  	 * set. We use this counter to prevent snapshots. We must increment it  	 * before walking the extents because we don't want a concurrent  	 * snapshot to run after we've already checked the extents. +	 * +	 * It is possible that subvolume is marked for deletion but still not +	 * removed yet. To prevent this race, we check the root status before +	 * activating the swapfile.  	 */ +	spin_lock(&root->root_item_lock); +	if (btrfs_root_dead(root)) { +		spin_unlock(&root->root_item_lock); + +		btrfs_exclop_finish(fs_info); +		btrfs_warn(fs_info, +		"cannot activate swapfile because subvolume %llu is being deleted", +			root->root_key.objectid); +		return -EPERM; +	}  	atomic_inc(&root->nr_swapfiles); +	spin_unlock(&root->root_item_lock);  	isize = ALIGN_DOWN(inode->i_size, fs_info->sectorsize);  | 
