1
0
mirror of https://github.com/samba-team/samba.git synced 2025-08-30 17:49:30 +03:00

fixed the bug that caused tdbtorture to fail

It was an error in the new transaction code

(This used to be ctdb commit 27f0dfdfb93d92859de3cbbd3874cfb38c13a169)
This commit is contained in:
Andrew Tridgell
2008-01-14 15:11:10 +11:00
parent b866a147d2
commit ddbe31e5aa
3 changed files with 123 additions and 0 deletions

View File

@ -715,6 +715,11 @@ int tdb_wipe_all(struct tdb_context *tdb)
goto failed; goto failed;
} }
if (tdb_ofs_write(tdb, TDB_RECOVERY_HEAD, &offset) == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write recovery head\n"));
goto failed;
}
/* add all the rest of the file to the freelist */ /* add all the rest of the file to the freelist */
data_len = (tdb->map_size - TDB_DATA_START(tdb->header.hash_size)) - sizeof(struct list_struct); data_len = (tdb->map_size - TDB_DATA_START(tdb->header.hash_size)) - sizeof(struct list_struct);
if (data_len > 0) { if (data_len > 0) {
@ -738,3 +743,45 @@ failed:
tdb_unlockall(tdb); tdb_unlockall(tdb);
return -1; return -1;
} }
/*
validate the integrity of all tdb hash chains. Useful when debugging
*/
int tdb_validate(struct tdb_context *tdb)
{
int h;
for (h=-1;h<(int)tdb->header.hash_size;h++) {
tdb_off_t rec_ptr;
uint32_t count = 0;
if (tdb_ofs_read(tdb, TDB_HASH_TOP(h), &rec_ptr) == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_validate: failed ofs_read at top of hash %d\n", h));
return -1;
}
while (rec_ptr) {
struct list_struct r;
tdb_off_t size;
if (tdb_rec_read(tdb, rec_ptr, &r) == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_validate: failed rec_read h=%d rec_ptr=%u count=%u\n",
h, rec_ptr, count));
return -1;
}
if (tdb_ofs_read(tdb, rec_ptr + sizeof(r) + r.rec_len - sizeof(tdb_off_t), &size) == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_validate: failed ofs_read h=%d rec_ptr=%u count=%u\n",
h, rec_ptr, count));
return -1;
}
if (size != r.rec_len + sizeof(r)) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_validate: failed size check size=%u h=%d rec_ptr=%u count=%u\n",
size, h, rec_ptr, count));
return -1;
}
rec_ptr = r.next;
count++;
}
}
return 0;
}

View File

@ -87,6 +87,7 @@
*/ */
/* /*
hold the context of any current transaction hold the context of any current transaction
*/ */
@ -280,6 +281,63 @@ fail:
return -1; return -1;
} }
/*
write while in a transaction - this varient never expands the transaction blocks, it only
updates existing blocks. This means it cannot change the recovery size
*/
static int transaction_write_existing(struct tdb_context *tdb, tdb_off_t off,
const void *buf, tdb_len_t len)
{
uint32_t blk;
/* break it up into block sized chunks */
while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) {
tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size);
if (transaction_write_existing(tdb, off, buf, len2) != 0) {
return -1;
}
len -= len2;
off += len2;
if (buf != NULL) {
buf = (const void *)(len2 + (const char *)buf);
}
}
if (len == 0) {
return 0;
}
blk = off / tdb->transaction->block_size;
off = off % tdb->transaction->block_size;
if (tdb->transaction->num_blocks <= blk ||
tdb->transaction->blocks[blk] == NULL) {
return 0;
}
/* overwrite part of an existing block */
if (buf == NULL) {
memset(tdb->transaction->blocks[blk] + off, 0, len);
} else {
memcpy(tdb->transaction->blocks[blk] + off, buf, len);
}
if (blk == tdb->transaction->num_blocks-1) {
if (len + off > tdb->transaction->last_block_size) {
tdb->transaction->last_block_size = len + off;
}
}
return 0;
fail:
TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: failed at off=%d len=%d\n",
(blk*tdb->transaction->block_size) + off, len));
tdb->transaction->transaction_error = 1;
return -1;
}
/* /*
accelerated hash chain head search, using the cached hash heads accelerated hash chain head search, using the cached hash heads
*/ */
@ -629,6 +687,10 @@ static int tdb_recovery_allocate(struct tdb_context *tdb,
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n")); TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n"));
return -1; return -1;
} }
if (transaction_write_existing(tdb, TDB_RECOVERY_HEAD, &recovery_head, sizeof(tdb_off_t)) == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_recovery_allocate: failed to write recovery head\n"));
return -1;
}
return 0; return 0;
} }
@ -726,6 +788,12 @@ static int transaction_setup_recovery(struct tdb_context *tdb,
tdb->ecode = TDB_ERR_IO; tdb->ecode = TDB_ERR_IO;
return -1; return -1;
} }
if (transaction_write_existing(tdb, recovery_offset, data, sizeof(*rec) + recovery_size) == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write secondary recovery data\n"));
free(data);
tdb->ecode = TDB_ERR_IO;
return -1;
}
/* as we don't have ordered writes, we have to sync the recovery /* as we don't have ordered writes, we have to sync the recovery
data before we update the magic to indicate that the recovery data before we update the magic to indicate that the recovery
@ -747,6 +815,11 @@ static int transaction_setup_recovery(struct tdb_context *tdb,
tdb->ecode = TDB_ERR_IO; tdb->ecode = TDB_ERR_IO;
return -1; return -1;
} }
if (transaction_write_existing(tdb, *magic_offset, &magic, sizeof(magic)) == -1) {
TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_setup_recovery: failed to write secondary recovery magic\n"));
tdb->ecode = TDB_ERR_IO;
return -1;
}
/* ensure the recovery magic marker is on disk */ /* ensure the recovery magic marker is on disk */
if (transaction_sync(tdb, *magic_offset, sizeof(magic)) == -1) { if (transaction_sync(tdb, *magic_offset, sizeof(magic)) == -1) {
@ -778,6 +851,7 @@ int tdb_transaction_commit(struct tdb_context *tdb)
return -1; return -1;
} }
if (tdb->transaction->nesting != 0) { if (tdb->transaction->nesting != 0) {
tdb->transaction->nesting--; tdb->transaction->nesting--;
return 0; return 0;
@ -916,6 +990,7 @@ int tdb_transaction_commit(struct tdb_context *tdb)
/* use a transaction cancel to free memory and remove the /* use a transaction cancel to free memory and remove the
transaction locks */ transaction locks */
tdb_transaction_cancel(tdb); tdb_transaction_cancel(tdb);
return 0; return 0;
} }

View File

@ -157,6 +157,7 @@ int tdb_printfreelist(struct tdb_context *tdb);
int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries); int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries);
int tdb_wipe_all(struct tdb_context *tdb); int tdb_wipe_all(struct tdb_context *tdb);
int tdb_freelist_size(struct tdb_context *tdb); int tdb_freelist_size(struct tdb_context *tdb);
int tdb_validate(struct tdb_context *tdb);
extern TDB_DATA tdb_null; extern TDB_DATA tdb_null;