summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_lockf.c
diff options
context:
space:
mode:
authorjeff <jeff@FreeBSD.org>2008-03-19 07:13:24 +0000
committerjeff <jeff@FreeBSD.org>2008-03-19 07:13:24 +0000
commit4cd4553bb53da6eff2e16385db01ba95bd7d7266 (patch)
treec6e3b7daf968664cd89e965811151abeab9c38fa /sys/kern/kern_lockf.c
parente846a1612b584a4d896189eb9ece9b3fa61d3878 (diff)
downloadFreeBSD-src-4cd4553bb53da6eff2e16385db01ba95bd7d7266.zip
FreeBSD-src-4cd4553bb53da6eff2e16385db01ba95bd7d7266.tar.gz
- Fix the last of the threading bugs that were introduced as far back as
1.38 in 2001. Break out of the FOREACH_THREAD_IN_PROC loop when we've discovered a new proc in the chain. - Increment i and check for maxlockdepth once per matching process not once per thread. This didn't properly terminate the loop before. - Fix a bug which has existed potentially since rev 1.1. waitblock->lf_next can be NULL when a thread has been woken-up but not yet scheduled. Check for this condition rather than blindly dereferencing. Found by: libMicro
Diffstat (limited to 'sys/kern/kern_lockf.c')
-rw-r--r--sys/kern/kern_lockf.c18
1 files changed, 12 insertions, 6 deletions
diff --git a/sys/kern/kern_lockf.c b/sys/kern/kern_lockf.c
index 6cce5aa..95ac99d 100644
--- a/sys/kern/kern_lockf.c
+++ b/sys/kern/kern_lockf.c
@@ -286,28 +286,34 @@ restart:
PROC_LOCK(wproc);
FOREACH_THREAD_IN_PROC(wproc, td) {
thread_lock(td);
- while (td->td_wchan &&
- (td->td_wmesg == lockstr) &&
- (i++ < maxlockdepth)) {
+ for (;;) {
+ if (!TD_ON_SLEEPQ(td) ||
+ td->td_wmesg != lockstr)
+ break;
waitblock = (struct lockf *)td->td_wchan;
/* Get the owner of the blocking lock */
+ if (waitblock->lf_next == NULL)
+ break;
waitblock = waitblock->lf_next;
if ((waitblock->lf_flags & F_POSIX) == 0)
break;
- nproc = (struct proc *)waitblock->lf_id;
- if (nproc == (struct proc *)lock->lf_id) {
+ if (waitblock->lf_id == lock->lf_id) {
thread_unlock(td);
PROC_UNLOCK(wproc);
lock->lf_next = *clean;
*clean = lock;
return (EDEADLK);
}
+ nproc = (struct proc *)waitblock->lf_id;
+ break;
}
thread_unlock(td);
+ if (nproc)
+ break;
}
PROC_UNLOCK(wproc);
wproc = nproc;
- if (wproc)
+ if (++i < maxlockdepth && wproc)
goto restart;
}
/*
OpenPOWER on IntegriCloud