aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/kern_umtx.c
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2016-08-25 16:35:42 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2016-08-25 16:35:42 +0000
commit28e21133f31baeedf68af4e5432dd6d3d27c0214 (patch)
tree7a35619a5c9a9ce1a044883c2e2adda3e211df4c /sys/kern/kern_umtx.c
parent76723b39ca2fd613243b4622588cb43cd32df203 (diff)
downloadsrc-28e21133f31baeedf68af4e5432dd6d3d27c0214.tar.gz
src-28e21133f31baeedf68af4e5432dd6d3d27c0214.zip
Prevent leak of URWLOCK_READ_WAITERS flag for urwlocks.
If there was some error, e.g. the sleep was interrupted, as in the referenced PR, do_rw_rdlock() did not cleared URWLOCK_READ_WAITERS. Since unlock only wakes up write waiters when there is no read waiters, for URWLOCK_PREFER_READER kind of locks, the result was missed wakeups for writers. In particular, the most visible victims are ld-elf.so locks in processes which loaded libthr, because rtld locks are urwlocks in prefer-reader mode. Normal rwlocks fall into prefer-reader mode only if thread already owns rw lock in read mode, which is not typical and correspondingly less visible. In the PR, unowned rtld bind lock was waited for in the process where only one thread was left alive. Note that do_rw_wrlock() correctly clears URWLOCK_WRITE_WAITERS in case of errors. Reported and tested by: longwitz@incore.de PR: 211947 Sponsored by: The FreeBSD Foundation MFC after: 1 week
Notes
Notes: svn path=/head/; revision=304808
Diffstat (limited to 'sys/kern/kern_umtx.c')
-rw-r--r--sys/kern/kern_umtx.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c
index 33eb8bca43cc..51495aa23ff5 100644
--- a/sys/kern/kern_umtx.c
+++ b/sys/kern/kern_umtx.c
@@ -2743,9 +2743,12 @@ sleep:
suword32(&rwlock->rw_blocked_readers, blocked_readers-1);
if (blocked_readers == 1) {
rv = fueword32(&rwlock->rw_state, &state);
- if (rv == -1)
+ if (rv == -1) {
+ umtxq_unbusy_unlocked(&uq->uq_key);
error = EFAULT;
- while (error == 0) {
+ break;
+ }
+ for (;;) {
rv = casueword32(&rwlock->rw_state, state,
&oldstate, state & ~URWLOCK_READ_WAITERS);
if (rv == -1) {
@@ -2756,6 +2759,8 @@ sleep:
break;
state = oldstate;
error = umtxq_check_susp(td);
+ if (error != 0)
+ break;
}
}