Skip to content

Commit

Permalink
[SERVER] Verify checksums of all images on SIGUSR1
Browse files Browse the repository at this point in the history
  • Loading branch information
srett committed Jul 5, 2024
1 parent 1b3068f commit ae91f37
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 14 deletions.
1 change: 1 addition & 0 deletions src/server/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ struct _dnbd3_image
} problem;
uint16_t rid; // revision of image
bool accessed; // image was accessed since .meta was written
bool wantCheck; // true if the entire image should be checked as soon as the according thread is idle
pthread_mutex_t lock;
};
#define PIMG(x) (x)->name, (int)(x)->rid
Expand Down
35 changes: 35 additions & 0 deletions src/server/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -2125,3 +2125,38 @@ static void loadImageMeta(dnbd3_image_t *image)
timing_gets( &image->atime, offset );
}

void image_checkForNextFullCheck(void)
{
int i;
dnbd3_image_t *check = NULL;

mutex_lock( &imageListLock );
for (i = 0; i < _num_images; ++i) {
dnbd3_image_t * const image = _images[i];
if ( image != NULL && image->wantCheck ) {
image->wantCheck = false;
check = image;
break;
}
}
mutex_unlock( &imageListLock );
if ( check != NULL ) {
logadd( LOG_DEBUG1, "Queueing next full image check" );
integrity_check( check, -1, false );
}
}

void image_hashAllImages(void)
{
int i;

mutex_lock( &imageListLock );
for (i = 0; i < _num_images; ++i) {
dnbd3_image_t * const image = _images[i];
if ( image != NULL ) {
image->wantCheck = true;
}
}
mutex_unlock( &imageListLock );
integrity_trigger();
}
4 changes: 4 additions & 0 deletions src/server/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ bool image_ensureDiskSpaceLocked(uint64_t size, bool force);

bool image_saveCacheMap(dnbd3_image_t *image);

void image_checkForNextFullCheck(void);

void image_hashAllImages(void);

/**
* Check if given range is cached. Be careful when using this function because:
* 1) you need to hold a reference to the cache map
Expand Down
49 changes: 39 additions & 10 deletions src/server/integrity.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ static void flushFileRange(dnbd3_image_t *image, uint64_t start, uint64_t end);
/**
* Initialize the integrity check thread
*/
void integrity_init()
void integrity_init(void)
{
assert( queueLen == -1 );
mutex_init( &integrityQueueLock, LOCK_INTEGRITY_QUEUE );
Expand All @@ -56,7 +56,7 @@ void integrity_init()
}
}

void integrity_shutdown()
void integrity_shutdown(void)
{
assert( queueLen != -1 );
if ( !bRunning )
Expand Down Expand Up @@ -98,11 +98,16 @@ void integrity_check(dnbd3_image_t *image, int block, bool blocking)
}
// There is an existing check request for the given image, see if we can merge
if ( block == -1 ) {
// New request is supposed to check entire image, reset existing queue item
checkQueue[i].block = 0;
checkQueue[i].count = CHECK_ALL;
mutex_unlock( &integrityQueueLock );
return;
// New request is supposed to check entire image
if ( checkQueue[i].block == 0 && checkQueue[i].count == CHECK_ALL ) {
// Existing full check that didn't start yet, bail out
mutex_unlock( &integrityQueueLock );
return;
}
// Mark existing queue item as void
checkQueue[i].block = -1;
checkQueue[i].count = -1;
continue;
}
if ( checkQueue[i].block <= block ) {
// The block to check is after the block to check in queue
Expand Down Expand Up @@ -148,9 +153,20 @@ void integrity_check(dnbd3_image_t *image, int block, bool blocking)
mutex_unlock( &integrityQueueLock );
}

void integrity_trigger(void)
{
if ( !bRunning )
return;
mutex_lock( &integrityQueueLock );
pthread_cond_signal( &queueSignal );
mutex_unlock( &integrityQueueLock );
}

