Subject: bug#79139: cp --reflink truncates sparse files on ZFS

From: Pádraig Brady <[email-masked]>
Date: Sat, 2 Aug 2025 09:32:39 +0100

On 02/08/2025 05:39, Collin Funk wrote:
> Bruno Haible <[email-masked]> writes:
> 
>>> +      /* Work around glibc bug 33245
>>
>> It would be good to document the workaround in
>> doc/glibc-functions/copy_file_range.texi.
> 
> Yep, I noticed as well. Just wanted to make sure I wasn't
> misunderstanding the versions before doing it myself. Done with the
> attached patch now.
> 
>> Collin Funk wrote:
>>> Can't we make this condition only occur for glibc 2.41 and glibc 2.42?
>>> The issue shouldn't occur before commit
>>> 89b53077d2a58f00e7debdfe58afabe953dac60d in glibc (2024-06-25).
>>
>> Users are supposed to be able to create binaries with an older version of
>> glibc, then upgrade their glibc. The binaries should continue to work.
> 
> Right. I seemed to have forgot that every program isn't statically
> linked to glibc... Thanks.

Thanks for the prompt fixes everyone.

I think the current gnulib code is good enough,
but it's worth mentioning run-time vs build-time checks.

For data corruption bugs we should be extra wary.

Consider build hosts with new glibc building binaries
to be run on older glibc (perhaps in containers etc.)
We saw such issues with cp before, with the kernel version check:
https://github.com/coreutils/gnulib/commit/fb034b35eb

Now the kernel binary interface does have more stringent
compat guarantees, than library interfaces like glibc,
so this is less of a concern than for kernel version checks.

For reference I made some notes on various version compat at:
http://pixelbeat/programming/linux_binary_compatibility.html
The thrust of that is that building on older systems
should produce binaries that work on newer ones,
and the current gnulib patch caters for that.

For reference if we did want to be extra defensive
for this silent data corruption bug, I suppose we could
check the glibc version at runtime with something like:

static signed char libc_ok;
if (! libc_ok)
{
#if 2 < __GLIBC__ + (8 <= __GLIBC_MINOR__)
   #include <gnu/libc-version.h>
   char const * glibc_ver = gnu_get_libc_version();
   libc_ok = (strcmp (glibc_ver, "2.41") != 0 && strcmp (glibc_ver, "2.42") != 0)
             ? 1 : -1;
#else
   libc_ok = 1;
#endif
}

Other reasons that the above might be overkill;
the gnulib workaround isn't too onerous as SYS_BUFZISE_MAX is large,
and I expect the glibc fix will be backported to glibc 2.41 systems promptly anyway.

cheers,
Padraig