Commit 53687007 authored by Filipe Manana's avatar Filipe Manana Committed by David Sterba

Btrfs: fix metadata space leak on fixup worker failure to set range as delalloc

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: f3038ee3 ("btrfs: Handle btrfs_set_extent_delalloc failure in fixup worker")
CC: stable@vger.kernel.org # 4.19+
Reviewed-by: default avatarNikolay Borisov <nborisov@suse.com>
Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent a0e248bb
...@@ -2254,12 +2254,16 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work) ...@@ -2254,12 +2254,16 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)
mapping_set_error(page->mapping, ret); mapping_set_error(page->mapping, ret);
end_extent_writepage(page, ret, page_start, page_end); end_extent_writepage(page, ret, page_start, page_end);
ClearPageChecked(page); ClearPageChecked(page);
goto out; goto out_reserved;
} }
ClearPageChecked(page); ClearPageChecked(page);
set_page_dirty(page); set_page_dirty(page);
out_reserved:
btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE); btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE);
if (ret)
btrfs_delalloc_release_space(inode, data_reserved, page_start,
PAGE_SIZE, true);
out: out:
unlock_extent_cached(&BTRFS_I(inode)->io_tree, page_start, page_end, unlock_extent_cached(&BTRFS_I(inode)->io_tree, page_start, page_end,
&cached_state); &cached_state);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment