提交 28e58ee8 编写于 作者: L Linus Torvalds

Fix broken "pipe: use event aware wakeups" optimization

Commit e462c448 ("pipe: use event aware wakeups") optimized the pipe
event wakeup calls to avoid wakeups if the events do not match the
requested set.

However, the optimization was buggy, in that it didn't actually use the
correct sets for the events: when we make room for more data to be
written, the pipe poll() routine will return both the POLLOUT _and_
POLLWRNORM bits.  Similarly for read.

And most critically, when a pipe is released, that will potentially
result in POLLHUP|POLLERR (depending on whether it was the last reader
or writer), not just the regular POLLIN|POLLOUT.

This bug showed itself as a hung gnome-screensaver-dialog process, stuck
forever (or at least until it was poked by a signal or by being traced)
in a poll() system call.

Cc: Davide Libenzi <davidel@xmailserver.org>
Cc: David S. Miller <davem@davemloft.net>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
上级 d7b9935a
...@@ -441,7 +441,7 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov, ...@@ -441,7 +441,7 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov,
break; break;
} }
if (do_wakeup) { if (do_wakeup) {
wake_up_interruptible_sync_poll(&pipe->wait, POLLOUT); wake_up_interruptible_sync_poll(&pipe->wait, POLLOUT | POLLWRNORM);
kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
} }
pipe_wait(pipe); pipe_wait(pipe);
...@@ -450,7 +450,7 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov, ...@@ -450,7 +450,7 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov,
/* Signal writers asynchronously that there is more room. */ /* Signal writers asynchronously that there is more room. */
if (do_wakeup) { if (do_wakeup) {
wake_up_interruptible_sync_poll(&pipe->wait, POLLOUT); wake_up_interruptible_sync_poll(&pipe->wait, POLLOUT | POLLWRNORM);
kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
} }
if (ret > 0) if (ret > 0)
...@@ -612,7 +612,7 @@ pipe_write(struct kiocb *iocb, const struct iovec *_iov, ...@@ -612,7 +612,7 @@ pipe_write(struct kiocb *iocb, const struct iovec *_iov,
break; break;
} }
if (do_wakeup) { if (do_wakeup) {
wake_up_interruptible_sync_poll(&pipe->wait, POLLIN); wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLRDNORM);
kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
do_wakeup = 0; do_wakeup = 0;
} }
...@@ -623,7 +623,7 @@ pipe_write(struct kiocb *iocb, const struct iovec *_iov, ...@@ -623,7 +623,7 @@ pipe_write(struct kiocb *iocb, const struct iovec *_iov,
out: out:
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
if (do_wakeup) { if (do_wakeup) {
wake_up_interruptible_sync_poll(&pipe->wait, POLLIN); wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLRDNORM);
kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
} }
if (ret > 0) if (ret > 0)
...@@ -715,7 +715,7 @@ pipe_release(struct inode *inode, int decr, int decw) ...@@ -715,7 +715,7 @@ pipe_release(struct inode *inode, int decr, int decw)
if (!pipe->readers && !pipe->writers) { if (!pipe->readers && !pipe->writers) {
free_pipe_info(inode); free_pipe_info(inode);
} else { } else {
wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLOUT); wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM | POLLERR | POLLHUP);
kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册