Re: [RESEND PATCH] fs/pipe: Introduce a check to skip sleeping processes during pipe read/write

From: Oleg Nesterov
Date: Thu Jan 02 2025 - 08:58:31 EST


On 12/31, Linus Torvalds wrote:
>
> On Tue, 31 Dec 2024 at 12:25, Oleg Nesterov <oleg@xxxxxxxxxx> wrote:
> >
> > But let me ask another question right now. what do you think about another
> > minor change below?
>
> Probably ok. Although I'm not convinced it makes things any more readable.

OK, lets forget it for now.

> > Again, mostly to make this logic more understandable. Although I am not
> > sure I really understand it...
>
> So see commit fe67f4dd8daa ("pipe: do FASYNC notifications for every
> pipe IO, not just state changes") on why that crazy poll_usage thing
> exists.

Ah. Yes, yes, thanks, I have already read this commit/changelog, because
I was confused by the unconditional kill_fasync()'s in pipe_read/write.
So I guess I mostly understand the "edge-triggered" issues.

As for epoll, I even wrote the stupid test-case:

int main(void)
{
int pfd[2], efd;
struct epoll_event evt = { .events = EPOLLIN | EPOLLET };

pipe(pfd);
efd = epoll_create1(0);
epoll_ctl(efd, EPOLL_CTL_ADD, pfd[0], &evt);

for (int i = 0; i < 2; ++i) {
write(pfd[1], "", 1);
assert(epoll_wait(efd, &evt, 1, 0) == 1);
}

return 0;
}

without the pipe->poll_usage check in pipe_write() assert() fails on the
2nd iteration. BTW, I think pipe_write() needs READ_ONCE(pipe->poll_usage),
KCSAN can complain.

> The
>
> #ifdef CONFIG_EPOLL
>
> addition is straightforward enough and matches the existing comment.
>
> But you adding the FMODE_READ test should probably get a new comment
> about how we only do this for epoll readability, not for writability..

Agreed. perhaps I'll try to make V2 later...

The unconditional WRITE_ONCE(pipe->poll_usage) in pipe_poll() may hide
some subtle race between pipe_write() and the "normal" select/poll, that
is why I'd like to make ->poll_usage depend on filp->f_ep != NULL.

Thanks!

Oleg.