From 3d99fda0f6e5cc689e156c0b92a4a91ee0647b6a Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Wed, 28 Jun 2023 12:21:25 -0700 Subject: [PATCH] Preallocate data around iblock when noncontig If the _contig_only option isn't set then we try to preallocate aligned regions of files. The initial implementation naively only allowed one preallocation attempt in each aligned region. If it got a small allocation that didn't fill the region then every future allocation in the region would be a single block. This changes every preallocation in the region to attempt to fill the hole in the region that iblock fell in. It uses an extra extent search (item cache search) to try and avoid thousands of single block allocations. Signed-off-by: Zach Brown --- kmod/src/data.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/kmod/src/data.c b/kmod/src/data.c index bf934084..e05c23c4 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -456,11 +456,13 @@ static int alloc_block(struct super_block *sb, struct inode *inode, } else { /* - * Preallocation of aligned regions only preallocates if - * the aligned region contains no extents at all. This - * could be fooled by offline sparse extents but we - * don't want to iterate over all offline extents in the - * aligned region. + * Preallocation within aligned regions tries to + * allocate an extent to fill the hole in the region + * that contains iblock. We search for a next extent + * from the start of the region. If it's at the start + * we might have to search again to find an existing + * extent at the end of the region. (This next could be + * given to us by the caller). */ div64_u64_rem(iblock, opts.data_prealloc_blocks, &rem); start = iblock - rem; @@ -468,8 +470,20 @@ static int alloc_block(struct super_block *sb, struct inode *inode, ret = scoutfs_ext_next(sb, &data_ext_ops, &args, start, 1, &found); if (ret < 0 && ret != -ENOENT) goto out; - if (found.len && found.start < start + count) - count = 1; + + /* trim count if there's an extent in the region before iblock */ + if (found.len && found.start < iblock) { + count -= (found.start + found.len) - start; + start = found.start + found.len; + /* see if there's also an extent after iblock */ + ret = scoutfs_ext_next(sb, &data_ext_ops, &args, iblock, 1, &found); + if (ret < 0 && ret != -ENOENT) + goto out; + } + + /* trim count by a next extent in the region */ + if (found.len && found.start > start && found.start < start + count) + count = (found.start - start); } /* overall prealloc limit */