On Fri, Mar 12, 2021 at 02:30:17AM +0100, David Disseldorp wrote:
> This change sees --reflink behave similar to coreutils cp
> --reflink=auto. The kernel may attempt a copy-on-write clone of the
> range and may fallback to splice. cpio fallback to regular read/write
> is needed in case the source and destination reside on separate
> filesystems.
> 
> Signed-off-by: David Disseldorp <[email protected]>
> ---
>  src/copyin.c  |  2 +-
>  src/copyout.c | 33 ++++++++++++++++++++++++++++++---
>  2 files changed, 31 insertions(+), 4 deletions(-)
> 
> diff --git a/src/copyin.c b/src/copyin.c
> index c8ea278..f6d7292 100644
> --- a/src/copyin.c
> +++ b/src/copyin.c
> @@ -510,7 +510,7 @@ copyin_regular_file (struct cpio_file_stat* file_hdr, int 
> in_file_des)
>      }
>    copy_files_tape_to_disk (in_file_des, out_file_des, file_hdr->c_filesize);
>    disk_empty_output_buffer (out_file_des, true);
> -  
> +
>    if (to_stdout_option)
>      {
>        if (archive_format == arf_crcascii)
> diff --git a/src/copyout.c b/src/copyout.c
> index 5ca587f..076478e 100644
> --- a/src/copyout.c
> +++ b/src/copyout.c
> @@ -718,9 +718,36 @@ process_copy_out ()
>  
>             if (write_out_header (&file_hdr, out_file_des))
>               continue;
> -           copy_files_disk_to_tape (in_file_des,
> -                                    out_file_des, file_hdr.c_filesize,
> -                                    orig_file_name);
> +#ifdef HAVE_CPIO_REFLINK
> +           /*
> +            * copy_file_range(2) should only be used if:
> +            * - it has explicitly been requested via --reflink
> +            * - crc calculations for aren't needed
> +            * - output is a regular seekable file
> +            */
> +           if (reflink_flag && !crc_i_flag && output_is_seekable)
> +             {
> +               ssize_t ret;
> +               /* flush output buffer before copy_file_range I/O */
> +               tape_empty_output_buffer (out_file_des);
> +                  ret = copy_files_range (in_file_des,

(nit: spaces/tabs inconsistent here?)

> +                                       out_file_des,
> +                                       file_hdr.c_filesize);
> +               /* -EXDEV: can't use copy_file_range, fallback to read/write 
> */
> +               if (ret == -EXDEV)
> +                 copy_files_disk_to_tape (in_file_des,
> +                                          out_file_des, file_hdr.c_filesize,
> +                                          orig_file_name);
> +               else if (ret < 0)
> +                 error (PAXEXIT_FAILURE, -ret, _("copy_file_range failed."));

Maybe you could log the error but, instead of exiting, simply try the
copy_file_disk_to_tape() instead of doing so only if -EXDEV.  This is
particularly relevant because in copy_files_range() you're doing:

    ...
    ret = copy_file_range(...);
    /* simplify read/write fallback: don't partially seek on error */
    if (ret == 0)
      return -ENODATA;

(Unfortunately, not doing the seek() on error will force the full
read+write instead of trying to continue if there was already some data
copied.  But yeah it greatly simplifies things too.)

Cheers,
--
Luís

> +             }
> +           else
> +#endif /* HAVE_CPIO_REFLINK */
> +             {
> +               copy_files_disk_to_tape (in_file_des,
> +                                        out_file_des, file_hdr.c_filesize,
> +                                        orig_file_name);
> +             }
>             warn_if_file_changed(orig_file_name, file_hdr.c_filesize,
>                                     file_hdr.c_mtime);
>  
> -- 
> 2.26.2
> 

Reply via email to