X-Git-Url: https://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Ftdb2%2Fcheck.c;h=ecd6c13c5394bc97e2b4e923cf3bdc2ca5110fc2;hp=ab6621ea85b4596aa192c3b53a9dc1aab73de366;hb=836119375a6c477747bc85a4a384a98599610f73;hpb=024fbb5f9682d3187b65849948c372c3879ed9bd diff --git a/ccan/tdb2/check.c b/ccan/tdb2/check.c index ab6621ea..ecd6c13c 100644 --- a/ccan/tdb2/check.c +++ b/ccan/tdb2/check.c @@ -31,11 +31,12 @@ static bool append(tdb_off_t **arr, size_t *num, tdb_off_t off) } static enum TDB_ERROR check_header(struct tdb_context *tdb, tdb_off_t *recovery, - uint64_t *features) + uint64_t *features, size_t *num_capabilities) { uint64_t hash_test; struct tdb_header hdr; enum TDB_ERROR ecode; + tdb_off_t off, next; ecode = tdb_read_convert(tdb, 0, &hdr, sizeof(hdr)); if (ecode != TDB_SUCCESS) { @@ -81,6 +82,24 @@ static enum TDB_ERROR check_header(struct tdb_context *tdb, tdb_off_t *recovery, } } + for (off = hdr.capabilities; off && ecode == TDB_SUCCESS; off = next) { + const struct tdb_capability *cap; + enum TDB_ERROR err; + + cap = tdb_access_read(tdb, off, sizeof(*cap), true); + if (TDB_PTR_IS_ERR(cap)) { + return TDB_PTR_ERR(cap); + } + + /* All capabilities are unknown. */ + err = unknown_capability(tdb, "tdb_check", cap->type); + next = cap->next; + tdb_access_release(tdb, cap); + if (err) + return err; + (*num_capabilities)++; + } + /* Don't check reserved: they *can* be used later. */ return TDB_SUCCESS; } @@ -94,7 +113,7 @@ static enum TDB_ERROR check_hash_tree(struct tdb_context *tdb, size_t *num_found, enum TDB_ERROR (*check)(TDB_DATA, TDB_DATA, void *), - void *private_data); + void *data); static enum TDB_ERROR check_hash_chain(struct tdb_context *tdb, tdb_off_t off, @@ -105,7 +124,7 @@ static enum TDB_ERROR check_hash_chain(struct tdb_context *tdb, enum TDB_ERROR (*check)(TDB_DATA, TDB_DATA, void *), - void *private_data) + void *data) { struct tdb_used_record rec; enum TDB_ERROR ecode; @@ -141,20 +160,20 @@ static enum TDB_ERROR check_hash_chain(struct tdb_context *tdb, off += sizeof(rec); ecode = check_hash_tree(tdb, off, 0, hash, 64, - used, num_used, num_found, check, private_data); + used, num_used, num_found, check, data); if (ecode != TDB_SUCCESS) { return ecode; } off = tdb_read_off(tdb, off + offsetof(struct tdb_chain, next)); if (TDB_OFF_IS_ERR(off)) { - return off; + return TDB_OFF_TO_ERR(off); } if (off == 0) return TDB_SUCCESS; (*num_found)++; return check_hash_chain(tdb, off, hash, used, num_used, num_found, - check, private_data); + check, data); } static enum TDB_ERROR check_hash_record(struct tdb_context *tdb, @@ -167,14 +186,14 @@ static enum TDB_ERROR check_hash_record(struct tdb_context *tdb, enum TDB_ERROR (*check)(TDB_DATA, TDB_DATA, void *), - void *private_data) + void *data) { struct tdb_used_record rec; enum TDB_ERROR ecode; if (hprefix_bits >= 64) return check_hash_chain(tdb, off, hprefix, used, num_used, - num_found, check, private_data); + num_found, check, data); ecode = tdb_read_convert(tdb, off, &rec, sizeof(rec)); if (ecode != TDB_SUCCESS) { @@ -210,7 +229,7 @@ static enum TDB_ERROR check_hash_record(struct tdb_context *tdb, return check_hash_tree(tdb, off, TDB_SUBLEVEL_HASH_BITS-TDB_HASH_GROUP_BITS, hprefix, hprefix_bits, - used, num_used, num_found, check, private_data); + used, num_used, num_found, check, data); } static int off_cmp(const tdb_off_t *a, const tdb_off_t *b) @@ -237,7 +256,7 @@ static enum TDB_ERROR check_hash_tree(struct tdb_context *tdb, size_t *num_found, enum TDB_ERROR (*check)(TDB_DATA, TDB_DATA, void *), - void *private_data) + void *data) { unsigned int g, b; const tdb_off_t *hash; @@ -318,7 +337,7 @@ static enum TDB_ERROR check_hash_tree(struct tdb_context *tdb, + group_bits + TDB_HASH_GROUP_BITS, used, num_used, num_found, - check, private_data); + check, data); if (ecode != TDB_SUCCESS) { goto fail; } @@ -401,7 +420,7 @@ static enum TDB_ERROR check_hash_tree(struct tdb_context *tdb, check: if (check) { - TDB_DATA key, data; + TDB_DATA k, d; const unsigned char *kptr; kptr = tdb_access_read(tdb, @@ -414,10 +433,10 @@ static enum TDB_ERROR check_hash_tree(struct tdb_context *tdb, goto fail; } - key = tdb_mkdata(kptr, rec_key_length(&rec)); - data = tdb_mkdata(kptr + key.dsize, - rec_data_length(&rec)); - ecode = check(key, data, private_data); + k = tdb_mkdata(kptr, rec_key_length(&rec)); + d = tdb_mkdata(kptr + k.dsize, + rec_data_length(&rec)); + ecode = check(k, d, data); tdb_access_release(tdb, kptr); if (ecode != TDB_SUCCESS) { goto fail; @@ -435,18 +454,18 @@ fail: static enum TDB_ERROR check_hash(struct tdb_context *tdb, tdb_off_t used[], - size_t num_used, size_t num_ftables, - int (*check)(TDB_DATA, TDB_DATA, void *), - void *private_data) + size_t num_used, size_t num_other_used, + enum TDB_ERROR (*check)(TDB_DATA, TDB_DATA, void *), + void *data) { - /* Free tables also show up as used. */ - size_t num_found = num_ftables; + /* Free tables and capabilities also show up as used. */ + size_t num_found = num_other_used; enum TDB_ERROR ecode; ecode = check_hash_tree(tdb, offsetof(struct tdb_header, hashtable), TDB_TOPLEVEL_HASH_BITS-TDB_HASH_GROUP_BITS, 0, 0, used, num_used, &num_found, - check, private_data); + check, data); if (ecode == TDB_SUCCESS) { if (num_found != num_used) { ecode = tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR, @@ -478,8 +497,8 @@ static enum TDB_ERROR check_free(struct tdb_context *tdb, } - ecode = tdb->methods->oob(tdb, off - + frec_len(frec) + ecode = tdb->tdb2.io->oob(tdb, off, + frec_len(frec) + sizeof(struct tdb_used_record), false); if (ecode != TDB_SUCCESS) { @@ -533,10 +552,12 @@ static enum TDB_ERROR check_free_table(struct tdb_context *tdb, h = bucket_off(ftable_off, i); for (off = tdb_read_off(tdb, h); off; off = f.next) { - if (!first) - first = off; if (TDB_OFF_IS_ERR(off)) { - return off; + return TDB_OFF_TO_ERR(off); + } + if (!first) { + off &= TDB_OFF_MASK; + first = off; } ecode = tdb_read_convert(tdb, off, &f, sizeof(f)); if (ecode != TDB_SUCCESS) { @@ -585,9 +606,9 @@ tdb_off_t dead_space(struct tdb_context *tdb, tdb_off_t off) for (len = 0; off + len < tdb->file->map_size; len++) { char c; - ecode = tdb->methods->tread(tdb, off, &c, 1); + ecode = tdb->tdb2.io->tread(tdb, off, &c, 1); if (ecode != TDB_SUCCESS) { - return ecode; + return TDB_ERR_TO_OFF(ecode); } if (c != 0 && c != 0x43) break; @@ -632,7 +653,7 @@ static enum TDB_ERROR check_linear(struct tdb_context *tdb, } else { len = dead_space(tdb, off); if (TDB_OFF_IS_ERR(len)) { - return len; + return TDB_OFF_TO_ERR(len); } if (len < sizeof(rec.r)) { return tdb_logerr(tdb, TDB_ERR_CORRUPT, @@ -696,7 +717,8 @@ static enum TDB_ERROR check_linear(struct tdb_context *tdb, } else if (rec_magic(&rec.u) == TDB_USED_MAGIC || rec_magic(&rec.u) == TDB_CHAIN_MAGIC || rec_magic(&rec.u) == TDB_HTABLE_MAGIC - || rec_magic(&rec.u) == TDB_FTABLE_MAGIC) { + || rec_magic(&rec.u) == TDB_FTABLE_MAGIC + || rec_magic(&rec.u) == TDB_CAP_MAGIC) { uint64_t klen, dlen, extra; /* This record is used! */ @@ -732,7 +754,8 @@ static enum TDB_ERROR check_linear(struct tdb_context *tdb, /* Check that records have correct 0 at end (but may * not in future). */ - if (extra && !features) { + if (extra && !features + && rec_magic(&rec.u) != TDB_CAP_MAGIC) { const char *p; char c; p = tdb_access_read(tdb, off + sizeof(rec.u) @@ -772,15 +795,27 @@ static enum TDB_ERROR check_linear(struct tdb_context *tdb, } enum TDB_ERROR tdb_check_(struct tdb_context *tdb, - enum TDB_ERROR (*check)(TDB_DATA key, TDB_DATA data, - void *private_data), - void *private_data) + enum TDB_ERROR (*check)(TDB_DATA, TDB_DATA, void *), + void *data) { tdb_off_t *fr = NULL, *used = NULL, ft, recovery; - size_t num_free = 0, num_used = 0, num_found = 0, num_ftables = 0; + size_t num_free = 0, num_used = 0, num_found = 0, num_ftables = 0, + num_capabilities = 0; uint64_t features; enum TDB_ERROR ecode; + if (tdb->flags & TDB_CANT_CHECK) { + return tdb_logerr(tdb, TDB_SUCCESS, TDB_LOG_WARNING, + "tdb_check: database has unknown capability," + " cannot check."); + } + + if (tdb->flags & TDB_VERSION1) { + if (tdb1_check(tdb, check, data) == -1) + return tdb->last_error; + return TDB_SUCCESS; + } + ecode = tdb_allrecord_lock(tdb, F_RDLCK, TDB_LOCK_WAIT, false); if (ecode != TDB_SUCCESS) { return tdb->last_error = ecode; @@ -792,7 +827,7 @@ enum TDB_ERROR tdb_check_(struct tdb_context *tdb, return tdb->last_error = ecode; } - ecode = check_header(tdb, &recovery, &features); + ecode = check_header(tdb, &recovery, &features, &num_capabilities); if (ecode != TDB_SUCCESS) goto out; @@ -804,7 +839,7 @@ enum TDB_ERROR tdb_check_(struct tdb_context *tdb, for (ft = first_ftable(tdb); ft; ft = next_ftable(tdb, ft)) { if (TDB_OFF_IS_ERR(ft)) { - ecode = ft; + ecode = TDB_OFF_TO_ERR(ft); goto out; } ecode = check_free_table(tdb, ft, num_ftables, fr, num_free, @@ -815,8 +850,8 @@ enum TDB_ERROR tdb_check_(struct tdb_context *tdb, } /* FIXME: Check key uniqueness? */ - ecode = check_hash(tdb, used, num_used, num_ftables, check, - private_data); + ecode = check_hash(tdb, used, num_used, num_ftables + num_capabilities, + check, data); if (ecode != TDB_SUCCESS) goto out;