public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: "Michael Kerrisk" <mtk-manpages@gmx.net>
To: Jens Axboe <axboe@suse.de>
Cc: linux-kernel@vger.kernel.org
Subject: splice() and file offsets
Date: Mon, 10 Jul 2006 14:11:10 +0200	[thread overview]
Message-ID: <20060710121110.26260@gmx.net> (raw)

Jens,

What are the semantics of splice() supposed to be with respect 
to the current file offsets of 'fd_in' and 'fd_out', and how
is the presence or absence (NULL) of 'off_in' and 'off_out'
supposed to affect things.

Using the program below, here is what I observe for 
fd_out/off_out:

1. If off_out is NULL, then 
   a) splice() changes the current file offset of fd_out.

2. If off_out is not NULL, then splice() 
   a) does not change the current file offset of fd_out, but 
   b) treats off_out as a value result parameter, returning 
      an updated offset of the file.

It is "2 a)" that surprises me.  But perhaps it's expected 
behaviour; or I'm doing something dumb in my test program.

If the test program is run without a third command-line 
argument, then 'off_out' is specified as NULL, and we see:

$ find .. | ./t_splice out
splice() returned 69632
After splice(), offset of fd is: 69632; off_out = 0
splice() returned 32768
After splice(), offset of fd is: 102400; off_out = 0
splice() returned 100000
After splice(), offset of fd is: 202400; off_out = 0
splice() returned 14688
After splice(), offset of fd is: 217088; off_out = 0
splice() returned 31990
After splice(), offset of fd is: 249078; off_out = 0
splice() returned 0
After splice(), offset of fd is: 249078; off_out = 0

If the test program is run with a third command-line 
argument, then 'off_out' is initialised to 0, and then
supplied as an argument on each splice() call, and we 
see:

$ find .. | ./t_splice out x
splice() returned 20480
After splice(), offset of fd is: 0; off_out = 20480
splice() returned 49152
After splice(), offset of fd is: 0; off_out = 69632
splice() returned 100000
After splice(), offset of fd is: 0; off_out = 169632
splice() returned 35168
After splice(), offset of fd is: 0; off_out = 204800
splice() returned 44278
After splice(), offset of fd is: 0; off_out = 249078
splice() returned 0
After splice(), offset of fd is: 0; off_out = 249078

Cheers,

Michael

/* t_splice.c */

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <errno.h>
#include <limits.h>

#if defined(__i386__)
#define __NR_splice     313
#define __NR_tee        315
#else
#error unsupported arch
#endif

#define SPLICE_F_MOVE   (0x01)  /* move pages instead of copying */
#define SPLICE_F_NONBLOCK (0x02) /* don't block on the pipe splicing (but */
                                 /* we may still block on the fd we splice */
                                 /* from/to, of course */
#define SPLICE_F_MORE   (0x04)  /* expect more data */
#define SPLICE_F_GIFT   (0x08)  /* pages passed in are a gift */


static inline int splice(int fdin, loff_t *off_in, int fdout,
                         loff_t *off_out, size_t len, unsigned int flags)
{
    return syscall(__NR_splice, fdin, off_in, fdout, off_out, len, flags);
}

static inline int tee(int fdin, int fdout, size_t len, unsigned int flags)
{
    return syscall(__NR_tee, fdin, fdout, len, flags);
}

int
main(int argc, char *argv[])
{
    int fd;
    int slen;
    loff_t off_out;

    assert(argc >= 2);

    fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) {
        perror("open");
        exit(EXIT_FAILURE);
    }

    off_out = 0;
    for (;;) {
        slen = splice(STDIN_FILENO, NULL, fd,
                (argc > 2) ? &off_out : NULL, 100000, 0);
        if (slen < 0) {
            perror("splice");
            break;
        }
        fprintf(stderr, "splice() returned %ld\n", (long) slen);
        fprintf(stderr, "After splice(), offset of fd is: %lld; "
                "off_out = %lld\n",
                (long long) lseek(fd, 0, SEEK_CUR),
                (long long) off_out);
        if (slen == 0)
            break;
    }

    close(fd);
    exit(EXIT_SUCCESS);
}

-- 
Michael Kerrisk
maintainer of Linux man pages Sections 2, 3, 4, 5, and 7 

Want to help with man page maintenance?  
Grab the latest tarball at
ftp://ftp.win.tue.nl/pub/linux-local/manpages/, 
read the HOWTOHELP file and grep the source 
files for 'FIXME'.

             reply	other threads:[~2006-07-10 12:11 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-07-10 12:11 Michael Kerrisk [this message]
2006-07-10 12:51 ` splice() and file offsets Jens Axboe
2006-07-10 13:07   ` Michael Kerrisk
2006-07-10 13:25     ` Jens Axboe
2006-07-10 13:54       ` Michael Kerrisk
2006-07-10 14:22         ` Jens Axboe
2006-07-10 15:48           ` Michael Kerrisk
2006-07-10 16:51             ` Jens Axboe

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20060710121110.26260@gmx.net \
    --to=mtk-manpages@gmx.net \
    --cc=axboe@suse.de \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox