tdb: TDB_INCOMPATIBLE_HASH, to allow safe changing of default hash.
authorRusty Russell <rusty@rustcorp.com.au>
Fri, 24 Sep 2010 06:15:11 +0000 (15:45 +0930)
committerJeremy Allison <jra@samba.org>
Mon, 27 Sep 2010 04:55:30 +0000 (21:55 -0700)
This flag to tdb_open/tdb_open_ex effects creation of a new database:
1) Uses the Jenkins lookup3 hash instead of the old gdbm hash if none is
   specified,
2) Places a non-zero field in header->rwlocks, so older versions of TDB will
   refuse to open it.

This means that the caller (ie Samba) can set this flag to safely
change the hash function.  Versions of TDB from this one on will either
use the correct hash or refuse to open (if a different hash is specified).
Older TDB versions will see the nonzero rwlocks field and refuse to open
it under any conditions.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
(cherry picked from commit 2dcf76c9247ff02a1779000dbbecdc418473ca41)

lib/tdb/common/check.c
lib/tdb/common/open.c
lib/tdb/common/tdb_private.h
lib/tdb/configure.ac
lib/tdb/include/tdb.h
lib/tdb/wscript

index b1b98d4f1ed385a1f2c4e690f9a983296be24ad6..58c9c26540dcfb29d292e0c00bdb22bc9afc3c20 100644 (file)
@@ -39,7 +39,7 @@ static bool tdb_check_header(struct tdb_context *tdb, tdb_off_t *recovery)
        if (hdr.version != TDB_VERSION)
                goto corrupt;
 
-       if (hdr.rwlocks != 0)
+       if (hdr.rwlocks != 0 && hdr.rwlocks != TDB_HASH_RWLOCK_MAGIC)
                goto corrupt;
 
        tdb_header_hash(tdb, &h1, &h2);
index 9a82bc9badbbdeccbf0aa6fd85b049c89370c6c4..66539c3f6c5dd9fece0010a3822355ec07c9af34 100644 (file)
@@ -70,6 +70,11 @@ static int tdb_new_database(struct tdb_context *tdb, int hash_size)
 
        tdb_header_hash(tdb, &newdb->magic1_hash, &newdb->magic2_hash);
 
+       /* Make sure older tdbs (which don't check the magic hash fields)
+        * will refuse to open this TDB. */
+       if (tdb->flags & TDB_INCOMPATIBLE_HASH)
+               newdb->rwlocks = TDB_HASH_RWLOCK_MAGIC;
+
        if (tdb->flags & TDB_INTERNAL) {
                tdb->map_size = size;
                tdb->map_ptr = (char *)newdb;
@@ -150,7 +155,10 @@ static bool check_header_hash(struct tdb_context *tdb,
                return false;
 
        /* Otherwise, try the other inbuilt hash. */
-       tdb->hash_fn = tdb_jenkins_hash;
+       if (tdb->hash_fn == tdb_old_hash)
+               tdb->hash_fn = tdb_jenkins_hash;
+       else
+               tdb->hash_fn = tdb_old_hash;
        return check_header_hash(tdb, false, m1, m2);
 }
 
@@ -193,7 +201,12 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
                tdb->hash_fn = hash_fn;
                hash_alg = "the user defined";
        } else {
-               tdb->hash_fn = tdb_old_hash;
+               /* This controls what we use when creating a tdb. */
+               if (tdb->flags & TDB_INCOMPATIBLE_HASH) {
+                       tdb->hash_fn = tdb_jenkins_hash;
+               } else {
+                       tdb->hash_fn = tdb_old_hash;
+               }
                hash_alg = "either default";
        }
 
@@ -312,13 +325,15 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
        if (fstat(tdb->fd, &st) == -1)
                goto fail;
 
-       if (tdb->header.rwlocks != 0) {
+       if (tdb->header.rwlocks != 0 &&
+           tdb->header.rwlocks != TDB_HASH_RWLOCK_MAGIC) {
                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: spinlocks no longer supported\n"));
                goto fail;
        }
 
        if ((tdb->header.magic1_hash == 0) && (tdb->header.magic2_hash == 0)) {
                /* older TDB without magic hash references */
+               tdb->hash_fn = tdb_old_hash;
        } else if (!check_header_hash(tdb, !hash_fn, &magic1, &magic2)) {
                TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: "
                         "%s was not created with %s hash function we are using\n"
index fe3603c1043f444a51c50cdb22b246250d38d405..0c621636fa2bc4b60df90fa04a24183e7ce29bb8 100644 (file)
@@ -50,6 +50,7 @@ typedef uint32_t tdb_off_t;
 #define TDB_DEAD_MAGIC (0xFEE1DEAD)
 #define TDB_RECOVERY_MAGIC (0xf53bc0e7U)
 #define TDB_RECOVERY_INVALID_MAGIC (0x0)
+#define TDB_HASH_RWLOCK_MAGIC (0xbad1a51U)
 #define TDB_ALIGNMENT 4
 #define DEFAULT_HASH_SIZE 131
 #define FREELIST_TOP (sizeof(struct tdb_header))
index a858aa7ec3a320ea6517a157d291da0130e6be1b..26e8ed42ce1959f4dbac425bc790bf8ababcc711 100644 (file)
@@ -2,7 +2,7 @@ AC_PREREQ(2.50)
 AC_DEFUN([SMB_MODULE_DEFAULT], [echo -n ""])
 AC_DEFUN([SMB_LIBRARY_ENABLE], [echo -n ""])
 AC_DEFUN([SMB_ENABLE], [echo -n ""])
-AC_INIT(tdb, 1.2.5)
+AC_INIT(tdb, 1.2.6)
 AC_CONFIG_SRCDIR([common/tdb.c])
 AC_CONFIG_HEADER(include/config.h)
 AC_LIBREPLACE_ALL_CHECKS
index 08b6b3ab55f4c037ada7f07a9211be795ff4a932..96fc157f6853810b7bd392796834333b5647f70f 100644 (file)
@@ -50,6 +50,7 @@ extern "C" {
 #define TDB_VOLATILE   256 /* Activate the per-hashchain freelist, default 5 */
 #define TDB_ALLOW_NESTING 512 /* Allow transactions to nest */
 #define TDB_DISALLOW_NESTING 1024 /* Disallow transactions to nest */
+#define TDB_INCOMPATIBLE_HASH 2048 /* Better hashing: can't be opened by tdb < 1.2.6. */
 
 /* error codes */
 enum TDB_ERROR {TDB_SUCCESS=0, TDB_ERR_CORRUPT, TDB_ERR_IO, TDB_ERR_LOCK, 
index 970c6287cfe27a425d76aa20aafe33b191ae9954..94f85cd708414e1e83b245a7522feaf95f58c868 100644 (file)
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
 APPNAME = 'tdb'
-VERSION = '1.2.5'
+VERSION = '1.2.6'
 
 blddir = 'bin'