Make `unp_msgcount' and `unp_file' atomic. Introduce `unp_rights_mtx'
authormvs <mvs@openbsd.org>
Sat, 6 Nov 2021 17:35:14 +0000 (17:35 +0000)
committermvs <mvs@openbsd.org>
Sat, 6 Nov 2021 17:35:14 +0000 (17:35 +0000)
commit46d8bbe61ce96a35f176dd10933b30d9d8adfb09
tree9f888edbe5c7f29b58c6320d925528eeabb59c54
parent9cf3bd2b34c9b752dd959b32a0fdbba1b8246c47
Make `unp_msgcount' and `unp_file' atomic. Introduce `unp_rights_mtx'
mutex(9) to protect `unp_rights'.

This removes global rwlock(9) from unp_internalize() and unp_externalize()
normal paths and leaves it in the unp_externalize() error path only. Also
we don't need to simultaneously hold fdplock() and `unp_lock' within
unp_internalize().

The `unp_rights' can't be atomic. Otherwise the thread which exceeding the
limit will break all other not-exceeding threads until it decrements
`unp_rights'. That why the mutex(9) used for protection.

It's safe to call fptounp() without `unp_lock' held. We always got this
file descriptor by fd_getfile(9) so we always have the extra reference
and this descriptor can't be closed by concurrent thread. Some sockets
could be destroyed through 'PRU_ABORT' path but they don't have
associated file descriptor and they are not accessible in the
unp_internalize() path.

The `unp_file' access without `unp_lock' held is also safe. Each socket
could have the only associated file descriptor and each file descriptor
could have the only associated socket. We only assign `unp_file' in the
unp_internalize() path where we got the socket by fd_getfile(9). This
descriptor has the extra reference and couldn't be closed concurrently.
We could override `unp_file' but with the same address because the
associated file descriptor can't be changed so the address will be also
the same. While unp_gc() concurrently runs the dereference of
non-NULL `unp_file' is always safe.

Discussed with kettenis@ and mpi@.

ok mpi@
sys/kern/uipc_usrreq.c
sys/sys/unpcb.h