summaryrefslogtreecommitdiffstats
path: root/src/server/uplink.c
diff options
context:
space:
mode:
authorSimon Rettberg2015-01-27 19:39:04 +0100
committerSimon Rettberg2015-01-27 19:39:04 +0100
commit2b722b756864b14b6299a8b24067a37e12aabfc4 (patch)
treec73c47c7f4a8a9a24f218ca865176c3b237687a4 /src/server/uplink.c
parent[SERVER] Crank up warning levels of gcc and fix them all (mostly sign compare... (diff)
downloaddnbd3-2b722b756864b14b6299a8b24067a37e12aabfc4.tar.gz
dnbd3-2b722b756864b14b6299a8b24067a37e12aabfc4.tar.xz
dnbd3-2b722b756864b14b6299a8b24067a37e12aabfc4.zip
[SERVER] Fix automatic proxying to use supplied connection; fix race condition in uplink_init
Diffstat (limited to 'src/server/uplink.c')
-rw-r--r--src/server/uplink.c44
1 files changed, 26 insertions, 18 deletions
diff --git a/src/server/uplink.c b/src/server/uplink.c
index cc82fe0..fdc4b27 100644
--- a/src/server/uplink.c
+++ b/src/server/uplink.c
@@ -43,7 +43,8 @@ bool uplink_init(dnbd3_image_t *image, int sock, dnbd3_host_t *host)
assert( image != NULL );
spin_lock( &image->lock );
if ( image->uplink != NULL ) {
- goto failure;
+ spin_unlock( &image->lock );
+ return true; // There's already an uplink, so should we consider this success or failure?
}
if ( image->cache_map == NULL ) {
memlogf( "[WARNING] Uplink was requested for image %s, but it is already complete", image->lower_name );
@@ -66,47 +67,49 @@ bool uplink_init(dnbd3_image_t *image, int sock, dnbd3_host_t *host)
link->recvBufferLen = 0;
link->shutdown = false;
spin_init( &link->queueLock, PTHREAD_PROCESS_PRIVATE );
- if ( 0 != thread_create( &(link->thread), NULL, &uplink_mainloop, (void *)(uintptr_t)link ) ) {
- memlogf( "[ERROR] Could not start thread for new client." );
+ if ( 0 != thread_create( &(link->thread), NULL, &uplink_mainloop, (void *)link ) ) {
+ memlogf( "[ERROR] Could not start thread for new uplink." );
goto failure;
}
spin_unlock( &image->lock );
return true;
failure: ;
- if ( link != NULL ) free( link );
- link = image->uplink = NULL;
+ if ( link != NULL ) {
+ free( link );
+ link = image->uplink = NULL;
+ }
spin_unlock( &image->lock );
return false;
}
/**
* Locks on image.lock, uplink.lock
- * Sets image->uplink to NULL while locked, so
- * calling it multiple times, even concurrently, will
+ * Calling it multiple times, even concurrently, will
* not break anything.
*/
void uplink_shutdown(dnbd3_image_t *image)
{
+ bool join = false;
+ pthread_t thread;
assert( image != NULL );
spin_lock( &image->lock );
- if ( image->uplink == NULL || image->uplink->shutdown ) {
+ if ( image->uplink == NULL ) {
spin_unlock( &image->lock );
return;
}
dnbd3_connection_t * const uplink = image->uplink;
spin_lock( &uplink->queueLock );
- if ( uplink->shutdown ) {
- spin_unlock( &uplink->queueLock );
- spin_unlock( &image->lock );
- return;
+ if ( !uplink->shutdown ) {
+ uplink->shutdown = true;
+ signal_call( uplink->signal );
+ thread = uplink->thread;
+ join = true;
}
- image->uplink = NULL;
- uplink->shutdown = true;
- signal_call( uplink->signal );
- pthread_t thread = uplink->thread;
spin_unlock( &uplink->queueLock );
spin_unlock( &image->lock );
- thread_join( thread, NULL );
+ if ( join ) thread_join( thread, NULL );
+ while ( image->uplink != NULL )
+ usleep( 10000 );
}
/**
@@ -140,6 +143,11 @@ bool uplink_request(dnbd3_client_t *client, uint64_t handle, uint64_t start, uin
return false;
}
dnbd3_connection_t * const uplink = client->image->uplink;
+ if ( uplink->shutdown ) {
+ spin_unlock( &client->image->lock );
+ printf( "[DEBUG] Uplink request for image with uplink shutting down (%s)\n", client->image->lower_name );
+ return false;
+ }
// Check if the client is the same host as the uplink. If so assume this is a circular proxy chain
if ( isSameAddress( &uplink->currentServer, &client->host ) ) {
spin_unlock( &client->image->lock );
@@ -253,7 +261,7 @@ static void* uplink_mainloop(void *data)
link->image->working = true;
buffer[0] = '@';
if ( host_to_string( &link->currentServer, buffer + 1, sizeof(buffer) - 1 ) ) {
- printf( "[DEBUG] Now connected to %s\n", buffer + 1 );
+ printf( "[DEBUG] (Uplink %s) Now connected to %s\n", link->image->lower_name, buffer + 1 );
setThreadName( buffer );
}
// Re-send all pending requests