diff options
author | David Howells <dhowells@redhat.com> | 2019-09-24 18:09:04 +0300 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2019-11-15 19:22:54 +0300 |
commit | b667b867344301e24f21d4a4c844675ff61d89e1 (patch) | |
tree | eb01278af88b386a56fee12ced51cb1764d70aaa /fs/pipe.c | |
parent | 6718b6f855a0b4962d54bd625be2718cb820cec6 (diff) | |
download | linux-b667b867344301e24f21d4a4c844675ff61d89e1.tar.xz |
pipe: Advance tail pointer inside of wait spinlock in pipe_read()
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>
Diffstat (limited to 'fs/pipe.c')
-rw-r--r-- | fs/pipe.c | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/fs/pipe.c b/fs/pipe.c index 69afeab8a73a..ea134f69a292 100644 --- 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); } |