GNU cp --reflink: Fast Clones, Fallbacks, and Storage Boundaries
Choose GNU cp reflink modes deliberately, test copy-on-write support on the actual paths, and avoid mistaking a fast clone for a backup or atomic publish.
cp --reflink can make a large file appear to copy almost instantly by asking the filesystem to create a second file that initially shares data extents with the source. That is a useful optimization for disposable work trees, virtual-machine images, and large test fixtures. It is also easy to misread: a quick copy is not proof that blocks are independent, that the destination is a backup, or that later writes will remain cheap.
This guide describes GNU Coreutils cp using the versioned 9.12 manual source and implementation. --reflink is a GNU extension, not a POSIX shell guarantee. Check the installed implementation before putting these options into a script; the cp on macOS, BusyBox, a container image, and a GNU/Linux host need not expose the same interface. GNU’s documentation defines a reflink as a lightweight copy whose blocks are copied only when changed. Btrfs describes the resulting files as independent names that can initially share extents. The filesystem and the exact source/destination paths determine whether that operation is available.
Pick the fallback policy explicitly
GNU cp offers three policies:
| Invocation | Copy policy | Appropriate when |
|---|---|---|
--reflink=auto |
Try a copy-on-write clone, then fall back to an ordinary copy if the clone is unavailable. This is GNU cp’s default behavior. |
A clone is a performance optimization, but a correct copy is still required. |
--reflink=always |
Require the copy-on-write operation; fail instead of silently doing a regular copy when it is unsupported. | The workflow depends on clone capability and should stop if it is absent. |
--reflink=never |
Request an ordinary copy rather than GNU cp’s reflink operation. |
The workflow deliberately does not want cp to request a reflink. |
For routine interactive use, the default is convenient. For automation, select the mode that matches the contract. A backup job that uses auto may successfully finish with a regular copy on one filesystem and a shared-extent clone on another. Conversely, always turns an unavailable optimization into a clear failure, which is preferable when the operator needs to know that a clone was actually requested and accepted.
never only rules out GNU cp’s reflink request. It is not a promise that every lower storage layer uses physically unique media: a filesystem, storage appliance, virtual disk, or array can have its own compression or deduplication behavior. If physical separation matters, define that requirement with the storage platform rather than inferring it from a command-line flag.
Exercise the real source and destination filesystem
On Btrfs, a reflink is a shallow copy: both files initially reference shared extents, and a write to one file allocates changed data without changing the other file’s visible contents. Btrfs documents that reflinks require the source and destination to be on the same filesystem. Mount and inode properties can impose further constraints, so a filesystem name alone is not a sufficient capability test. Other filesystems have their own clone interfaces and limitations.
Use a disposable directory on the same mount and path layout as the intended workload. The following Bash example creates a unique fixture, requires the reflink operation, modifies only the clone, and checks that the source’s contents remain unchanged:
#!/usr/bin/env bash
set -euo pipefail
umask 077
work=$(mktemp -d "${TMPDIR:-/tmp}/cp-reflink-test.XXXXXX")
trap 'rm -rf -- "$work"' EXIT
printf 'source contents\n' >"$work/source"
cp --reflink=always -- "$work/source" "$work/clone"
printf 'clone-only contents\n' >"$work/clone"
grep -Fxq 'source contents' "$work/source"
grep -Fxq 'clone-only contents' "$work/clone"
cmp -s "$work/source" <(printf 'source contents\n')
printf '%s\n' 'The required clone succeeded and the two files diverged independently.'
Run this only where mktemp creates the work directory on the filesystem you want to test. If cp --reflink=always fails, preserve the diagnostic and investigate the actual mount, filesystem, and file attributes; do not replace always with auto and then report that the test proved reflink support. A passing test demonstrates that this implementation could create this clone for these paths at that time. It does not certify every directory, mount, container volume, or future kernel/filesystem configuration.
To let an optimization fail open to an ordinary copy, use the more permissive form:
cp --reflink=auto -- "$source_image" "$working_image"
That form asks GNU cp to try a clone but prioritizes getting a normal copy when it cannot. Do not use its successful exit status as telemetry that a reflink occurred. If the difference matters, require the operation, use documented filesystem-specific diagnostics, or record a separate capability test; do not infer sharing from elapsed time or apparent file size.
Reflink and sparse-file policy solve different problems
Reflink policy concerns whether source and destination can initially share extents. Sparse-file policy concerns whether runs of zero bytes in the destination are represented as holes. GNU cp documents --sparse=auto as its default heuristic, --sparse=always as an attempt to create holes for sufficiently long zero runs, and --sparse=never as a way to inhibit sparse output. A sparse file reads as zeros in its holes without storing those zero bytes in ordinary data blocks, but not every filesystem or downstream image consumer handles sparse files in the same way.
Do not add --sparse=always just because a VM image is large or because the source happens to contain zeros. First confirm that the destination filesystem supports holes and that the application accepts them. When an image format or interchange process requires allocated data, test that exact consumer and choose an explicit sparse policy. Reflinks and holes can both reduce immediate allocation, but they are not interchangeable guarantees and neither is a content-integrity check.
A clone is not an independent backup
A reflinked destination is a separate file from the application’s perspective: changing its contents should not change the source. Yet both names can depend on the same underlying filesystem, metadata, device set, and administrative failure domain. A filesystem failure, accidental deletion policy, ransomware running with access to both paths, or loss of the storage pool can affect both. A clone is not a second copy on independent media and does not create an off-site recovery point.
Space use can also shift over time. The initial operation may share extents; later writes to either file can allocate new extents and metadata. A workload that creates many clones and modifies most of each one may eventually consume space closer to multiple full copies, plus copy-on-write metadata and fragmentation costs. Conversely, clones that remain mostly unchanged may retain sharing. Capacity planning should model the write pattern and retention window, not multiply the initial cp duration into a projected storage saving.
Do not use du output or apparent file length alone as proof of unique physical allocation. The apparent length describes the logical file; block counts and sharing diagnostics vary by filesystem and may not answer the same accounting question. Use the storage platform’s documented accounting tools, and validate the measurement against a representative workload. For Btrfs, consult the Btrfs documentation for the current behavior and limitations of its own inspection tools rather than treating a generic utility’s output as a universal reflink metric.
Keep recovery copies on a separate failure domain with their own retention and access policy. If the source is a database, active VM, or mutable application tree, first decide whether the source must be quiesced or captured through an application-consistent snapshot. A file-copy operation is not an application transaction. Reflink speed does not make a live multi-file dataset internally consistent.
Do not confuse cloning with publication
cp writes the destination as it copies. A reader that opens the destination during the operation may therefore see an incomplete artifact. Reflink can shorten that interval, but it does not turn the pathname update into an atomic publish protocol. For releases, stage the candidate in a private name, validate its content and metadata, then publish it through a same-filesystem rename or another mechanism documented by the application. That workflow is distinct from the decision to share file extents.
When a clone is the desired result, keep the policy visible in the command and in operational logs. Record the GNU Coreutils version, the requested mode, source and destination filesystem identities, command exit status, and any validation performed. Avoid printing sensitive paths or data into broadly retained logs. If a later process needs an ordinary independent data copy, state that requirement explicitly and verify it using the relevant storage platform’s semantics.
Use --reflink=auto when the clone is opportunistic, --reflink=always when lack of clone support must stop the workflow, and --reflink=never when the cp process must not request reflink behavior. In every mode, keep integrity validation, application consistency, backup independence, sparse-file policy, and atomic publication as separate engineering decisions.
Related:
- Btrfs Copy-on-Write and Snapshots: What Is Shared, What Changes, and What Can Fail
- mv in Production: Rename Atomicity, Cross-Filesystem Copies, and Safe Publication
Sources: