summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2019-09-06 17:32:58 +0200
committerSimon Rettberg2019-09-06 17:32:58 +0200
commit701e5a967fd6bc97644f39e6fea3714f49a90291 (patch)
tree254e8bc23dfb9e6640b6f1c8d7c57ffff975b998
parent[SERVER] Introduce autoFreeDiskSpaceDelay (diff)
downloaddnbd3-701e5a967fd6bc97644f39e6fea3714f49a90291.tar.gz
dnbd3-701e5a967fd6bc97644f39e6fea3714f49a90291.tar.xz
dnbd3-701e5a967fd6bc97644f39e6fea3714f49a90291.zip
[SERVER] rpc: Add cachemap feature
-rw-r--r--src/server/globals.h2
-rw-r--r--src/server/image.c16
-rw-r--r--src/server/image.h2
-rw-r--r--src/server/rpc.c44
4 files changed, 63 insertions, 1 deletions
diff --git a/src/server/globals.h b/src/server/globals.h
index 58b2c9d..df8c595 100644
--- a/src/server/globals.h
+++ b/src/server/globals.h
@@ -110,7 +110,7 @@ typedef struct
typedef struct
{
ref reference;
- atomic_uint_least8_t map[];
+ _Atomic uint8_t map[];
} dnbd3_cache_map_t;
/**
diff --git a/src/server/image.c b/src/server/image.c
index 9fcb866..5fa06d8 100644
--- a/src/server/image.c
+++ b/src/server/image.c
@@ -274,6 +274,22 @@ bool image_ensureOpen(dnbd3_image_t *image)
return image->readFd != -1;
}
+dnbd3_image_t* image_byId(int imgId)
+{
+ int i;
+ mutex_lock( &imageListLock );
+ for (i = 0; i < _num_images; ++i) {
+ dnbd3_image_t * const image = _images[i];
+ if ( image != NULL && image->id == imgId ) {
+ image->users++;
+ mutex_unlock( &imageListLock );
+ return image;
+ }
+ }
+ mutex_unlock( &imageListLock );
+ return NULL;
+}
+
/**
* Get an image by name+rid. This function increases a reference counter,
* so you HAVE TO CALL image_release for every image_get() call at some
diff --git a/src/server/image.h b/src/server/image.h
index cd87f03..449e31f 100644
--- a/src/server/image.h
+++ b/src/server/image.h
@@ -17,6 +17,8 @@ void image_markComplete(dnbd3_image_t *image);
bool image_ensureOpen(dnbd3_image_t *image);
+dnbd3_image_t* image_byId(int imgId);
+
dnbd3_image_t* image_get(char *name, uint16_t revision, bool checkIfWorking);
bool image_reopenCacheFd(dnbd3_image_t *image, const bool force);
diff --git a/src/server/rpc.c b/src/server/rpc.c
index 662263e..548c80f 100644
--- a/src/server/rpc.c
+++ b/src/server/rpc.c
@@ -9,6 +9,7 @@
#include "fileutil.h"
#include "picohttpparser/picohttpparser.h"
#include "urldecode.h"
+#include "reference.h"
#include <jansson.h>
#include <sys/types.h>
@@ -43,7 +44,9 @@ _Static_assert( sizeof("test") == 5 && sizeof("test2") == 6, "Stringsize messup
DEFSTR(STR_CONNECTION, "connection")
DEFSTR(STR_CLOSE, "close")
DEFSTR(STR_QUERY, "/query")
+DEFSTR(STR_CACHEMAP, "/cachemap")
DEFSTR(STR_Q, "q")
+DEFSTR(STR_ID, "id")
static inline bool equals(struct string *s1,struct string *s2)
{
@@ -81,6 +84,7 @@ static struct {
} status;
static bool handleStatus(int sock, int permissions, struct field *fields, size_t fields_num, int keepAlive);
+static bool handleCacheMap(int sock, int permissions, struct field *fields, size_t fields_num, int keepAlive);
static bool sendReply(int sock, const char *status, const char *ctype, const char *payload, ssize_t plen, int keepAlive);
static void parsePath(struct string *path, struct string *file, struct field *getv, size_t *getc);
static bool hasHeaderValue(struct phr_header *headers, size_t numHeaders, struct string *name, struct string *value);
@@ -212,6 +216,8 @@ void rpc_sendStatsJson(int sock, dnbd3_host_t* host, const void* data, const int
// Don't care if GET or POST
if ( equals( &file, &STR_QUERY ) ) {
ok = handleStatus( sock, permissions, getv, getc, keepAlive );
+ } else if ( equals( &file, &STR_CACHEMAP ) ) {
+ ok = handleCacheMap( sock, permissions, getv, getc, keepAlive );
} else {
ok = sendReply( sock, "404 Not found", "text/plain", "Nothing", -1, keepAlive );
}
@@ -342,6 +348,44 @@ static bool handleStatus(int sock, int permissions, struct field *fields, size_t
return ok;
}
+static bool handleCacheMap(int sock, int permissions, struct field *fields, size_t fields_num, int keepAlive)
+{
+ if ( !(permissions & ACL_IMAGE_LIST) ) {
+ return sendReply( sock, "403 Forbidden", "text/plain", "No permission to access image list", -1, keepAlive );
+ }
+ int imgId = -1;
+ static const char one = 0xff;
+ for (size_t i = 0; i < fields_num; ++i) {
+ if ( equals( &fields[i].name, &STR_ID ) ) {
+ char *broken;
+ imgId = strtol( fields[i].value.s, &broken, 10 );
+ if ( broken != fields[i].value.s )
+ break;
+ imgId = -1;
+ }
+ }
+ if ( imgId == -1 )
+ return sendReply( sock, "400 Bad Request", "text/plain", "Missing parameter 'id'", -1, keepAlive );
+ dnbd3_image_t *image = image_byId( imgId );
+ if ( image == NULL )
+ return sendReply( sock, "404 Not found", "text/plain", "Image not found", -1, keepAlive );
+ dnbd3_cache_map_t *cache = ref_get_cachemap( image );
+ image_release( image );
+ int len;
+ const char *map;
+ if ( cache == NULL ) {
+ map = &one;
+ len = 1;
+ } else {
+ _Static_assert( sizeof(const char) == sizeof(_Atomic uint8_t), "Atomic assumption exploded" );
+ map = (const char*)cache->map;
+ len = IMGSIZE_TO_MAPBYTES( image->virtualFilesize );
+ }
+ bool ok = sendReply( sock, "200 OK", "application/octet-stream", map, len, keepAlive );
+ ref_put( &cache->reference );
+ return ok;
+}
+
static bool sendReply(int sock, const char *status, const char *ctype, const char *payload, ssize_t plen, int keepAlive)
{
if ( plen == -1 ) plen = strlen( payload );