From: Lennart Poettering Date: Fri, 20 Jun 2025 10:07:27 +0000 (+0200) Subject: copy: when looking for file holes, consider empty data segments X-Git-Tag: v258-rc1~281 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e04d7824167e967a64142991a541b1686cc1351c;p=thirdparty%2Fsystemd.git copy: when looking for file holes, consider empty data segments This could mean that we hit EOF, or it could mean that somebody punched a hole concurrently where we are currently looking. Let's figure this out by simply trying to copy a single byte, which will give us a definitive answer. Fixes: #35569 --- diff --git a/src/shared/copy.c b/src/shared/copy.c index 17268387569..6f415fe2078 100644 --- a/src/shared/copy.c +++ b/src/shared/copy.c @@ -335,15 +335,21 @@ int copy_bytes_full( break; return -errno; } + if (e == c) + /* Empty data segment? Maybe concurrent hole punching taking place? Or EOF? + * Let's figure this out by copying the smallest amount possible */ + m = 1; + else { + assert(e > c); + + /* SEEK_HOLE modifies the file offset so we need to move back to the initial offset. */ + if (lseek(fdf, c, SEEK_SET) < 0) + return -errno; - /* SEEK_HOLE modifies the file offset so we need to move back to the initial offset. */ - if (lseek(fdf, c, SEEK_SET) < 0) - return -errno; - - /* Make sure we're not copying more than the current data segment. */ - m = MIN(m, (size_t) e - c); - if (m <= 0) - continue; + /* Make sure we're not copying more than the current data segment. */ + m = MIN(m, (size_t) e - c); + assert(m > 0); + } } /* First try copy_file_range(), unless we already tried */