bug-cpio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [RFC] Add copy_file_range syscall support


From: Luis Henriques
Subject: Re: [RFC] Add copy_file_range syscall support
Date: Mon, 20 Jul 2020 11:50:53 +0100

Hi Sergey,

I forgot to include you on CC for this RFC patch.  Explicitly pinging you
now.  Please let me know your thoughts about adding support for this on
cpio.

Cheers,
-- 
Luis

Luis Henriques <lhenriques@suse.de> writes:

> Hi!
>
> I'm sharing a quick hack to cpio that adds support for using the linux
> copy_file_range(2) syscall when doing a disk_to_disk copy ('pass-through'
> mode).
>
> My very limited testing on running this patch on a filesystem that
> supports this syscall (btrfs) showed a nice performance improvement, but
> this is just a very early hack to try to get some feedback on whether this
> would be something other people would like to see merged in.
>
> Cheers,
> --
> Luís
>
> ---
>  configure.ac   |  2 +-
>  src/copypass.c |  4 ++++
>  src/extern.h   |  2 ++
>  src/util.c     | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 58 insertions(+), 1 deletion(-)
>
> diff --git a/configure.ac b/configure.ac
> index 9f81a4730cd1..79c1533a7a1c 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -48,7 +48,7 @@ AC_HEADER_DIRENT
>  AC_COMPILE_CHECK_RETTYPE([major], [0])
>  AC_COMPILE_CHECK_RETTYPE([minor], [0])
>  
> -AC_CHECK_FUNCS([fchmod fchown])
> +AC_CHECK_FUNCS([fchmod fchown copy_file_range])
>  # This is needed for mingw build
>  AC_CHECK_FUNCS([setmode getpwuid getpwnam getgrgid getgrnam pipe fork getuid 
> geteuid])
>  
> diff --git a/src/copypass.c b/src/copypass.c
> index 3b0104fef784..9987a58bd4f8 100644
> --- a/src/copypass.c
> +++ b/src/copypass.c
> @@ -188,8 +188,12 @@ process_copy_pass ()
>                 continue;
>               }
>  
> +#ifdef HAVE_COPY_FILE_RANGE
> +           copy_files_range (in_file_des, out_file_des, 
> in_file_stat.st_size, input_name.ds_string);
> +#else
>             copy_files_disk_to_disk (in_file_des, out_file_des, 
> in_file_stat.st_size, input_name.ds_string);
>             disk_empty_output_buffer (out_file_des, true);
> +#endif /* HAVE_COPY_FILE_RANGE */
>             
>             set_copypass_perms (out_file_des,
>                                 output_name.ds_string, &in_file_stat);
> diff --git a/src/extern.h b/src/extern.h
> index ad05e78a1ae9..981045ef93ef 100644
> --- a/src/extern.h
> +++ b/src/extern.h
> @@ -170,6 +170,8 @@ void tape_toss_input (int in_des, off_t num_bytes);
>  void copy_files_tape_to_disk (int in_des, int out_des, off_t num_bytes);
>  void copy_files_disk_to_tape (int in_des, int out_des, off_t num_bytes, char 
> *filename);
>  void copy_files_disk_to_disk (int in_des, int out_des, off_t num_bytes, char 
> *filename);
> +void copy_files_range (int in_des, int out_des, off_t num_bytes, char 
> *filename);
> +
>  void warn_if_file_changed (char *file_name, off_t old_file_size,
>                             time_t old_file_mtime);
>  void create_all_directories (char const *name);
> diff --git a/src/util.c b/src/util.c
> index c44a17b2cd07..9dd0be537294 100644
> --- a/src/util.c
> +++ b/src/util.c
> @@ -516,6 +516,57 @@ copy_files_disk_to_tape (int in_des, int out_des, off_t 
> num_bytes,
>        in_buff += size;
>      }
>  }
> +
> +#ifdef HAVE_COPY_FILE_RANGE
> +void
> +copy_files_range (int in_des, int out_des, off_t num_bytes,
> +               char *filename)
> +{
> +  loff_t in_off = 0, out_off = 0;
> +  off_t next_start, next_end;
> +  ssize_t total = 0;
> +  ssize_t ret;
> +
> +  while (in_off < num_bytes)
> +    {
> +      next_start = lseek (in_des, in_off, SEEK_DATA);
> +      if (next_start < 0)
> +     {
> +       /* Hole at the end of the file */
> +       if (errno == ENXIO)
> +         {
> +           if (ftruncate (out_des, num_bytes) < 0)
> +             error (PAXEXIT_FAILURE, errno, _("Failed ftruncate"));
> +           in_off = num_bytes;
> +           break;
> +         }
> +       error (PAXEXIT_FAILURE, errno, _("Can't seek to data in file"));
> +     }
> +      next_end = lseek (in_des, next_start, SEEK_HOLE);
> +      if (next_end < 0)
> +     error (PAXEXIT_FAILURE, errno, _("Can't seek to hole in file"));
> +      in_off = out_off = next_start;
> +      ret = copy_file_range (in_des, &in_off, out_des, &out_off,
> +                          (next_end - next_start), 0);
> +      if (ret < 0)
> +     {
> +       error (0, errno, _("copy_file_range failed."));
> +       break;
> +     }
> +      total += ret;
> +    }
> +
> +  if (in_off < num_bytes)
> +    {
> +      lseek (in_des, in_off, SEEK_SET);
> +      lseek (out_des, in_off, SEEK_SET);
> +      copy_files_disk_to_disk (in_des, out_des, (num_bytes - in_off),
> +                            filename);
> +      disk_empty_output_buffer (out_des, true);
> +    }
> +}
> +#endif /* HAVE_COPY_FILE_RANGE */
> +
>  /* Copy a file using the input and output buffers, which may start out
>     partly full.  After the copy, the files are not closed nor the last
>     block flushed to output, and the input buffer may still be partly
>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]