pipe: Advance tail pointer inside of wait spinlock in pipe_read()
authorDavid Howells <dhowells@redhat.com>
Tue, 24 Sep 2019 15:09:04 +0000 (16:09 +0100)
committerDavid Howells <dhowells@redhat.com>
Fri, 15 Nov 2019 16:22:54 +0000 (16:22 +0000)
Advance the pipe ring tail pointer inside of wait spinlock in pipe_read()
so that the pipe can be written into with kernel notifications from
contexts where pipe->mutex cannot be taken.

Signed-off-by: David Howells <dhowells@redhat.com>
fs/pipe.c

index 69afeab..ea134f6 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -325,9 +325,14 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to)
 
                        if (!buf->len) {
                                pipe_buf_release(pipe, buf);
+                               spin_lock_irq(&pipe->wait.lock);
                                tail++;
                                pipe->tail = tail;
-                               do_wakeup = 1;
+                               do_wakeup = 0;
+                               wake_up_interruptible_sync_poll_locked(
+                                       &pipe->wait, EPOLLOUT | EPOLLWRNORM);
+                               spin_unlock_irq(&pipe->wait.lock);
+                               kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
                        }
                        total_len -= chars;
                        if (!total_len)
@@ -359,6 +364,7 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to)
                if (do_wakeup) {
                        wake_up_interruptible_sync_poll(&pipe->wait, EPOLLOUT | EPOLLWRNORM);
                        kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
+                       do_wakeup = 0;
                }
                pipe_wait(pipe);
        }