From: Rusty Russell Date: Mon, 13 Sep 2010 09:08:20 +0000 (+0930) Subject: tdb: fix tdb_check() on read-only TDBs to actually work. X-Git-Url: https://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=ba2cc03f0648101ca0be687ae70947e7ae331f4c tdb: fix tdb_check() on read-only TDBs to actually work. But make sure we can still do tdb_check() inside a transaction (weird, but we previously allowed it). --- diff --git a/ccan/tdb/check.c b/ccan/tdb/check.c index c5469e99..a9a9ece0 100644 --- a/ccan/tdb/check.c +++ b/ccan/tdb/check.c @@ -327,9 +327,17 @@ int tdb_check(struct tdb_context *tdb, struct tdb_record rec; bool found_recovery = false; tdb_len_t dead; - - if (tdb_lockall_read(tdb) == -1) - return -1; + bool locked; + + /* Read-only databases use no locking at all: it's best-effort. + * We may have a write lock already, so skip that case too. */ + if (tdb->read_only || tdb->allrecord_lock.count != 0) { + locked = false; + } else { + if (tdb_lockall_read(tdb) == -1) + return -1; + locked = true; + } /* Make sure we know true size of the underlying file. */ tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1); @@ -444,12 +452,16 @@ int tdb_check(struct tdb_context *tdb, } free(hashes); - tdb_unlockall_read(tdb); + if (locked) { + tdb_unlockall_read(tdb); + } return 0; free: free(hashes); unlock: - tdb_unlockall_read(tdb); + if (locked) { + tdb_unlockall_read(tdb); + } return -1; } diff --git a/ccan/tdb/test/run-readonly-check.c b/ccan/tdb/test/run-readonly-check.c new file mode 100644 index 00000000..87cdd643 --- /dev/null +++ b/ccan/tdb/test/run-readonly-check.c @@ -0,0 +1,53 @@ +/* We should be able to tdb_check a O_RDONLY tdb, and we were previously allowed + * to tdb_check() inside a transaction (though that's paranoia!). */ +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "logging.h" + +int main(int argc, char *argv[]) +{ + struct tdb_context *tdb; + TDB_DATA key, data; + + plan_tests(11); + tdb = tdb_open_ex("run-readonly-check.tdb", 1024, + TDB_DEFAULT, + O_CREAT|O_TRUNC|O_RDWR, 0600, &taplogctx, NULL); + + ok1(tdb); + key.dsize = strlen("hi"); + key.dptr = (void *)"hi"; + data.dsize = strlen("world"); + data.dptr = (void *)"world"; + + ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0); + ok1(tdb_check(tdb, NULL, NULL) == 0); + + /* We are also allowed to do a check inside a transaction. */ + ok1(tdb_transaction_start(tdb) == 0); + ok1(tdb_check(tdb, NULL, NULL) == 0); + ok1(tdb_close(tdb) == 0); + + tdb = tdb_open_ex("run-readonly-check.tdb", 1024, + TDB_DEFAULT, O_RDONLY, 0, &taplogctx, NULL); + + ok1(tdb); + ok1(tdb_store(tdb, key, data, TDB_MODIFY) == -1); + ok1(tdb_error(tdb) == TDB_ERR_RDONLY); + ok1(tdb_check(tdb, NULL, NULL) == 0); + ok1(tdb_close(tdb) == 0); + + return exit_status(); +}