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 <zab@versity.com>
This commit is contained in:
Zach Brown
2023-06-28 12:21:25 -07:00
parent 6c0ab75477
commit 3d99fda0f6

View File

@@ -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 */