ruby-changes:48169
From: glass <ko1@a...>
Date: Sat, 21 Oct 2017 23:25:51 +0900 (JST)
Subject: [ruby-changes:48169] glass:r60284 (trunk): io.c: introduce copy offload to IO.copy_stream
glass 2017-10-21 23:25:46 +0900 (Sat, 21 Oct 2017) New Revision: 60284 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=60284 Log: io.c: introduce copy offload to IO.copy_stream io.c (rb_io_s_copy_stream): add copy offload feature (by using copy_file_range(2) if available) to IO.copy_stream Modified files: trunk/NEWS trunk/io.c Index: NEWS =================================================================== --- NEWS (revision 60283) +++ NEWS (revision 60284) @@ -53,6 +53,7 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L53 * IO#pread [Feature #4532] * IO#pwrite [Feature #4532] + * IO#copy_stream tries copy offload with copy_file_range(2) [Feature #13867] * IOError Index: io.c =================================================================== --- io.c (revision 60283) +++ io.c (revision 60284) @@ -10489,6 +10489,113 @@ nogvl_copy_stream_wait_write(struct copy https://github.com/ruby/ruby/blob/trunk/io.c#L10489 return 0; } +#if defined __linux__ && defined __NR_copy_file_range +# define USE_COPY_FILE_RANGE +#endif + +#ifdef USE_COPY_FILE_RANGE + +static ssize_t +simple_copy_file_range(int in_fd, off_t *in_offset, int out_fd, off_t *out_offset, size_t count, unsigned int flags) +{ + return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags); +} + +static int +nogvl_copy_file_range(struct copy_stream_struct *stp) +{ + struct stat src_stat, dst_stat; + ssize_t ss; + int ret; + + off_t copy_length, src_offset, *src_offset_ptr; + + ret = fstat(stp->src_fd, &src_stat); + if (ret == -1) { + stp->syserr = "fstat"; + stp->error_no = errno; + return -1; + } + if (!S_ISREG(src_stat.st_mode)) + return 0; + + ret = fstat(stp->dst_fd, &dst_stat); + if (ret == -1) { + stp->syserr = "fstat"; + stp->error_no = errno; + return -1; + } + + src_offset = stp->src_offset; + if (src_offset != (off_t)-1) { + src_offset_ptr = &src_offset; + } + else { + src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */ + } + + copy_length = stp->copy_length; + if (copy_length == (off_t)-1) { + if (src_offset == (off_t)-1) { + off_t current_offset; + errno = 0; + current_offset = lseek(stp->src_fd, 0, SEEK_CUR); + if (current_offset == (off_t)-1 && errno) { + stp->syserr = "lseek"; + stp->error_no = errno; + return -1; + } + copy_length = src_stat.st_size - current_offset; + } + else { + copy_length = src_stat.st_size - src_offset; + } + } + + retry_copy_file_range: +# if SIZEOF_OFF_T > SIZEOF_SIZE_T + /* we are limited by the 32-bit ssize_t return value on 32-bit */ + ss = (copy_length > (off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length; +# else + ss = (ssize_t)copy_length; +# endif + ss = simple_copy_file_range(stp->src_fd, src_offset_ptr, stp->dst_fd, NULL, ss, 0); + if (0 < ss) { + stp->total += ss; + copy_length -= ss; + if (0 < copy_length) { + goto retry_copy_file_range; + } + } + if (ss == -1) { + if (maygvl_copy_stream_continue_p(0, stp)) { + goto retry_copy_file_range; + } + switch (errno) { + case EINVAL: +#ifdef ENOSYS + case ENOSYS: +#endif +#ifdef EXDEV + case EXDEV: /* in_fd and out_fd are not on the same filesystem */ +#endif + return 0; + case EAGAIN: +#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + if (nogvl_copy_stream_wait_write(stp) == -1) + return -1; + goto retry_copy_file_range; + } + stp->syserr = "copy_file_range"; + stp->error_no = errno; + return -1; + } + return 1; +} +#endif + #ifdef HAVE_SENDFILE # ifdef __linux__ @@ -10787,6 +10894,12 @@ nogvl_copy_stream_func(void *arg) https://github.com/ruby/ruby/blob/trunk/io.c#L10894 int ret; #endif +#ifdef USE_COPY_FILE_RANGE + ret = nogvl_copy_file_range(stp); + if (ret != 0) + goto finish; /* error or success */ +#endif + #ifdef USE_SENDFILE ret = nogvl_copy_stream_sendfile(stp); if (ret != 0) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/