bug#80060: mv: move files across bind mounts using the rename syscall
Pádraig Brady <[email protected]> Tue, 23 Dec 2025 12:27:34 +0000
| Newsgroups | gmane.comp.gnu.core-utils.bugs |
|---|---|
| Message-ID | <[email protected]> |
On 23/12/2025 00:08, Andrei Topala wrote:
>> Is there a downside to always trying rename() first and doing the copy
>
>> if it fails? That's approximately what toybox's mv does...
>
>
> mv already tries rename() first. The problem is that rename() returns
>
> EXDEV even when source and destination are on the same physical device
>
> but accessed through different bind mount points.
>
>
> For example, with these bind mounts on the same device:
>
>
> /mnt/full root=/
>
> /mnt/data root=/data
>
>
> Moving /mnt/data/file to /mnt/full/backup/ fails with EXDEV because the
>
> kernel sees different mount points, forcing an unnecessary copy+delete.
>
>
> [1] solves this by iterating through all mount/realpath combinations
>
> until rename() succeeds. I've implemented an approach using gnulib's
>
> mountlist.h [2].
>
>
> I'm thinking of:
>
> 1. Parse /proc/self/mountinfo via read_file_system_list()
>
> 2. Find mount entries for source and destination paths
>
> 3. If different me_dev, fall back to copy (truly different devices)
>
> 4. Compute device_path = me_mntroot + path_relative_to_mountpoint
>
> 5. Translate one path through the other's mount:
>
> - If dst's device_path is under src_mount's root, translate dst
>
> - Otherwise translate src through dst_mount
>
> 6. rename() with translated path succeeds - both paths now resolve
>
> through the same mount point
>
>
> Example translation:
>
> /mnt/data/file
>
> → mount: root="/data", mountdir="/mnt/data"
>
> → device_path: /data/file
>
> → through /mnt/full (root="/"): /mnt/full/data/file
>
>
>
> rename("/mnt/full/data/file", "/mnt/full/backup/file") succeeds
>
>
> This avoids the brute-force iteration in [1] by computing which mount
>
> can "see" both paths (the one with the wider root).
>
>
> I haven't signed FSF copyright assignment yet but am willing to do so
>
> if there's interest.
>
>
> [1] https://github.com/milahu/move-files-across-bind-mounts
>
> [2]
> https://github.com/coreutils/coreutils/commit/a961fc317951b92c2468771f8a0d2895e94ac2a3
Referencing the original discussion:
https://lists.gnu.org/archive/html/coreutils/2024-12/msg00002.html
The code is good, and thanks for talking time to propose a solution.
However my conclusion from the original thread is still the same.
I don't think it's appropriate for mv to do this expensive/error prone
path manipulation for each file being copied across devices.
IMHO this is more appropriate for the kernel,
which has a more holistic view of the mount space.
thanks,
Padraig.