Fix nesting tdb_traverse in a transaction
authorVolker Lendecke <vl@samba.org>
Tue, 20 May 2008 19:54:36 +0000 (21:54 +0200)
committerJeremy Allison <jra@samba.org>
Tue, 20 May 2008 21:20:42 +0000 (14:20 -0700)
Calling tdb_traverse inside a transaction led to the transaction lock being
held indefinitely. This was caused by the tdb_transaction_lock/unlock inside
tdb_traverse: The transaction code holds the global lock at offset
TRANSACTION_LOCK. The call to tdb_transaction_lock does nothing because the
transaction_lock is already being held. tdb_transaction_unlock inside tdb_wrap
resets tdb->have_transaction_lock but does not release the kernel-level fcntl
lock. transaction_commit later on does not release that fcntl lock either,
because tdb->have_transaction_lock was already reset by tdb_transaction().

This patch does fix that problem for me. An alternative would be to make
tdb->have_transaction_lock a counter that can cope with proper nesting, maybe
in other places as well.

Volker
(This used to be commit 89543005fe2e4934b3c560c937d49304a32a7fc2)

source4/lib/tdb/common/traverse.c

index 07b0c238587eb85fe3945b61b71dbd9dd0729d58..5a31742e7b548a28cd71c6587e57b5fc168eaf6c 100644 (file)
@@ -232,20 +232,25 @@ int tdb_traverse(struct tdb_context *tdb,
 {
        struct tdb_traverse_lock tl = { NULL, 0, 0, F_WRLCK };
        int ret;
+       int in_transaction = (tdb->transaction != NULL);
 
        if (tdb->read_only || tdb->traverse_read) {
                return tdb_traverse_read(tdb, fn, private_data);
        }
        
-       if (tdb_transaction_lock(tdb, F_WRLCK)) {
-               return -1;
+       if (!in_transaction) {
+               if (tdb_transaction_lock(tdb, F_WRLCK)) {
+                       return -1;
+               }
        }
 
        tdb->traverse_write++;
        ret = tdb_traverse_internal(tdb, fn, private_data, &tl);
        tdb->traverse_write--;
 
-       tdb_transaction_unlock(tdb);
+       if (!in_transaction) {
+               tdb_transaction_unlock(tdb);
+       }
 
        return ret;
 }