summaryrefslogtreecommitdiffstats
path: root/src/server/image.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/image.c')
-rw-r--r--src/server/image.c45
1 files changed, 44 insertions, 1 deletions
diff --git a/src/server/image.c b/src/server/image.c
index 2df4565..02a383f 100644
--- a/src/server/image.c
+++ b/src/server/image.c
@@ -469,7 +469,7 @@ dnbd3_image_t* image_get(char *name, uint16_t revision, bool checkIfWorking)
if ( candidate->cache_map != NULL ) {
// -- Incomplete - rw check
if ( candidate->cacheFd == -1 ) { // Make sure file is open for writing
- candidate->cacheFd = open( candidate->path, O_RDWR );
+ image_reopenCacheFd( candidate, false );
// It might have failed - still offer proxy mode, we just can't cache
if ( candidate->cacheFd == -1 ) {
logadd( LOG_WARNING, "Cannot re-open %s for writing - replication disabled", candidate->path );
@@ -484,6 +484,49 @@ dnbd3_image_t* image_get(char *name, uint16_t revision, bool checkIfWorking)
}
/**
+ * Open the given image's main image file in
+ * rw mode, assigning it to the cacheFd struct member.
+ *
+ * @param force If cacheFd was previously assigned a file descriptor (not == -1),
+ * it will be closed first. Otherwise, nothing will happen and true will be returned
+ * immediately.
+ */
+bool image_reopenCacheFd(dnbd3_image_t *image, const bool force)
+{
+ if ( image->cacheFd != -1 && !force )
+ return true;
+ const int nfd = open( image->path, O_RDWR );
+ if ( nfd == -1 ) {
+ if ( force ) {
+ // Opening new one failed, force is enabled -- close old one
+ spin_lock( &image->lock );
+ int ofd = image->cacheFd;
+ image->cacheFd = -1;
+ spin_unlock( &image->lock );
+ if ( ofd != -1 ) {
+ close( ofd );
+ }
+ }
+ return false;
+ }
+ // Open succeeded, now switch out while holding lock to make it look somewhat atomic
+ spin_lock( &image->lock );
+ int closeFd = -1;
+ if ( force || image->cacheFd == -1 ) {
+ closeFd = image->cacheFd;
+ image->cacheFd = nfd;
+ } else {
+ closeFd = nfd;
+ }
+ spin_unlock( &image->lock );
+ if ( closeFd != -1 ) { // Failed
+ close( closeFd );
+ }
+ return true; // We either replaced the fd in force mode or the old one was -1, or
+ // force was false and cacheFd != -1. Either way we consider that success
+}
+
+/**
* Lock the image by increasing its users count
* Returns the image on success, NULL if it is not found in the image list
* Every call to image_lock() needs to be followed by a call to image_release() at some point.