Linux-BTRFS Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH] Btrfs: fix metadata space leak on fixup worker failure to set range as delalloc
@ 2019-10-09 16:43 fdmanana
  2019-10-11  7:00 ` Nikolay Borisov
  2019-10-11 18:38 ` David Sterba
  0 siblings, 2 replies; 3+ messages in thread
From: fdmanana @ 2019-10-09 16:43 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

In the fixup worker, if we fail to mark the range as delalloc in the io
tree, we must release the previously reserved metadata, as well as update
the outstanding extents counter for the inode, otherwise we leak metadata
space.

In pratice we can't return an error from btrfs_set_extent_delalloc(),
which is just a wrapper around __set_extent_bit(), as for most errors
__set_extent_bit() does a BUG_ON() (or panics which hits a BUG_ON() as
well) and returning an -EEXIST error doesn't happen in this case since
the exclusive bits parameter always has a value of 0 through this code
path. Nevertheless, just fix the error handling in the fixup worker,
in case one day __set_extent_bit() can return an error to this code
path.

Fixes: f3038ee3a3f101 ("btrfs: Handle btrfs_set_extent_delalloc failure in fixup worker")
Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/inode.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 0f2754eaa05b..f23b14ec743a 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2201,12 +2201,16 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)
 		mapping_set_error(page->mapping, ret);
 		end_extent_writepage(page, ret, page_start, page_end);
 		ClearPageChecked(page);
-		goto out;
+		goto out_reserved;
 	}
 
 	ClearPageChecked(page);
 	set_page_dirty(page);
-	btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE, false);
+out_reserved:
+	btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE, ret != 0);
+	if (ret)
+		btrfs_delalloc_release_space(inode, data_reserved, page_start,
+					     PAGE_SIZE, true);
 out:
 	unlock_extent_cached(&BTRFS_I(inode)->io_tree, page_start, page_end,
 			     &cached_state);
-- 
2.11.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] Btrfs: fix metadata space leak on fixup worker failure to set range as delalloc
  2019-10-09 16:43 [PATCH] Btrfs: fix metadata space leak on fixup worker failure to set range as delalloc fdmanana
@ 2019-10-11  7:00 ` Nikolay Borisov
  2019-10-11 18:38 ` David Sterba
  1 sibling, 0 replies; 3+ messages in thread
From: Nikolay Borisov @ 2019-10-11  7:00 UTC (permalink / raw)
  To: fdmanana, linux-btrfs



On 9.10.19 г. 19:43 ч., fdmanana@kernel.org wrote:
> From: Filipe Manana <fdmanana@suse.com>
> 
> In the fixup worker, if we fail to mark the range as delalloc in the io
> tree, we must release the previously reserved metadata, as well as update
> the outstanding extents counter for the inode, otherwise we leak metadata
> space.
> 
> In pratice we can't return an error from btrfs_set_extent_delalloc(),
> which is just a wrapper around __set_extent_bit(), as for most errors
> __set_extent_bit() does a BUG_ON() (or panics which hits a BUG_ON() as
> well) and returning an -EEXIST error doesn't happen in this case since
> the exclusive bits parameter always has a value of 0 through this code
> path. Nevertheless, just fix the error handling in the fixup worker,
> in case one day __set_extent_bit() can return an error to this code
> path.
> 
> Fixes: f3038ee3a3f101 ("btrfs: Handle btrfs_set_extent_delalloc failure in fixup worker")
> Signed-off-by: Filipe Manana <fdmanana@suse.com>

Reviewed-by: Nikolay Borisov <nborisov@suse.com>

> ---
>  fs/btrfs/inode.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> index 0f2754eaa05b..f23b14ec743a 100644
> --- a/fs/btrfs/inode.c
> +++ b/fs/btrfs/inode.c
> @@ -2201,12 +2201,16 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)
>  		mapping_set_error(page->mapping, ret);
>  		end_extent_writepage(page, ret, page_start, page_end);
>  		ClearPageChecked(page);
> -		goto out;
> +		goto out_reserved;
>  	}
>  
>  	ClearPageChecked(page);
>  	set_page_dirty(page);
> -	btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE, false);
> +out_reserved:
> +	btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE, ret != 0);
> +	if (ret)
> +		btrfs_delalloc_release_space(inode, data_reserved, page_start,
> +					     PAGE_SIZE, true);
>  out:
>  	unlock_extent_cached(&BTRFS_I(inode)->io_tree, page_start, page_end,
>  			     &cached_state);
> 

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] Btrfs: fix metadata space leak on fixup worker failure to set range as delalloc
  2019-10-09 16:43 [PATCH] Btrfs: fix metadata space leak on fixup worker failure to set range as delalloc fdmanana
  2019-10-11  7:00 ` Nikolay Borisov
@ 2019-10-11 18:38 ` David Sterba
  1 sibling, 0 replies; 3+ messages in thread
From: David Sterba @ 2019-10-11 18:38 UTC (permalink / raw)
  To: fdmanana; +Cc: linux-btrfs

On Wed, Oct 09, 2019 at 05:43:59PM +0100, fdmanana@kernel.org wrote:
> From: Filipe Manana <fdmanana@suse.com>
> 
> In the fixup worker, if we fail to mark the range as delalloc in the io
> tree, we must release the previously reserved metadata, as well as update
> the outstanding extents counter for the inode, otherwise we leak metadata
> space.
> 
> In pratice we can't return an error from btrfs_set_extent_delalloc(),
> which is just a wrapper around __set_extent_bit(), as for most errors
> __set_extent_bit() does a BUG_ON() (or panics which hits a BUG_ON() as
> well) and returning an -EEXIST error doesn't happen in this case since
> the exclusive bits parameter always has a value of 0 through this code
> path. Nevertheless, just fix the error handling in the fixup worker,
> in case one day __set_extent_bit() can return an error to this code
> path.
> 
> Fixes: f3038ee3a3f101 ("btrfs: Handle btrfs_set_extent_delalloc failure in fixup worker")
> Signed-off-by: Filipe Manana <fdmanana@suse.com>

Added to misc-next, thanks.

> @@ -2201,12 +2201,16 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)
>  		mapping_set_error(page->mapping, ret);
>  		end_extent_writepage(page, ret, page_start, page_end);
>  		ClearPageChecked(page);
> -		goto out;
> +		goto out_reserved;
>  	}
>  
>  	ClearPageChecked(page);
>  	set_page_dirty(page);
> -	btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE, false);
> +out_reserved:
> +	btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE, ret != 0);

This is a shortcut to avoid extra variable to track the status of the
3rd parameter (qgroup_free) but as the goto and label are only a few
lines apart, I guess it's ok.

> +	if (ret)
> +		btrfs_delalloc_release_space(inode, data_reserved, page_start,
> +					     PAGE_SIZE, true);

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, back to index

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-09 16:43 [PATCH] Btrfs: fix metadata space leak on fixup worker failure to set range as delalloc fdmanana
2019-10-11  7:00 ` Nikolay Borisov
2019-10-11 18:38 ` David Sterba

Linux-BTRFS Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-btrfs/0 linux-btrfs/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-btrfs linux-btrfs/ https://lore.kernel.org/linux-btrfs \
		linux-btrfs@vger.kernel.org linux-btrfs@archiver.kernel.org
	public-inbox-index linux-btrfs

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-btrfs


AGPL code for this site: git clone https://public-inbox.org/ public-inbox