From 55f9435fad37b1b34d96914060fd921605303509 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Thu, 13 Jul 2023 12:31:58 -0700 Subject: [PATCH] Fix partial preallocation when _contig_only = 0 Data preallocation attempts to allocate large aligned regions of extents. It tried to fill the hole around a write offset that didn't contain an extent. It missed the case where there can be multiple extents between the start of the region and the hole. It could try to overwrite these additional existing extents and writes could return EINVAL. We fix this by trimming the preallocation to start at the write offset if there are any extents in the region before the write offset. The data preallocation test output has to be updated now that allocation extents won't grow towards the start of the region when there are existing extents. Signed-off-by: Zach Brown --- kmod/src/data.c | 14 ++++++-------- tests/golden/data-prealloc | 18 ------------------ tests/tests/data-prealloc.sh | 3 ++- 3 files changed, 8 insertions(+), 27 deletions(-) diff --git a/kmod/src/data.c b/kmod/src/data.c index 6b581a3b..48aae57a 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -458,11 +458,9 @@ static int alloc_block(struct super_block *sb, struct inode *inode, /* * 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). + * that contains iblock. We'd have to add a bit of plumbing + * to find previous extents so we only search for a next + * extent from the front of the region and from iblock. */ div64_u64_rem(iblock, opts.data_prealloc_blocks, &rem); start = iblock - rem; @@ -473,15 +471,15 @@ static int alloc_block(struct super_block *sb, struct inode *inode, /* 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; + count -= iblock - start; + start = iblock; /* 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 */ + /* trim count by next extent after iblock */ if (found.len && found.start > start && found.start < start + count) count = (found.start - start); } diff --git a/tests/golden/data-prealloc b/tests/golden/data-prealloc index f6ac8d65..ddea23cf 100644 --- a/tests/golden/data-prealloc +++ b/tests/golden/data-prealloc @@ -122,7 +122,6 @@ wrote blk 39 25.. 1: 26.. 6: unwritten 32.. 1: -33.. 6: unwritten 39.. 1: 40.. 1: 55.. 1: @@ -143,10 +142,8 @@ wrote blk 44 25.. 1: 26.. 6: unwritten 32.. 1: -33.. 6: unwritten 39.. 1: 40.. 1: -41.. 3: unwritten 44.. 1: 45.. 3: unwritten 55.. 1: @@ -167,10 +164,8 @@ wrote blk 48 25.. 1: 26.. 6: unwritten 32.. 1: -33.. 6: unwritten 39.. 1: 40.. 1: -41.. 3: unwritten 44.. 1: 45.. 3: unwritten 48.. 1: @@ -193,10 +188,8 @@ wrote blk 62 25.. 1: 26.. 6: unwritten 32.. 1: -33.. 6: unwritten 39.. 1: 40.. 1: -41.. 3: unwritten 44.. 1: 45.. 3: unwritten 48.. 1: @@ -221,10 +214,8 @@ wrote blk 67 25.. 1: 26.. 6: unwritten 32.. 1: -33.. 6: unwritten 39.. 1: 40.. 1: -41.. 3: unwritten 44.. 1: 45.. 3: unwritten 48.. 1: @@ -252,10 +243,8 @@ wrote blk 73 25.. 1: 26.. 6: unwritten 32.. 1: -33.. 6: unwritten 39.. 1: 40.. 1: -41.. 3: unwritten 44.. 1: 45.. 3: unwritten 48.. 1: @@ -285,10 +274,8 @@ wrote blk 86 25.. 1: 26.. 6: unwritten 32.. 1: -33.. 6: unwritten 39.. 1: 40.. 1: -41.. 3: unwritten 44.. 1: 45.. 3: unwritten 48.. 1: @@ -304,7 +291,6 @@ wrote blk 86 73.. 1: 74.. 5: unwritten 79.. 2: -81.. 5: unwritten 86.. 1: 87.. 2: 95.. 1: eof @@ -320,10 +306,8 @@ wrote blk 92 25.. 1: 26.. 6: unwritten 32.. 1: -33.. 6: unwritten 39.. 1: 40.. 1: -41.. 3: unwritten 44.. 1: 45.. 3: unwritten 48.. 1: @@ -339,10 +323,8 @@ wrote blk 92 73.. 1: 74.. 5: unwritten 79.. 2: -81.. 5: unwritten 86.. 1: 87.. 2: -89.. 3: unwritten 92.. 1: 93.. 2: unwritten 95.. 1: eof diff --git a/tests/tests/data-prealloc.sh b/tests/tests/data-prealloc.sh index 09f42637..fdc09f8e 100644 --- a/tests/tests/data-prealloc.sh +++ b/tests/tests/data-prealloc.sh @@ -168,7 +168,8 @@ print_extents_found $prefix # the start, and one at the end. # # Let's keep this last because it creates a ton of output to read -# through. +# through. The correct output is tied to preallocation strategy so it +# has to be verified each time we change preallocation. # echo "== block writes into region allocs hole" t_set_sysfs_mount_option 0 data_prealloc_blocks 8