mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
carefully step around the recovery area when doing a tdb_wipe_all. This prevents
problems with wipe_all on databases that may need crash recovery (This used to be ctdb commit e7b1349bf8784c151c2651edd99b3f40ebcece1f)
This commit is contained in:
parent
1ff6e08f78
commit
f6ebcd6a55
@ -686,10 +686,36 @@ void tdb_enable_seqnum(struct tdb_context *tdb)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
add a region of the file to the freelist. Length is the size of the region in bytes,
|
||||
which includes the free list header that needs to be added
|
||||
*/
|
||||
static int tdb_free_region(struct tdb_context *tdb, tdb_off_t offset, ssize_t length)
|
||||
{
|
||||
struct list_struct rec;
|
||||
if (length <= sizeof(rec)) {
|
||||
/* the region is not worth adding */
|
||||
return 0;
|
||||
}
|
||||
if (length + offset > tdb->map_size) {
|
||||
TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: adding region beyond end of file\n"));
|
||||
return -1;
|
||||
}
|
||||
memset(&rec,'\0',sizeof(rec));
|
||||
rec.rec_len = length - sizeof(rec);
|
||||
if (tdb_free(tdb, offset, &rec) == -1) {
|
||||
TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: failed to add free record\n"));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
wipe the entire database, deleting all records. This can be done
|
||||
very fast by using a global lock. The entire data portion of the
|
||||
file becomes a single entry in the freelist.
|
||||
|
||||
This code carefully steps around the recovery area, leaving it alone
|
||||
*/
|
||||
int tdb_wipe_all(struct tdb_context *tdb)
|
||||
{
|
||||
@ -735,44 +761,32 @@ int tdb_wipe_all(struct tdb_context *tdb)
|
||||
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 */
|
||||
data_len = (tdb->map_size - TDB_DATA_START(tdb->header.hash_size)) - sizeof(struct list_struct);
|
||||
if (data_len < recovery_size+sizeof(tdb_off_t)) {
|
||||
recovery_size = 0;
|
||||
/* add all the rest of the file to the freelist, possibly leaving a gap
|
||||
for the recovery area */
|
||||
if (recovery_size == 0) {
|
||||
/* the simple case - the whole file can be used as a freelist */
|
||||
data_len = (tdb->map_size - TDB_DATA_START(tdb->header.hash_size));
|
||||
if (tdb_free_region(tdb, TDB_DATA_START(tdb->header.hash_size), data_len) != 0) {
|
||||
goto failed;
|
||||
}
|
||||
} else {
|
||||
data_len -= recovery_size;
|
||||
}
|
||||
if (data_len > 0) {
|
||||
struct list_struct rec;
|
||||
memset(&rec,'\0',sizeof(rec));
|
||||
rec.rec_len = data_len;
|
||||
if (tdb_free(tdb, TDB_DATA_START(tdb->header.hash_size), &rec) == -1) {
|
||||
TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to add free record\n"));
|
||||
/* we need to add two freelist entries - one on either
|
||||
side of the recovery area
|
||||
|
||||
Note that we cannot shift the recovery area during
|
||||
this operation. Only the transaction.c code may
|
||||
move the recovery area or we risk subtle data
|
||||
corruption
|
||||
*/
|
||||
data_len = (recovery_head - TDB_DATA_START(tdb->header.hash_size));
|
||||
if (tdb_free_region(tdb, TDB_DATA_START(tdb->header.hash_size), data_len) != 0) {
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
/* possibly add the recovery record */
|
||||
if (recovery_size != 0) {
|
||||
struct list_struct rec;
|
||||
|
||||
recovery_head = tdb->map_size - recovery_size;
|
||||
|
||||
ZERO_STRUCT(rec);
|
||||
rec.rec_len = recovery_size - sizeof(rec);
|
||||
if (tdb_rec_write(tdb, recovery_head, &rec) != 0) {
|
||||
TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to add recovery record\n"));
|
||||
/* and the 2nd free list entry after the recovery area - if any */
|
||||
data_len = tdb->map_size - (recovery_head+recovery_size);
|
||||
if (tdb_free_region(tdb, recovery_head+recovery_size, data_len) != 0) {
|
||||
goto failed;
|
||||
}
|
||||
if (tdb_ofs_write(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
|
||||
TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write recovery head\n"));
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
if (tdb_unlockall(tdb) != 0) {
|
||||
|
Loading…
Reference in New Issue
Block a user