[2/2] btrfs-progs: Do metadata preallocation for fs trees and csum tree
diff mbox series

Message ID 20190416102144.12173-3-wqu@suse.com
State New
Headers show
Series
  • btrfs-progs: Metadata preallocation enhancement
Related show

Commit Message

Qu Wenruo April 16, 2019, 10:21 a.m. UTC
In github issues, one user reports unexpected ENOSPC error if enabling
datasum druing convert.  After some investigation, it looks like that
during ext2_saved/image creation, we could create large file extent
whose size can be 128M (max data extent size).

In that case, its csum block will be at least 128K. Under certain case
we need to allocate extra metadata chunks to fulfill such space
requirement.

However we only do metadata prealloc if we're reserving extents for fs
trees.  (we use btrfs_root::ref_cows to determine whether we should do
metadata prealloc, and that member is only set for fs trees).

There is no explaination on why we only do metadata prealloc for file
trees, but from my educated guess, it could be related to avoid nested
extent/chunk tree modication.

At least extent reservation for csum tree shouldn't be a problem with
metadata block group preallocation.

So adding new condition for metadata preallocate to avoid unexpected
ENOSPC problem.

Issue: #123
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 extent-tree.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

Patch
diff mbox series

diff --git a/extent-tree.c b/extent-tree.c
index e25ddf02e5cc..cf2e29258dfb 100644
--- a/extent-tree.c
+++ b/extent-tree.c
@@ -2518,7 +2518,13 @@  int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
 		profile = BTRFS_BLOCK_GROUP_METADATA | alloc_profile;
 	}
 
-	if (root->ref_cows) {
+	/*
+	 * Also preallocate metadata for csum tree and fs trees (root->ref_cows
+	 * already set), as they can consume a lot of metadata space.
+	 * Pre-allocate to avoid unexpected ENOSPC.
+	 */
+	if (root->ref_cows ||
+	    root->root_key.objectid == BTRFS_CSUM_TREE_OBJECTID) {
 		if (!(profile & BTRFS_BLOCK_GROUP_METADATA)) {
 			ret = do_chunk_alloc(trans, info,
 					     num_bytes,