Browse Source

tdb: fix recovery reuse after crash (from SAMBA)

commit b37b452cb8c1f56b37b04abe7bffdede371ca361
Author: Rusty Russell <rusty@rustcorp.com.au>
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 <rusty@rustcorp.com.au>
Rusty Russell 16 years ago
parent
commit
8321967a3b
1 changed files with 10 additions and 4 deletions
  1. 10 4
      ccan/tdb/transaction.c

+ 10 - 4
ccan/tdb/transaction.c

@@ -683,10 +683,16 @@ static int tdb_recovery_allocate(struct tdb_context *tdb,
 
 
 	rec.rec_len = 0;
 	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);
 	*recovery_size = tdb_recovery_size(tdb);