diff options
author | Volker Lendecke <vl@samba.org> | 2015-07-06 13:13:36 +0200 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2015-07-09 00:42:15 +0200 |
commit | 1061a9cafda7d73ebcd2f74e69e74f4adc485d5d (patch) | |
tree | 2746679ff5fa9959091b1582fa39caa15d4caaf7 /lib | |
parent | be9c4f90331a244c50543d080db769a94e01d77b (diff) | |
download | samba-1061a9cafda7d73ebcd2f74e69e74f4adc485d5d.tar.gz |
tdb: Fix bug 11381, deadlock
This fixes a deadlock in tdb that is a bad interaction between tdb_lockall
and tdb_traverse. This deadlock condition has been around even before
tdb mutexes, it's just that the kernel fcntl EDEADLK detection protected
us from this ABBA lock condition to become a real deadlock stalling
processes. With tdb mutexes, this deadlock protection is gone, so we do
lock dead.
This patch glosses over this particular ABBA condition, making tdb with
mutexes behave the same as tdb without mutexes. Admittedly this is no
real fix, but it works around a real user's problem.
Bug: https://bugzilla.samba.org/show_bug.cgi?id=11381
Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/tdb/common/traverse.c | 14 |
1 files changed, 13 insertions, 1 deletions
diff --git a/lib/tdb/common/traverse.c b/lib/tdb/common/traverse.c index 618670fd1cb..e18e3c34fd3 100644 --- a/lib/tdb/common/traverse.c +++ b/lib/tdb/common/traverse.c @@ -245,13 +245,25 @@ _PUBLIC_ int tdb_traverse(struct tdb_context *tdb, tdb_traverse_func fn, void *private_data) { struct tdb_traverse_lock tl = { NULL, 0, 0, F_WRLCK }; + enum tdb_lock_flags lock_flags; int ret; if (tdb->read_only || tdb->traverse_read) { return tdb_traverse_read(tdb, fn, private_data); } - if (tdb_transaction_lock(tdb, F_WRLCK, TDB_LOCK_WAIT)) { + lock_flags = TDB_LOCK_WAIT; + + if (tdb->allrecord_lock.count != 0) { + /* + * This avoids a deadlock between tdb_lockall() and + * tdb_traverse(). See + * https://bugzilla.samba.org/show_bug.cgi?id=11381 + */ + lock_flags = TDB_LOCK_NOWAIT; + } + + if (tdb_transaction_lock(tdb, F_WRLCK, lock_flags)) { return -1; } |