From 8321967a3b0917b9b1ac4cbc3cda2ace881a886f Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 22 Feb 2010 22:54:26 +1030 Subject: [PATCH] tdb: fix recovery reuse after crash (from SAMBA) commit b37b452cb8c1f56b37b04abe7bffdede371ca361 Author: Rusty Russell Date: Thu Feb 4 23:59:54 2010 +1030 tdb: fix recovery reuse after crash If a process (or the machine) dies after just after writing the recovery head (pointing at the end of file), the recovery record will filled with 0x42. This will not invoke a recovery on open, since rec.magic != TDB_RECOVERY_MAGIC. Unfortunately, the first transaction commit will happily reuse that area: tdb_recovery_allocate() doesn't check the magic. The recovery record has length 0x42424242, and it writes that back into the now-valid-looking transaction header) for the next comer (which happens to be tdb_wipe_all in my tests). Signed-off-by: Rusty Russell --- ccan/tdb/transaction.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/ccan/tdb/transaction.c b/ccan/tdb/transaction.c index fc0ca1d9..238034f3 100644 --- a/ccan/tdb/transaction.c +++ b/ccan/tdb/transaction.c @@ -683,10 +683,16 @@ static int tdb_recovery_allocate(struct tdb_context *tdb, rec.rec_len = 0; - if (recovery_head != 0 && - methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) { - TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery record\n")); - return -1; + if (recovery_head != 0) { + if (methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) { + TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to read recovery record\n")); + return -1; + } + /* ignore invalid recovery regions: can happen in crash */ + if (rec.magic != TDB_RECOVERY_MAGIC && + rec.magic != TDB_RECOVERY_INVALID_MAGIC) { + recovery_head = 0; + } } *recovery_size = tdb_recovery_size(tdb); -- 2.39.2