diff options
author | Simon Rettberg | 2024-07-05 10:48:29 +0200 |
---|---|---|
committer | Simon Rettberg | 2024-07-05 10:48:29 +0200 |
commit | ae91f373cf5ce045fe65df022fae151fe915c6c3 (patch) | |
tree | c6b069316052f507a52786841054b1afb6d51e4f | |
parent | [SERVER] integrity: Add comments, line wraps, add check for full scan (diff) | |
download | dnbd3-master.tar.gz dnbd3-master.tar.xz dnbd3-master.zip |
-rw-r--r-- | src/server/globals.h | 1 | ||||
-rw-r--r-- | src/server/image.c | 35 | ||||
-rw-r--r-- | src/server/image.h | 4 | ||||
-rw-r--r-- | src/server/integrity.c | 49 | ||||
-rw-r--r-- | src/server/integrity.h | 6 | ||||
-rw-r--r-- | src/server/server.c | 11 |
6 files changed, 92 insertions, 14 deletions
diff --git a/src/server/globals.h b/src/server/globals.h index bde1184..5129108 100644 --- a/src/server/globals.h +++ b/src/server/globals.h @@ -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 diff --git a/src/server/image.c b/src/server/image.c index 51fd5b6..f438c18 100644 --- a/src/server/image.c +++ b/src/server/image.c @@ -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(); +} diff --git a/src/server/image.h b/src/server/image.h index 7b6583c..df8ac87 100644 --- a/src/server/image.h +++ b/src/server/image.h @@ -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 diff --git a/src/server/integrity.c b/src/server/integrity.c index 5a436ee..346e3e2 100644 --- a/src/server/integrity.c +++ b/src/server/integrity.c @@ -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 ); @@ -56,7 +56,7 @@ void integrity_init() } } -void integrity_shutdown() +void integrity_shutdown(void) { assert( queueLen != -1 ); if ( !bRunning ) @@ -98,11 +98,16 @@ start_over: } // 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 @@ -148,9 +153,20 @@ start_over: 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__) @@ -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 ); @@ -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 ) { @@ -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; } @@ -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 @@ -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 ) { @@ -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; diff --git a/src/server/integrity.h b/src/server/integrity.h index 09d3785..7a1b8d7 100644 --- a/src/server/integrity.h +++ b/src/server/integrity.h @@ -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_ */ diff --git a/src/server/server.c b/src/server/server.c index 0f75935..d086930 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -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 @@ -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 ); @@ -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; } |