Re: [PATCH 0/2] pipe: Fixes [ver #2]

From: Linus Torvalds
Date: Fri Dec 06 2019 - 15:28:38 EST


On Fri, Dec 6, 2019 at 5:56 AM David Sterba <dsterba@xxxxxxx> wrote:
>
> For reference, I've retested current master (b0d4beaa5a4b7d), that
> incldes the 2 pipe fixes, the test still hangs.

I think I found it.

TOTALLY UNTESTED patch appended. It's whitespace-damaged and may be
completely wrong. And might not fix it.

The first hunk is purely syntactic sugar - use the normal head/tail
order. The second/third hunk is what I think fixes the problem:
iter_file_splice_write() had the same buggy "let's cache
head/tail/mask" pattern as pipe_write() had.

You can't cache them over a 'pipe_wait()' that drops the pipe lock,
and there's one in splice_from_pipe_next().

Linus

--- snip snip --

diff --git a/fs/splice.c b/fs/splice.c
index f2400ce7d528..fa1f3773c8cd 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -495,7 +495,7 @@ static int splice_from_pipe_feed(struct
pipe_inode_info *pipe, struct splice_des
unsigned int mask = pipe->ring_size - 1;
int ret;

- while (!pipe_empty(tail, head)) {
+ while (!pipe_empty(head, tail)) {
struct pipe_buffer *buf = &pipe->bufs[tail & mask];

sd->len = buf->len;
@@ -711,9 +711,7 @@ iter_file_splice_write(struct pipe_inode_info
*pipe, struct file *out,
splice_from_pipe_begin(&sd);
while (sd.total_len) {
struct iov_iter from;
- unsigned int head = pipe->head;
- unsigned int tail = pipe->tail;
- unsigned int mask = pipe->ring_size - 1;
+ unsigned int head, tail, mask;
size_t left;
int n;

@@ -732,6 +730,10 @@ iter_file_splice_write(struct pipe_inode_info
*pipe, struct file *out,
}
}

+ head = pipe->head;
+ tail = pipe->tail;
+ mask = pipe->ring_size - 1;
+
/* build the vector */
left = sd.total_len;
for (n = 0; !pipe_empty(head, tail) && left && n <
nbufs; tail++, n++) {