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 <lhenriq...@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 >