Subject: bug#31038: mv copies in ls -r order

From: Eric Blake <[email-masked]>
Date: Tue, 3 Apr 2018 09:52:36 -0500

On 04/03/2018 09:37 AM, 積丹尼 Dan Jacobson wrote:
> OK maybe I was just looking at the latter half of
> 
> $ sh O
> /tmp
> created directory '/var/tmp/y'
> copied 'x/1' -> '/var/tmp/y/1'
> copied 'x/2' -> '/var/tmp/y/2'
> copied 'x/3' -> '/var/tmp/y/3'
> copied 'x/4' -> '/var/tmp/y/4'
> copied 'x/5' -> '/var/tmp/y/5'
> copied 'x/6' -> '/var/tmp/y/6'
> copied 'x/7' -> '/var/tmp/y/7'
> copied 'x/8' -> '/var/tmp/y/8'
> copied 'x/9' -> '/var/tmp/y/9'
> removed 'x/9'
> removed 'x/8'
> removed 'x/7'
> removed 'x/6'
> removed 'x/5'
> removed 'x/4'
> removed 'x/3'
> removed 'x/2'
> removed 'x/1'

Ah, so you're questioning the behavior of cross-volume moves, rather
than same-volume (where mv has to do separate non-atomic steps instead
of letting rename(2) do all the work).  Please, when you report
something, GIVE ALL THE DETAILS up front, rather than making us play
guessing games at how to reproduce things.

> removed directory 'x'
> $ cat O
> set -eu
> cd /tmp
> mkdir x
> cd x
> seq 9|xargs touch
> cd -
> mv -v x /var/tmp/y

That is NOT the same command that you documented in your original report
(where you used a glob); rather, it is a single directory name, where mv
has to recurse itself.

Note that you have entirely changed the question from what I answered in
the previous mail.  My claim that POSIX requires mv to process things in
command line order is still true, but here, the command line order is
only a single directory, and there is no requirement in POSIX at the
order of the contents within the directory are handled, only that all
files within the directory eventually get reached.

In fact, there is no reason at all that file names in a cross-volume
move have to be visited in any particular order, so our choice is to
favor any order that is demonstratably faster, followed by any order
that is easier to code.  It's easier to process directory entries in
readdir() order (which is NOT necessarily sorted by filename); the only
reason to perform the copies in an order different from readdir() order
is if sorting things gives better performance (in fact, we've found that
sorting files, not by name order, but by inode number, tends to give
speedups for rotating disks, where visiting files in incrementing inode
order tends to be faster than visiting files in readdir() order).  But
when it comes to removing files, we have to perform bookkeeping in order
to carefully track which files need to be removed; and in that case, a
LIFO list is the simplest coding technique.

So, in your particular example, you touched nine files in order (which
probably had the side effect that readdir() order, name order, and inode
order all matched); once all nine files have been copied (using
whichever order was most efficient, although for your example all three
orders likely happened to be the same), then the removal is done by
processing the internal list of what still needs work, and that list
happens to be easiest in reverse order.

Still, I stand by my claim that this is not a bug, and that there is
nothing to change unless you can provide a benchmark that shows that
doing things in a different order offers a noticeable speedup.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org