From e632e888b3abbfa80abe92a1f5df34b081bd93cc Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Wed, 25 Mar 2026 13:53:29 -0700 Subject: [PATCH] Ramping up data preallocation Ramps up data preallocation based on the number of online blocks. This results in a simple 2< --- kmod/src/data.c | 18 ++++++++++++++++++ tests/golden/data-prealloc | 12 ++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/kmod/src/data.c b/kmod/src/data.c index 0abb48c0..33a6f7a1 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -384,6 +384,12 @@ static inline u64 ext_last(struct scoutfs_extent *ext) * This can waste a lot of space for small or sparse files but is * reasonable when a file population is known to be large and dense but * known to be written with non-streaming write patterns. + * + * In either strategy, preallocation ramps up proportionally with the + * file's online block count rather than jumping to the full prealloc + * size. This avoids overallocation for small files in mixed-size + * workloads while still allowing large files to benefit from full + * preallocation. */ static int alloc_block(struct super_block *sb, struct inode *inode, struct scoutfs_extent *ext, u64 iblock, @@ -400,6 +406,7 @@ static int alloc_block(struct super_block *sb, struct inode *inode, struct scoutfs_extent found; struct scoutfs_extent pre = {0,}; bool undo_pre = false; + bool have_onoff = false; u64 blkno = 0; u64 online; u64 offline; @@ -445,6 +452,7 @@ static int alloc_block(struct super_block *sb, struct inode *inode, * blocks. */ scoutfs_inode_get_onoff(inode, &online, &offline); + have_onoff = true; if (iblock > 1 && iblock == online) { ret = scoutfs_ext_next(sb, &data_ext_ops, &args, iblock, 1, &found); @@ -491,6 +499,16 @@ static int alloc_block(struct super_block *sb, struct inode *inode, /* overall prealloc limit */ count = min_t(u64, count, opts.data_prealloc_blocks); + /* + * Ramp preallocation up proportionally with the file's online + * block count rather than jumping to the full prealloc size. + */ + if (!ext->len) { + if (!have_onoff) + scoutfs_inode_get_onoff(inode, &online, &offline); + count = max_t(u64, 1, min(count, online)); + } + ret = scoutfs_alloc_data(sb, datinf->alloc, datinf->wri, &datinf->dalloc, count, &blkno, &count); if (ret < 0) diff --git a/tests/golden/data-prealloc b/tests/golden/data-prealloc index 19efd20a..69fb3a23 100644 --- a/tests/golden/data-prealloc +++ b/tests/golden/data-prealloc @@ -8,10 +8,10 @@ /mnt/test/test/data-prealloc/file-1: extents: 32 /mnt/test/test/data-prealloc/file-2: extents: 32 == any writes to region prealloc get full extents -/mnt/test/test/data-prealloc/file-1: extents: 4 -/mnt/test/test/data-prealloc/file-2: extents: 4 -/mnt/test/test/data-prealloc/file-1: extents: 4 -/mnt/test/test/data-prealloc/file-2: extents: 4 +/mnt/test/test/data-prealloc/file-1: extents: 8 +/mnt/test/test/data-prealloc/file-2: extents: 8 +/mnt/test/test/data-prealloc/file-1: extents: 8 +/mnt/test/test/data-prealloc/file-2: extents: 8 == streaming offline writes get full extents either way /mnt/test/test/data-prealloc/file-1: extents: 4 /mnt/test/test/data-prealloc/file-2: extents: 4 @@ -20,8 +20,8 @@ == goofy preallocation amounts work /mnt/test/test/data-prealloc/file-1: extents: 6 /mnt/test/test/data-prealloc/file-2: extents: 6 -/mnt/test/test/data-prealloc/file-1: extents: 6 -/mnt/test/test/data-prealloc/file-2: extents: 6 +/mnt/test/test/data-prealloc/file-1: extents: 10 +/mnt/test/test/data-prealloc/file-2: extents: 10 /mnt/test/test/data-prealloc/file-1: extents: 3 /mnt/test/test/data-prealloc/file-2: extents: 3 == block writes into region allocs hole