diff -up linux-5.19.7-200.fc36.x86_64/fs/pipe.c.pipe_fd_sigio_poll_hup linux-5.19.7-200.fc36.x86_64/fs/pipe.c --- linux-5.19.7-200.fc36.x86_64/fs/pipe.c.pipe_fd_sigio_poll_hup 2022-09-05 09:31:36.000000000 +0100 +++ linux-5.19.7-200.fc36.x86_64/fs/pipe.c 2022-09-07 21:09:14.075204459 +0100 @@ -233,7 +233,7 @@ pipe_read(struct kiocb *iocb, struct iov size_t total_len = iov_iter_count(to); struct file *filp = iocb->ki_filp; struct pipe_inode_info *pipe = filp->private_data; - bool was_full, wake_next_reader = false; + bool was_full, empty, wake_next_reader = false; ssize_t ret; /* Null read succeeds. */ @@ -382,10 +382,15 @@ pipe_read(struct kiocb *iocb, struct iov was_full = pipe_full(pipe->head, pipe->tail, pipe->max_usage); wake_next_reader = true; } - if (pipe_empty(pipe->head, pipe->tail)) + + if ((empty = pipe_empty(pipe->head, pipe->tail))) wake_next_reader = false; + __pipe_unlock(pipe); + if ( empty && pipe->fasync_readers && !pipe->writers ) + kill_fasync(&pipe->fasync_readers, SIGIO, POLL_HUP); + if (was_full) wake_up_interruptible_sync_poll(&pipe->wr_wait, EPOLLOUT | EPOLLWRNORM); if (wake_next_reader) @@ -592,7 +597,15 @@ out: */ if (was_empty || pipe->poll_usage) wake_up_interruptible_sync_poll(&pipe->rd_wait, EPOLLIN | EPOLLRDNORM); - kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); + + if (pipe->fasync_readers ) + { + if (ret > 0) + kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); + else if (!pipe->writers) + kill_fasync(&pipe->fasync_readers, SIGIO, POLL_HUP); + } + if (wake_next_writer) wake_up_interruptible_sync_poll(&pipe->wr_wait, EPOLLOUT | EPOLLWRNORM); if (ret > 0 && sb_start_write_trylock(file_inode(filp)->i_sb)) { @@ -715,6 +728,7 @@ static int pipe_release(struct inode *inode, struct file *file) { struct pipe_inode_info *pipe = file->private_data; + unsigned int head, tail; __pipe_lock(pipe); if (file->f_mode & FMODE_READ) @@ -726,8 +740,16 @@ pipe_release(struct inode *inode, struct if (!pipe->readers != !pipe->writers) { wake_up_interruptible_all(&pipe->rd_wait); wake_up_interruptible_all(&pipe->wr_wait); - kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); - kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); + head = READ_ONCE(pipe->head); + tail = READ_ONCE(pipe->tail); + if ( pipe_empty(head,tail) && !pipe->writers ) + kill_fasync(&pipe->fasync_readers, SIGIO, POLL_HUP); + else if (pipe->fasync_readers) + kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); + if ( (!pipe->readers) && pipe->fasync_writers) + kill_fasync(&pipe->fasync_writers, SIGIO, POLL_HUP); + else if (pipe->fasync_writers) + kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); } __pipe_unlock(pipe);