diff options
author | Jeremy Allison <jra@samba.org> | 2006-11-30 03:05:55 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:16:15 -0500 |
commit | cc13e21dbeb9548ea90f86445fe9a371b5c05e0c (patch) | |
tree | 9ee289f82efa8005426f07464e9537df5df391ed /source3/tdb | |
parent | 2941b044b3fed09cd94d6b2e9057d3e58c12703b (diff) | |
download | samba-cc13e21dbeb9548ea90f86445fe9a371b5c05e0c.tar.gz samba-cc13e21dbeb9548ea90f86445fe9a371b5c05e0c.tar.bz2 samba-cc13e21dbeb9548ea90f86445fe9a371b5c05e0c.zip |
r19959: Allow tdb to be built standalone in Samba3.
Add code to check for loops in the free list.
Should help us validate tdb's against corruption.
Jeremy.
(This used to be commit f8e7386773cbbb31e2f42ffcbae9b979c1197635)
Diffstat (limited to 'source3/tdb')
-rw-r--r-- | source3/tdb/Makefile.in | 4 | ||||
-rwxr-xr-x | source3/tdb/autogen.sh | 2 | ||||
-rw-r--r-- | source3/tdb/common/freelist.c | 2 | ||||
-rw-r--r-- | source3/tdb/common/freelistcheck.c | 108 | ||||
-rw-r--r-- | source3/tdb/config.m4 | 21 | ||||
-rw-r--r-- | source3/tdb/include/tdb.h | 1 | ||||
-rw-r--r-- | source3/tdb/tools/tdbtest.c | 9 |
7 files changed, 141 insertions, 6 deletions
diff --git a/source3/tdb/Makefile.in b/source3/tdb/Makefile.in index e158752d43..e16f50f6dd 100644 --- a/source3/tdb/Makefile.in +++ b/source3/tdb/Makefile.in @@ -12,12 +12,12 @@ libdir = @libdir@ VPATH = @srcdir@:@libreplacedir@ srcdir = @srcdir@ builddir = @builddir@ -CFLAGS = -I$(srcdir)/include -Iinclude -I@libreplacedir@ @CFLAGS@ +CFLAGS = -I$(srcdir)/include -Iinclude -I../include -I@libreplacedir@ @CFLAGS@ .PHONY: test PROGS = bin/tdbtool bin/tdbtorture -TDB_OBJ = @TDBOBJ@ @LIBREPLACEOBJ@ +TDB_OBJ = @TDBOBJ@ DIRS = bin common tools diff --git a/source3/tdb/autogen.sh b/source3/tdb/autogen.sh index bf84eeee19..1691689e10 100755 --- a/source3/tdb/autogen.sh +++ b/source3/tdb/autogen.sh @@ -3,7 +3,7 @@ rm -rf autom4te.cache rm -f configure config.h.in -IPATHS="-I libreplace -I lib/replace -I ../libreplace -I ../replace" +IPATHS="-I libreplace -I lib/replace -I ../libreplace -I ../replace -I ../lib/replace" autoconf $IPATHS || exit 1 autoheader $IPATHS || exit 1 diff --git a/source3/tdb/common/freelist.c b/source3/tdb/common/freelist.c index 9d1ae59801..0efe47f879 100644 --- a/source3/tdb/common/freelist.c +++ b/source3/tdb/common/freelist.c @@ -29,7 +29,7 @@ #include "tdb_private.h" /* read a freelist record and check for simple errors */ -static int rec_free_read(struct tdb_context *tdb, tdb_off_t off, struct list_struct *rec) +int rec_free_read(struct tdb_context *tdb, tdb_off_t off, struct list_struct *rec) { if (tdb->methods->tdb_read(tdb, off, rec, sizeof(*rec),DOCONV()) == -1) return -1; diff --git a/source3/tdb/common/freelistcheck.c b/source3/tdb/common/freelistcheck.c new file mode 100644 index 0000000000..3f79a016b8 --- /dev/null +++ b/source3/tdb/common/freelistcheck.c @@ -0,0 +1,108 @@ +/* + Unix SMB/CIFS implementation. + + trivial database library + + Copyright (C) Jeremy Allison 2006 + + ** NOTE! The following LGPL license applies to the tdb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "tdb_private.h" + +/* Check the freelist is good and contains no loops. + Very memory intensive - only do this as a consistency + checker. Heh heh - uses an in memory tdb as the storage + for the "seen" record list. For some reason this strikes + me as extremely clever as I don't have to write another tree + data structure implementation :-). + */ + +static int seen_insert(struct tdb_context *mem_tdb, tdb_off_t rec_ptr) +{ + TDB_DATA key, data; + + memset(&data, '\0', sizeof(data)); + key.dptr = (char *)&rec_ptr; + key.dsize = sizeof(rec_ptr); + return tdb_store(mem_tdb, key, data, TDB_INSERT); +} + +int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries) +{ + struct tdb_context *mem_tdb = NULL; + struct list_struct rec; + tdb_off_t rec_ptr, last_ptr; + int ret = -1; + + *pnum_entries = 0; + + mem_tdb = tdb_open("flval", tdb->header.hash_size, + TDB_INTERNAL, O_RDWR, 0600); + if (!mem_tdb) { + return -1; + } + + if (tdb_lock(tdb, -1, F_WRLCK) == -1) { + tdb_close(mem_tdb); + return 0; + } + + last_ptr = FREELIST_TOP; + + /* Store the FREELIST_TOP record. */ + if (seen_insert(mem_tdb, last_ptr) == -1) { + ret = TDB_ERRCODE(TDB_ERR_CORRUPT, -1); + goto fail; + } + + /* read in the freelist top */ + if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1) { + goto fail; + } + + while (rec_ptr) { + + /* If we can't store this record (we've seen it + before) then the free list has a loop and must + be corrupt. */ + + if (seen_insert(mem_tdb, rec_ptr)) { + ret = TDB_ERRCODE(TDB_ERR_CORRUPT, -1); + goto fail; + } + + if (rec_free_read(tdb, rec_ptr, &rec) == -1) { + goto fail; + } + + /* move to the next record */ + last_ptr = rec_ptr; + rec_ptr = rec.next; + *pnum_entries += 1; + } + + ret = 0; + + fail: + + tdb_close(mem_tdb); + tdb_unlock(tdb, -1, F_WRLCK); + return ret; +} diff --git a/source3/tdb/config.m4 b/source3/tdb/config.m4 index cb0801795c..a37f36b29e 100644 --- a/source3/tdb/config.m4 +++ b/source3/tdb/config.m4 @@ -1,3 +1,24 @@ +dnl find the tdb sources. This is meant to work both for +dnl tdb standalone builds, and builds of packages using tdb +tdbdir="" +tdbpaths="$srcdir $srcdir/lib/tdb $srcdir/tdb $srcdir/../tdb" +for d in $tdbpaths; do + if test -f "$d/common/tdb.c"; then + tdbdir="$d" + AC_SUBST(tdbdir) + break; + fi +done +if test x"$tdbdir" = "x"; then + AC_MSG_ERROR([cannot find tdb source in $tdbpaths]) +fi +TDBOBJ="common/tdb.o common/dump.o common/transaction.o common/error.o common/traverse.o" +TDBOBJ="$TDBOBJ common/freelist.o common/freelistcheck.o common/io.o common/lock.o common/open.o" +AC_SUBST(TDBOBJ) + +libreplacedir=../lib/replace +AC_SUBST(libreplacedir) + AC_CHECK_FUNCS(mmap pread pwrite getpagesize utime) AC_CHECK_HEADERS(getopt.h sys/select.h sys/time.h) diff --git a/source3/tdb/include/tdb.h b/source3/tdb/include/tdb.h index 920ac5c6d9..b783f23a1e 100644 --- a/source3/tdb/include/tdb.h +++ b/source3/tdb/include/tdb.h @@ -136,6 +136,7 @@ int tdb_chainunlock_read(struct tdb_context *tdb, TDB_DATA key); /* Debug functions. Not used in production. */ void tdb_dump_all(struct tdb_context *tdb); int tdb_printfreelist(struct tdb_context *tdb); +int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries); extern TDB_DATA tdb_null; diff --git a/source3/tdb/tools/tdbtest.c b/source3/tdb/tools/tdbtest.c index c7a09789fe..1564a42bc4 100644 --- a/source3/tdb/tools/tdbtest.c +++ b/source3/tdb/tools/tdbtest.c @@ -219,6 +219,7 @@ static void merge_test(void) { int i, seed=0; int loops = 10000; + int num_entries; char test_gdbm[] = "test.gdbm"; unlink("test.gdbm"); @@ -232,8 +233,6 @@ static void merge_test(void) fatal("db open failed"); } - tdb_logging_function(db, tdb_log); - #if 1 srand(seed); _start_timer(); @@ -248,6 +247,12 @@ static void merge_test(void) for (i=0;i<loops;i++) addrec_db(); printf("tdb got %.2f ops/sec\n", i/_end_timer()); + if (tdb_validate_freelist(db, &num_entries) == -1) { + printf("tdb freelist is corrupt\n"); + } else { + printf("tdb freelist is good (%d entries)\n", num_entries); + } + compare_db(); printf("traversed %d records\n", tdb_traverse(db, traverse_fn, NULL)); |