splice: reinstate SIGPIPE/EPIPE handling
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 21 Dec 2016 18:59:34 +0000 (10:59 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 21 Dec 2016 18:59:34 +0000 (10:59 -0800)
Commit 8924feff66f3 ("splice: lift pipe_lock out of splice_to_pipe()")
caused a regression when there were no more readers left on a pipe that
was being spliced into: rather than the expected SIGPIPE and -EPIPE
return value, the writer would end up waiting forever for space to free
up (which obviously was not going to happen with no readers around).

Fixes: 8924feff66f3 ("splice: lift pipe_lock out of splice_to_pipe()")
Reported-and-tested-by: Andreas Schwab <schwab@linux-m68k.org>
Debugged-by: Al Viro <viro@zeniv.linux.org.uk>
Cc: stable@kernel.org # v4.9
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
fs/splice.c

index 8ed7c9d8c0fbaf7ec81de0afa9ac3edafe8932aa..873d83104e79aed14a24c417f211e38ae4038122 100644 (file)
@@ -1087,7 +1087,13 @@ EXPORT_SYMBOL(do_splice_direct);
 
 static int wait_for_space(struct pipe_inode_info *pipe, unsigned flags)
 {
-       while (pipe->nrbufs == pipe->buffers) {
+       for (;;) {
+               if (unlikely(!pipe->readers)) {
+                       send_sig(SIGPIPE, current, 0);
+                       return -EPIPE;
+               }
+               if (pipe->nrbufs != pipe->buffers)
+                       return 0;
                if (flags & SPLICE_F_NONBLOCK)
                        return -EAGAIN;
                if (signal_pending(current))
@@ -1096,7 +1102,6 @@ static int wait_for_space(struct pipe_inode_info *pipe, unsigned flags)
                pipe_wait(pipe);
                pipe->waiting_writers--;
        }
-       return 0;
 }
 
 static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,