Page MenuHomeFreeBSD

pipe: Use a distinct wait channel for I/O serialization
ClosedPublic

Authored by markj on Jun 6 2022, 6:15 PM.
Tags
None
Referenced Files
Unknown Object (File)
Thu, Nov 7, 6:37 AM
Unknown Object (File)
Thu, Nov 7, 6:28 AM
Unknown Object (File)
Wed, Oct 30, 5:53 PM
Unknown Object (File)
Oct 11 2024, 7:29 AM
Unknown Object (File)
Oct 11 2024, 7:11 AM
Unknown Object (File)
Oct 11 2024, 12:57 AM
Unknown Object (File)
Oct 1 2024, 2:14 AM
Unknown Object (File)
Sep 26 2024, 7:49 AM
Subscribers

Details

Summary

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(), one 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.

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

Reported by: Paul Floyd
PR: 264441

Test Plan

I have a test program which can reproduce the problem. A couple
of test cases from the Valgrind regression test suite also trigger
the bug.

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 45870
Build 42758: arc lint + arc unit