static void* integrity_main(void * data UNUSED)
{
int i;
bool queueAnother;

setThreadName( "image-check" );
blockNoncriticalSignals();
#if defined(__linux__)
Expand All @@ -165,6 +181,7 @@ static void* integrity_main(void * data UNUSED)
if ( queueLen == 0 ) {
mutex_cond_wait( &queueSignal, &integrityQueueLock );
}
queueAnother = true;
for (i = queueLen - 1; i >= 0; --i) {
if ( _shutdown ) break;
dnbd3_image_t * const image = image_lock( checkQueue[i].image );
Expand Down Expand Up @@ -202,7 +219,7 @@ static void* integrity_main(void * data UNUSED)
if ( _shutdown )
break;
// Open for direct I/O if possible; this prevents polluting the fs cache
if ( directFd == -1 && ( end % DNBD3_BLOCK_SIZE ) == 0 ) {
if ( directFd == -1 && ( MIN( end, fileSize ) % DNBD3_BLOCK_SIZE ) == 0 ) {
// Use direct I/O only if read length is multiple of 4096 to be on the safe side
directFd = open( image->path, O_RDONLY | O_DIRECT );
if ( directFd == -1 ) {
Expand Down Expand Up @@ -231,7 +248,7 @@ static void* integrity_main(void * data UNUSED)
// If this is not a full check, queue one
if ( qCount != CHECK_ALL ) {
logadd( LOG_INFO, "Queueing full check for %s", image->name );
integrity_check( image, -1, false );
image->wantCheck = true;
}
foundCorrupted = true;
}
Expand All @@ -244,12 +261,17 @@ static void* integrity_main(void * data UNUSED)
}
mutex_lock( &integrityQueueLock );
assert( checkQueue[i].image == image );
if ( qCount != CHECK_ALL ) {
if ( checkQueue[i].block == -1 && checkQueue[i].count == -1 ) {
// Marked as dominated while we were checking - discard silently
} else if ( qCount != CHECK_ALL ) {
// Not a full check; update the counter
assert( checkQueue[i].count != CHECK_ALL );
checkQueue[i].count -= ( blocks[0] - checkQueue[i].block );
if ( checkQueue[i].count < 0 ) {
logadd( LOG_WARNING, "BUG! checkQueue counter ran negative" );
}
} else {
assert( checkQueue[i].count == CHECK_ALL );
}
if ( checkCount > 0 || checkQueue[i].count <= 0 ) {
// Done with this task as nothing left
Expand All @@ -258,6 +280,7 @@ static void* integrity_main(void * data UNUSED)
} else {
// Still more blocks to go...
checkQueue[i].block = blocks[0];
queueAnother = false; // Still busy
}
}
if ( foundCorrupted && !_shutdown ) {
Expand All @@ -267,6 +290,12 @@ static void* integrity_main(void * data UNUSED)
// Release :-)
image_release( image );
}
// See if there's another image queued for check
if ( queueAnother ) {
mutex_unlock( &integrityQueueLock );
image_checkForNextFullCheck();
mutex_lock( &integrityQueueLock );
}
}
mutex_unlock( &integrityQueueLock );
bRunning = false;
Expand Down
6 changes: 4 additions & 2 deletions src/server/integrity.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@

#include "globals.h"

void integrity_init();
void integrity_init(void);

void integrity_shutdown();
void integrity_shutdown(void);

void integrity_check(dnbd3_image_t *image, int block, bool blocking);

void integrity_trigger(void);

#endif /* INTEGRITY_H_ */
11 changes: 9 additions & 2 deletions src/server/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ static poll_list_t *listeners = NULL;
* Time the server was started
*/
static ticks startupTime;
static bool sigReload = false, sigLogCycle = false;
static bool sigReload = false, sigLogCycle = false, sigHashAll = false;

/**
* Copied to in signal handler so we can print info
Expand Down Expand Up @@ -445,6 +445,11 @@ int main(int argc, char *argv[])
else
logadd( LOG_WARNING, "Could not cycle log file." );
}
if ( sigHashAll ) {
sigHashAll = false;
logadd( LOG_INFO, "SIGUSR1 received, verifying checksum of all images..." );
image_hashAllImages();
}
//
len = sizeof(client);
fd = sock_accept( listeners, &client, &len );
Expand Down Expand Up @@ -543,8 +548,10 @@ static void dnbd3_handleSignal(int signum)
if ( _shutdown ) return;
if ( signum == SIGINT || signum == SIGTERM ) {
_shutdown = true;
} else if ( signum == SIGUSR1 || signum == SIGHUP ) {
} else if ( signum == SIGHUP ) {
sigReload = true;
} else if ( signum == SIGUSR1 ) {
sigHashAll = true;
} else if ( signum == SIGUSR2 ) {
sigLogCycle = true;
}
Expand Down

0 comments on commit ae91f37

Please sign in to comment.