diff options
Diffstat (limited to 'fs/btrfs/inode.c')
| -rw-r--r-- | fs/btrfs/inode.c | 48 | 
1 files changed, 37 insertions, 11 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 809b11472a80..f88e0ca8331d 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3184,8 +3184,23 @@ out:  			unwritten_start += logical_len;  		clear_extent_uptodate(io_tree, unwritten_start, end, NULL); -		/* Drop extent maps for the part of the extent we didn't write. */ -		btrfs_drop_extent_map_range(inode, unwritten_start, end, false); +		/* +		 * Drop extent maps for the part of the extent we didn't write. +		 * +		 * We have an exception here for the free_space_inode, this is +		 * because when we do btrfs_get_extent() on the free space inode +		 * we will search the commit root.  If this is a new block group +		 * we won't find anything, and we will trip over the assert in +		 * writepage where we do ASSERT(em->block_start != +		 * EXTENT_MAP_HOLE). +		 * +		 * Theoretically we could also skip this for any NOCOW extent as +		 * we don't mess with the extent map tree in the NOCOW case, but +		 * for now simply skip this if we are the free space inode. +		 */ +		if (!btrfs_is_free_space_inode(inode)) +			btrfs_drop_extent_map_range(inode, unwritten_start, +						    end, false);  		/*  		 * If the ordered extent had an IOERR or something else went @@ -4458,6 +4473,8 @@ int btrfs_delete_subvolume(struct btrfs_inode *dir, struct dentry *dentry)  	u64 root_flags;  	int ret; +	down_write(&fs_info->subvol_sem); +  	/*  	 * Don't allow to delete a subvolume with send in progress. This is  	 * inside the inode lock so the error handling that has to drop the bit @@ -4469,25 +4486,25 @@ int btrfs_delete_subvolume(struct btrfs_inode *dir, struct dentry *dentry)  		btrfs_warn(fs_info,  			   "attempt to delete subvolume %llu during send",  			   dest->root_key.objectid); -		return -EPERM; +		ret = -EPERM; +		goto out_up_write;  	}  	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; +		ret = -EPERM; +		goto out_up_write;  	}  	root_flags = btrfs_root_flags(&dest->root_item);  	btrfs_set_root_flags(&dest->root_item,  			     root_flags | BTRFS_ROOT_SUBVOL_DEAD);  	spin_unlock(&dest->root_item_lock); -	down_write(&fs_info->subvol_sem); -  	ret = may_destroy_subvol(dest);  	if (ret) -		goto out_up_write; +		goto out_undead;  	btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP);  	/* @@ -4497,7 +4514,7 @@ int btrfs_delete_subvolume(struct btrfs_inode *dir, struct dentry *dentry)  	 */  	ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, 5, true);  	if (ret) -		goto out_up_write; +		goto out_undead;  	trans = btrfs_start_transaction(root, 0);  	if (IS_ERR(trans)) { @@ -4563,15 +4580,17 @@ out_end_trans:  	inode->i_flags |= S_DEAD;  out_release:  	btrfs_subvolume_release_metadata(root, &block_rsv); -out_up_write: -	up_write(&fs_info->subvol_sem); +out_undead:  	if (ret) {  		spin_lock(&dest->root_item_lock);  		root_flags = btrfs_root_flags(&dest->root_item);  		btrfs_set_root_flags(&dest->root_item,  				root_flags & ~BTRFS_ROOT_SUBVOL_DEAD);  		spin_unlock(&dest->root_item_lock); -	} else { +	} +out_up_write: +	up_write(&fs_info->subvol_sem); +	if (!ret) {  		d_invalidate(dentry);  		btrfs_prune_dentries(dest);  		ASSERT(dest->send_in_progress == 0); @@ -10269,6 +10288,13 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from,  	if (encoded->encryption != BTRFS_ENCODED_IO_ENCRYPTION_NONE)  		return -EINVAL; +	/* +	 * Compressed extents should always have checksums, so error out if we +	 * have a NOCOW file or inode was created while mounted with NODATASUM. +	 */ +	if (inode->flags & BTRFS_INODE_NODATASUM) +		return -EINVAL; +  	orig_count = iov_iter_count(from);  	/* The extent size must be sane. */  | 
