Skip to content

pr-git-2380/vladpetric/vp/reflink-copy-v1

tagged this 11 Aug 15:03
From: Vlad Petric <vlad@drpetric.com>

Git currently copies files byte-for-byte through copy_file(). Local
clones separately try to hardlink object files before falling back to
copying them.

On filesystems that support copy-on-write cloning, a reflink can share
the underlying storage without making the source and destination names
refer to the same inode. This provides most of the space and I/O
benefits of hardlinks while allowing either file to be replaced or
modified independently.

On Linux, try FICLONE before performing a byte-for-byte copy. Treat
reflinking as an optimization: if the ioctl is unavailable or fails,
remove the partial destination and use the existing copy path.

For local clones, try a reflink before the existing hardlink path. The
resulting order is therefore:

  - reflink;
  - hardlink, unless --no-hardlinks was requested;
  - byte-for-byte copy.

Preserve source timestamps when reflinking local object files. This
matches the previous hardlink and copy behavior and is important for
the expiry decisions made by prune and gc.

Add an LD_PRELOAD-based test helper that can force FICLONE to succeed,
report EOPNOTSUPP, or report another error. This exercises the reflink
and fallback paths even when the test filesystem does not support
reflinks. Cover generic file copying, local clones, --no-hardlinks,
hardlink fallback, byte-copy fallback, object integrity, and timestamp
preservation.

The focused tests pass on three independent filesystems:

  - ZFS at /home;
  - ext4 at /tmp;
  - tmpfs at /dev/shm.

The complete Git test suite also passes on all three filesystems with
no unexpected failures.

Signed-off-by: Vlad Petric <vlad@drpetric.com>

Submitted-As: https://lore.kernel.org/git/pull.2380.git.git.1786460606222.gitgitgadget@gmail.com
Assets 2
Loading