]> git.ozlabs.org Git - ccan/blobdiff - ccan/tdb2/check.c
tdb2: fix coalesce race #3
[ccan] / ccan / tdb2 / check.c
index 1ce75be065f4317b1e63a4c2bc1afb47e446478b..f3fff5f6b8e25a99b0d34682b92788a28ea48c6a 100644 (file)
@@ -45,14 +45,15 @@ static bool check_header(struct tdb_context *tdb)
        if (hdr.hash_test != hash_test) {
                tdb->log(tdb, TDB_DEBUG_ERROR, tdb->log_priv,
                         "check: hash test %llu should be %llu\n",
-                        hdr.hash_test, hash_test);
+                        (long long)hdr.hash_test,
+                        (long long)hash_test);
                return false;
        }
 
        if (strcmp(hdr.magic_food, TDB_MAGIC_FOOD) != 0) {
                tdb->log(tdb, TDB_DEBUG_ERROR, tdb->log_priv,
                         "check: bad magic '%.*s'\n",
-                        sizeof(hdr.magic_food), hdr.magic_food);
+                        (unsigned)sizeof(hdr.magic_food), hdr.magic_food);
                return false;
        }
 
@@ -263,7 +264,7 @@ static bool check_hash(struct tdb_context *tdb,
 
        if (!check_hash_tree(tdb, offsetof(struct tdb_header, hashtable),
                             TDB_TOPLEVEL_HASH_BITS-TDB_HASH_GROUP_BITS,
-                            0, 0,  used, num_used, &num_found))
+                            0, 0, used, num_used, &num_found))
                return false;
 
        if (num_found != num_used) {
@@ -287,8 +288,8 @@ static bool check_free(struct tdb_context *tdb,
                return false;
        }
        if (tdb->methods->oob(tdb, off
-                             + frec->data_len-sizeof(struct tdb_used_record),
-                             true))
+                             + frec->data_len+sizeof(struct tdb_used_record),
+                             false))
                return false;
        if (off < zone_off || off >= zone_off + (1ULL<<frec_zone_bits(frec))) {
                tdb->log(tdb, TDB_DEBUG_ERROR, tdb->log_priv,
@@ -336,11 +337,11 @@ static tdb_len_t check_free_list(struct tdb_context *tdb,
                h = bucket_off(zone_off, i);
                for (off = tdb_read_off(tdb, h); off; off = f.next) {
                        if (off == TDB_OFF_ERR)
-                               return false;
+                               return TDB_OFF_ERR;
                        if (tdb_read_convert(tdb, off, &f, sizeof(f)))
-                               return false;
+                               return TDB_OFF_ERR;
                        if (!check_free(tdb, off, &f, prev, zone_off, i))
-                               return false;
+                               return TDB_OFF_ERR;
 
                        /* FIXME: Check hash bits */
                        p = asearch(&off, free, num_free, off_cmp);
@@ -350,7 +351,7 @@ static tdb_len_t check_free_list(struct tdb_context *tdb,
                                         "tdb_check: Invalid offset"
                                         " %llu in free table\n",
                                         (long long)off);
-                               return false;
+                               return TDB_OFF_ERR;
                        }
                        /* Mark it invalid. */
                        *p ^= 1;
@@ -406,7 +407,8 @@ static tdb_off_t check_zone(struct tdb_context *tdb, tdb_off_t zone_off,
                p = tdb_get(tdb, off, &pad, sizeof(pad));
                if (!p)
                        return TDB_OFF_ERR;
-               if (frec_magic(&p->f) == TDB_FREE_MAGIC) {
+               if (frec_magic(&p->f) == TDB_FREE_MAGIC
+                   || frec_magic(&p->f) == TDB_COALESCING_MAGIC) {
                        if (frec_zone_bits(&p->f) != zhdr.zone_bits) {
                                tdb->log(tdb, TDB_DEBUG_ERROR, tdb->log_priv,
                                         "tdb_check: Bad free zone bits %u"
@@ -415,9 +417,6 @@ static tdb_off_t check_zone(struct tdb_context *tdb, tdb_off_t zone_off,
                                         (long long)off);
                                return TDB_OFF_ERR;
                        }
-                       /* This record is free! */
-                       if (!append(free, num_free, off))
-                               return TDB_OFF_ERR;
                        len = sizeof(p->u) + p->f.data_len;
                        if (off + len > zone_off + (1ULL << zhdr.zone_bits)) {
                                tdb->log(tdb, TDB_DEBUG_ERROR, tdb->log_priv,
@@ -426,6 +425,10 @@ static tdb_off_t check_zone(struct tdb_context *tdb, tdb_off_t zone_off,
                                         (long long)len, (long long)off);
                                return TDB_OFF_ERR;
                        }
+                       /* This record is free! */
+                       if (frec_magic(&p->f) == TDB_FREE_MAGIC
+                           && !append(free, num_free, off))
+                               return TDB_OFF_ERR;
                } else {
                        uint64_t klen, dlen, extra;
 
@@ -487,7 +490,6 @@ int tdb_check(struct tdb_context *tdb,
        unsigned max_zone_bits = INITIAL_ZONE_BITS;
        uint8_t tailer;
 
-       /* This always ensures the header is uptodate. */
        if (tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, false) != 0)
                return -1;