diff mbox series

pipe: fix empty pipe check in pipe_write()

Message ID 65b22cd4e8bb142c5b7b86bc33fb08de6f318089.1577017472.git.jstancek@redhat.com (mailing list archive)
State New, archived
Headers show
Series pipe: fix empty pipe check in pipe_write() | expand

Commit Message

Jan Stancek Dec. 22, 2019, 12:33 p.m. UTC
LTP pipeio_1 test is hanging with v5.5-rc2-385-gb8e382a185eb,
with read side observing empty pipe and sleeping and write
side running out of space and then sleeping as well. In this
scenario there are 5 writers and 1 reader.

Problem is that after pipe_write() reacquires pipe lock, it
re-checks for empty pipe with potentially stale 'head' and
doesn't wake up read side anymore. pipe->tail can advance
beyond 'head', because there are multiple writers.

Use pipe->head for empty pipe check after reacquiring lock
to observe current state.

Testing: With patch, LTP pipeio_1 ran successfully in loop for 1 hour.
         Without patch it hanged within a minute.

Fixes: 1b6b26ae7053 ("pipe: fix and clarify pipe write wakeup logic")
Reported-by: Rachel Sibley <rasibley@redhat.com>
Signed-off-by: Jan Stancek <jstancek@redhat.com>
---
 fs/pipe.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Linus Torvalds Dec. 22, 2019, 5:50 p.m. UTC | #1
On Sun, Dec 22, 2019 at 4:35 AM Jan Stancek <jstancek@redhat.com> wrote:
> Problem is that after pipe_write() reacquires pipe lock, it
> re-checks for empty pipe with potentially stale 'head' and
> doesn't wake up read side anymore. pipe->tail can advance
> beyond 'head', because there are multiple writers.

Thank you. Patch is obviously correct, applied.

I wonder how much that whole "cache head/tail/mask" really helps, and
if we should strive to get rid of it entirely (and just make
"pipe_emptuy()" and friends take a 'const struct pipe_inode_info *"
argument).

Oh well.  I've apple your one-liner, but next time I might decide the
cleverness and slight code generation advantage might not be worth it.

Hopefully there won't _be_ a next time, of course ;)

             Linus
diff mbox series

Patch

diff --git a/fs/pipe.c b/fs/pipe.c
index 04d004ee2e8c..57502c3c0fba 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -581,7 +581,7 @@  static inline bool pipe_writable(const struct pipe_inode_info *pipe)
 		}
 		wait_event_interruptible(pipe->wait, pipe_writable(pipe));
 		__pipe_lock(pipe);
-		was_empty = pipe_empty(head, pipe->tail);
+		was_empty = pipe_empty(pipe->head, pipe->tail);
 	}
 out:
 	__pipe_unlock(pipe);