|
|
b1d0b3 |
From 4ae2eb88fadc256ddf9862b2e72ed216ddbb919d Mon Sep 17 00:00:00 2001
|
|
|
b1d0b3 |
From: michael brey <michael.brey@oracle.com>
|
|
|
b1d0b3 |
Date: Tue, 20 May 2014 14:49:44 +0200
|
|
|
b1d0b3 |
Subject: [PATCH] Fix a CDB race
|
|
|
b1d0b3 |
|
|
|
b1d0b3 |
Report and reproducer here:
|
|
|
b1d0b3 |
https://community.oracle.com/thread/3514381
|
|
|
b1d0b3 |
|
|
|
b1d0b3 |
From: michael brey <michael.brey@oracle.com>
|
|
|
b1d0b3 |
To: Lubomir Rintel <lkundrak@v3.sk>
|
|
|
b1d0b3 |
Subject: Re: BDB crash
|
|
|
b1d0b3 |
Date: Tue, 13 May 2014 09:07:45 -0600 (05/13/2014 05:07:45 PM)
|
|
|
b1d0b3 |
Message-id: <53723541.7040203@oracle.com>
|
|
|
b1d0b3 |
|
|
|
b1d0b3 |
attached are patches for each release. the 5.3.28 patch will apply on
|
|
|
b1d0b3 |
top of 5.3.21.
|
|
|
b1d0b3 |
|
|
|
b1d0b3 |
thanks
|
|
|
b1d0b3 |
mike
|
|
|
b1d0b3 |
|
|
|
b1d0b3 |
RHBZ: #1099509
|
|
|
b1d0b3 |
---
|
|
|
b1d0b3 |
src/env/env_failchk.c | 24 ++++++++++++++++++++++++
|
|
|
b1d0b3 |
src/mutex/mut_tas.c | 18 +++++++++++++++++-
|
|
|
b1d0b3 |
2 files changed, 41 insertions(+), 1 deletion(-)
|
|
|
b1d0b3 |
|
|
|
b1d0b3 |
diff --git a/src/env/env_failchk.c b/src/env/env_failchk.c
|
|
|
b1d0b3 |
index 05752f0..b09df96 100644
|
|
|
b1d0b3 |
--- a/src/env/env_failchk.c
|
|
|
b1d0b3 |
+++ b/src/env/env_failchk.c
|
|
|
b1d0b3 |
@@ -312,6 +312,7 @@ __env_in_api(env)
|
|
|
b1d0b3 |
REGINFO *infop;
|
|
|
b1d0b3 |
THREAD_INFO *thread;
|
|
|
b1d0b3 |
u_int32_t i;
|
|
|
b1d0b3 |
+ pid_t pid;
|
|
|
b1d0b3 |
int unpin, ret;
|
|
|
b1d0b3 |
|
|
|
b1d0b3 |
if ((htab = env->thr_hashtab) == NULL)
|
|
|
b1d0b3 |
@@ -325,6 +326,7 @@ __env_in_api(env)
|
|
|
b1d0b3 |
|
|
|
b1d0b3 |
for (i = 0; i < env->thr_nbucket; i++)
|
|
|
b1d0b3 |
SH_TAILQ_FOREACH(ip, &htab[i], dbth_links, __db_thread_info) {
|
|
|
b1d0b3 |
+ pid = ip->dbth_pid;
|
|
|
b1d0b3 |
if (ip->dbth_state == THREAD_SLOT_NOT_IN_USE ||
|
|
|
b1d0b3 |
(ip->dbth_state == THREAD_OUT &&
|
|
|
b1d0b3 |
thread->thr_count < thread->thr_max))
|
|
|
b1d0b3 |
@@ -341,6 +343,28 @@ __env_in_api(env)
|
|
|
b1d0b3 |
ip->dbth_state = THREAD_SLOT_NOT_IN_USE;
|
|
|
b1d0b3 |
continue;
|
|
|
b1d0b3 |
}
|
|
|
b1d0b3 |
+ /*
|
|
|
b1d0b3 |
+ * The above tests are not atomic, so it is possible that
|
|
|
b1d0b3 |
+ * the process pointed by ip has changed during the tests.
|
|
|
b1d0b3 |
+ * In particular, if the process pointed by ip when is_alive
|
|
|
b1d0b3 |
+ * was executed terminated normally, a new process may reuse
|
|
|
b1d0b3 |
+ * the same ip structure and change its dbth_state before the
|
|
|
b1d0b3 |
+ * next two tests were performed. Therefore, we need to test
|
|
|
b1d0b3 |
+ * here that all four tests above are done on the same process.
|
|
|
b1d0b3 |
+ * If the process pointed by ip changed, all tests are invalid
|
|
|
b1d0b3 |
+ * and can be ignored.
|
|
|
b1d0b3 |
+ * Similarly, it's also possible for two processes racing to
|
|
|
b1d0b3 |
+ * change the dbth_state of the same ip structure. For example,
|
|
|
b1d0b3 |
+ * both process A and B reach the above test for the same
|
|
|
b1d0b3 |
+ * terminated process C where C's dbth_state is THREAD_OUT.
|
|
|
b1d0b3 |
+ * If A goes into the 'if' block and changes C's dbth_state to
|
|
|
b1d0b3 |
+ * THREAD_SLOT_NOT_IN_USE before B checks the condition, B
|
|
|
b1d0b3 |
+ * would incorrectly fail the test and run into this line.
|
|
|
b1d0b3 |
+ * Therefore, we need to check C's dbth_state again and fail
|
|
|
b1d0b3 |
+ * the db only if C's dbth_state is indeed THREAD_ACTIVE.
|
|
|
b1d0b3 |
+ */
|
|
|
b1d0b3 |
+ if (ip->dbth_state != THREAD_ACTIVE || ip->dbth_pid != pid)
|
|
|
b1d0b3 |
+ continue;
|
|
|
b1d0b3 |
return (__db_failed(env, DB_STR("1507",
|
|
|
b1d0b3 |
"Thread died in Berkeley DB library"),
|
|
|
b1d0b3 |
ip->dbth_pid, ip->dbth_tid));
|
|
|
b1d0b3 |
diff --git a/src/mutex/mut_tas.c b/src/mutex/mut_tas.c
|
|
|
b1d0b3 |
index 0899d23..db95030 100644
|
|
|
b1d0b3 |
--- a/src/mutex/mut_tas.c
|
|
|
b1d0b3 |
+++ b/src/mutex/mut_tas.c
|
|
|
b1d0b3 |
@@ -151,10 +151,26 @@ loop: /* Attempt to acquire the resource for N spins. */
|
|
|
b1d0b3 |
if (F_ISSET(dbenv, DB_ENV_FAILCHK) &&
|
|
|
b1d0b3 |
ip == NULL && dbenv->is_alive(dbenv,
|
|
|
b1d0b3 |
mutexp->pid, mutexp->tid, 0) == 0) {
|
|
|
b1d0b3 |
+ /*
|
|
|
b1d0b3 |
+ * The process owing the mutex is "dead" now, but it may
|
|
|
b1d0b3 |
+ * have already released the mutex. We need to check again
|
|
|
b1d0b3 |
+ * by going back to the top of the loop
|
|
|
b1d0b3 |
+ * if the mutex is still held by the "dead" process. We
|
|
|
b1d0b3 |
+ * yield 10 us to increase the likelyhood of mutexp fields
|
|
|
b1d0b3 |
+ * being up-to-date. Set spin so we spin one more time
|
|
|
b1d0b3 |
+ * because no need to spin more if dead process owns mutex.
|
|
|
b1d0b3 |
+ */
|
|
|
b1d0b3 |
+ if (nspins > 1) {
|
|
|
b1d0b3 |
+ nspins = 2;
|
|
|
b1d0b3 |
+ __os_yield(env, 0, 10);
|
|
|
b1d0b3 |
+ continue;
|
|
|
b1d0b3 |
+ }
|
|
|
b1d0b3 |
ret = __env_set_state(env, &ip, THREAD_VERIFY);
|
|
|
b1d0b3 |
if (ret != 0 ||
|
|
|
b1d0b3 |
- ip->dbth_state == THREAD_FAILCHK)
|
|
|
b1d0b3 |
+ ip->dbth_state == THREAD_FAILCHK) {
|
|
|
b1d0b3 |
+ printf("mut_tas:172, pid: %d, flag: %d\n", mutexp->pid, mutexp->flags);
|
|
|
b1d0b3 |
return (DB_RUNRECOVERY);
|
|
|
b1d0b3 |
+ }
|
|
|
b1d0b3 |
}
|
|
|
b1d0b3 |
if (nowait)
|
|
|
b1d0b3 |
return (DB_LOCK_NOTGRANTED);
|
|
|
b1d0b3 |
--
|
|
|
b1d0b3 |
1.8.3.1
|
|
|
b1d0b3 |
|