From: Rusty Russell Date: Mon, 15 Nov 2010 07:25:45 +0000 (+1030) Subject: tdb2: fix coalesce race #3 X-Git-Url: https://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=06a5b1a852c207a5172922e39d8effab0dd17b91 tdb2: fix coalesce race #3 When we're coalescing, we need to drop the lock on the current free list, as we've enlarged the block and it may now belong in a different list. Unfortunately (as shown by repeated tdbtorture -n 8) another coalescing run can do the coalescing while we've dropped the lock. So for this case, we use the TDB_COALESCING_MAGIC flag so it doesn't look free. --- diff --git a/ccan/tdb2/free.c b/ccan/tdb2/free.c index df2792ec..c5a0c40e 100644 --- a/ccan/tdb2/free.c +++ b/ccan/tdb2/free.c @@ -347,7 +347,17 @@ static int coalesce(struct tdb_context *tdb, if (remove_from_list(tdb, b_off, off, r) == -1) goto err; - /* We have to drop this to avoid deadlocks. */ + r = tdb_access_write(tdb, off, sizeof(*r), true); + if (!r) + goto err; + + /* We have to drop this to avoid deadlocks, so make sure record + * doesn't get coalesced by someone else! */ + r->magic_and_meta = TDB_COALESCING_MAGIC | zone_bits; + r->data_len = end - off - sizeof(struct tdb_used_record); + if (tdb_access_commit(tdb, r) != 0) + goto err; + tdb_unlock_free_bucket(tdb, b_off); if (add_free_record(tdb, zone_bits, off, end - off) == -1)