summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/server/globals.h1
-rw-r--r--src/server/image.c35
-rw-r--r--src/server/image.h4
-rw-r--r--src/server/integrity.c49
-rw-r--r--src/server/integrity.h6
-rw-r--r--src/server/server.c11
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;
}