On Sun Jan 17, 2021 at 5:46 AM NZDT, Johannes Berg wrote: > On Sat, 2021-01-16 at 20:35 +1300, Oliver Giles wrote: > > Commit 36e2c7421f02 (fs: don't allow splice read/write without > > explicit ops) broke my userspace application which talks to an SSL VPN > > by splice()ing between "openssl s_client" and "pppd". The latter > > operates over a pty, and since that commit there is no fallback for > > splice()ing between a pipe and a pty, or any tty for that matter. > > > > The above commit mentions switching them to the iter ops and using > > generic_file_splice_read. IIUC, this would require implementing iter > > ops also on the line disciplines, which sounds pretty disruptive. > > > > For my case, I attempted to instead implement splice_write and > > splice_read in tty_fops; I managed to get splice_write working calling > > ld->ops->write, but splice_read is not so simple because the > > tty_ldisc_ops read method expects a userspace buffer. So I cannot see > > how to implement this without either (a) using set_fs, or (b) > > implementing iter ops on all line disciplines. > > > > Is splice()ing between a tty and a pipe worth supporting at all? Not a > > big deal for my use case at least, but it used to work. > > Is it even strictly related to the tty? > > I was just now looking into why my cgit/fcgi/nginx setup no longer > works, and the reason is getting -EINVAL from sendfile() when the input > is a file and the output is a pipe(). > > So I wrote a simple test program (below) and that errors out on kernel > 5.10.4, while it works fine on the 5.9.16 I currently have. Haven't > tried reverting anything yet, but now that I haev a test program it > should be simple to even bisect. > > johannes > > > #include <unistd.h> > #include <sys/types.h> > #include <sys/stat.h> > #include <fcntl.h> > #include <sys/sendfile.h> > #include <stdio.h> > #include <assert.h> > > int main(int argc, char **argv) > { > int in = open(argv[0], O_RDONLY); > int p[2], out; > off_t off = 0; > int err; > > assert(in >= 0); > assert(pipe(p) >= 0); > out = p[1]; > err = sendfile(out, in, &off, 1024); > if (err < 0) > perror("sendfile"); > assert(err == 1024); > > return 0; > }
I can confirm the behaviour you see, and that it starts occurring from the same commit 36e2c7421f02a22 (fs: don't allow splice read/write without explicit ops). In my tty case, it is clear that removing the default fallback would cause this to fail, but assuming the sendfile() source is on a regular filesystem, I am unsure why splice cannot find the appropriate splice_write method. Could be connected to the fact that the message from warn_unsupported in fs/splice.c outputs "splice write not supported for file (pid: 983819 comm: test-sendfile)", i.e. the file path is blank. In my case of directly calling splice on a pty, I do see a path such as /ptyp0 in that error before implementing splice_(read/write) callbacks. Maybe splice is getting a bogus file pointer from sendfile?