]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/commit
pipe: Use a distinct wait channel for I/O serialization
authorMark Johnston <markj@FreeBSD.org>
Tue, 14 Jun 2022 14:52:03 +0000 (10:52 -0400)
committerMark Johnston <markj@FreeBSD.org>
Tue, 14 Jun 2022 16:00:59 +0000 (12:00 -0400)
commite8955bd643ee852d70a0b065f2a0d1bb3fa99df2
tree2b5bf76ca5092fe3b638de9a4919495eb0717633
parent116679b39cb94fdb94c02dceb1c2cae719bd3f42
pipe: Use a distinct wait channel for I/O serialization

Suppose a thread tries to read from an empty pipe.  pipe_read() does the
following:

1. pipelock(), possibly sleeping
2. check for buffered data
3. pipeunlock()
4. set PIPE_WANTR and sleep
5. goto 1

pipelock() is an open-coded mutex; if a thread blocks in pipelock(), it
sleeps until the lock holder calls pipeunlock().

Both sleeps use the same wait channel.  So if there are multiple threads
in pipe_read(), a thread T1 in step 3 can wake up a thread T2 sleeping
in step 4.  Then T1 goes to sleep in step 4, and T2 acquires and
releases the pipelock, waking up T1 again.  This can go on indefinitely,
livelocking the process (and potentially starving a would-be writer).

Fix the problem by using a separate wait channel for pipelock().

Reported by: Paul Floyd <paulf2718@gmail.com>
Reviewed by: mjg, kib
PR: 264441
MFC after: 1 month
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D35415
sys/kern/sys_pipe.c