[PATCHv2] Use sendfile to copy data between file descriptors

Denys Vlasenko vda.linux at googlemail.com
Wed Nov 26 15:06:30 UTC 2014


On Mon, Oct 20, 2014 at 2:56 PM, Bartosz Golaszewski
<bartekgola at gmail.com> wrote:
> +#if ENABLE_FEATURE_USE_SENDFILE
> +#include <sys/sendfile.h>
> +#endif
> +
> +/*
> + * Returns 1 if all bytes have been copied, 0 otherwise.
> + */
> +static int check_status(int *status, off_t *size, off_t *total, ssize_t rd)
> +{
> +       *total += rd;
> +       if (*status < 0) { /* if we aren't copying till EOF... */
> +               *size -= rd;
> +               if (!(*size)) {
> +                       /* 'size' bytes copied - all done */
> +                       *status = 0;
> +                       return 1;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
>  /* Used by NOFORK applets (e.g. cat) - must not use xmalloc.
>   * size < 0 means "ignore write errors", used by tar --to-command
>   * size = 0 means "copy till EOF"
> @@ -18,6 +40,7 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
>         int status = -1;
>         off_t total = 0;
>         bool continue_on_write_error = 0;
> +       ssize_t rd;
>  #if CONFIG_FEATURE_COPYBUF_KB <= 4
>         char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024];
>         enum { buffer_size = sizeof(buffer) };
> @@ -56,10 +79,29 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
>                 status = 1; /* copy until eof */
>         }
>
> -       while (1) {
> -               ssize_t rd;
> +#if ENABLE_FEATURE_USE_SENDFILE
> +       {
> +               ssize_t sz = size && (size < buffer_size)
> +                               ? size : MAXINT(ssize_t) - 0xffff;
>
> -               rd = safe_read(src_fd, buffer, size > buffer_size ? buffer_size : size);
> +               while (1) {
> +                       rd = sendfile(dst_fd, src_fd, NULL, sz);
> +                       if (rd <= 0) {
> +                               /* Might be EOF, might be an error,
> +                                * to make sure fall back to the read-write
> +                                * loop.
> +                                */
> +                               break;
> +                       } else if (check_status(&status, &size, &total, rd)) {
> +                               break;
> +                       }
> +               }
> +       }

Looks like it will always allocate the copy buffer,
and always attempt the final read, even if sendfile worked perfectly.
Can this be avoided?


More information about the busybox mailing list