diff options
Diffstat (limited to 'src/server/job.c')
-rw-r--r-- | src/server/job.c | 114 |
1 files changed, 101 insertions, 13 deletions
diff --git a/src/server/job.c b/src/server/job.c index 44beb00..b78ef4f 100644 --- a/src/server/job.c +++ b/src/server/job.c @@ -11,6 +11,7 @@ #include <string.h> #include <fcntl.h> #include <sys/ioctl.h> +#include <linux/fs.h> #include <pthread.h> #include <sys/socket.h> #include <netinet/in.h> @@ -84,8 +85,9 @@ void *dnbd3_job_thread(void *data) devices[j].available = TRUE; ++j; } + num_devices = j; } - memlogf("[INFO] %d available dnbd3 devices for proxy mode", j); + memlogf("[INFO] %d available dnbd3 devices for proxy mode", num_devices); // time_t next_delete_invocation = 0; // @@ -143,6 +145,52 @@ static void connect_proxy_images() pthread_spin_unlock(&_spinlock); break; } + if (image->working && image->cache_map && image->file) + { // Check if cache is complete + int complete = TRUE, j; + const int map_len_bytes = IMGSIZE_TO_MAPBYTES(image->filesize); + for (j = 0; j < map_len_bytes - 1; ++j) + { + if (image->cache_map[j] != 0xFF) + { + complete = FALSE; + break; + } + } + if (complete) + { + const int blocks_in_last_byte = (image->filesize >> 12) & 7; + uint8_t last_byte = 0; + if (blocks_in_last_byte == 0) + last_byte = 0xFF; + else + for (j = 0; j < blocks_in_last_byte; ++j) + last_byte |= (1 << j); + complete = ((image->cache_map[map_len_bytes - 1] & last_byte) == last_byte); + } + if (!complete) + { + pthread_spin_unlock(&_spinlock); + continue; + } + // Image is 100% cached, disconnect dnbd3 device + memlogf("[INFO] Disconnecting %s because local copy of %s is complete.", image->file, image->config_group); + int dh = open(image->file, O_RDONLY); + if (dh < 0) + memlogf("[ERROR] Could not open() device '%s'", image->file); + else + { + if (ioctl(dh, IOCTL_CLOSE, (void*)0) != 0) + memlogf("[ERROR] Could not IOCTL_CLOSE device '%s'", image->file); + else + return_free_device(image->file); + close(dh); + } + free(image->file); + image->file = NULL; + pthread_spin_unlock(&_spinlock); + continue; + } if (image->working || image->file || image->low_name == NULL) { // Nothing to do pthread_spin_unlock(&_spinlock); @@ -160,7 +208,7 @@ static void connect_proxy_images() rid = image->rid; memcpy(servers, image->servers, sizeof(servers[0]) * NUMBER_SERVERS); pthread_spin_unlock(&_spinlock); - int dh = open(devname, O_WRONLY); + int dh = open(devname, O_RDWR); if (dh < 0) continue; for (s = 0; s < NUMBER_SERVERS; ++s) @@ -168,12 +216,14 @@ static void connect_proxy_images() if (servers[s].host.type == 0) continue; // connect device + printf("[DEBUG] Connecting device....\n"); msg.host = servers[s].host; msg.imgname = imagename; msg.imgnamelen = strlen(imagename); msg.rid = rid; if (ioctl(dh, IOCTL_OPEN, &msg) < 0) continue; + printf("[DEBUG] Connected! Adding alt servers...\n"); // connected for (++s; s < NUMBER_SERVERS; ++s) { @@ -182,7 +232,10 @@ static void connect_proxy_images() msg.host = servers[s].host; if (ioctl(dh, IOCTL_ADD_SRV, &msg) < 0) memlogf("[WARNING] Could not add alt server to proxy device"); + else + printf("[DEBUG] Added an alt server\n"); } + printf("[DEBUG] Done, handling file size...\n"); // LOCK + UPDATE pthread_spin_lock(&_spinlock); if (g_slist_find(_dnbd3_images, image) == NULL) @@ -195,16 +248,29 @@ static void connect_proxy_images() else { image->file = strdup(devname); - const off_t off = lseek(dh, 0, SEEK_END); - if (off < 0) - memlogf("[ERROR] Could not get image size from connected device %s", devname); - else if (image->filesize != 0 && image->filesize != off) - memlogf("[ERROR] Remote and local size of image do not match: %llu != %llu for %s", (unsigned long long)off, (unsigned long long)image->filesize, image->low_name); + long long oct = 0; + int t, ret; + for (t = 0; t < 10 && dh >= 0; ++t) + { // For some reason the ioctl might return 0 right after connecting + ret = ioctl(dh, BLKGETSIZE64, &oct); + if (ret == 0 && oct > 0) + break; + close(dh); + usleep(100 * 1000); + dh = open(devname, O_RDONLY); + } + if (dh < 0 || ret != 0) + memlogf("[ERROR] SIZE fail on %s (ret=%d, oct=%lld)", devname, ret, oct); + else if (oct == 0) + memlogf("[ERROR] Reported disk size is 0."); + else if (image->filesize != 0 && image->filesize != oct) + memlogf("[ERROR] Remote and local size of image do not match: %llu != %llu for %s", (unsigned long long)oct, (unsigned long long)image->filesize, image->low_name); else image->working = TRUE; - image->filesize = (uint64_t)off; + image->filesize = (uint64_t)oct; if (image->cache_file != NULL && image->working && image->cache_map == NULL) { + printf("[DEBUG] Image has cache file %s\n", image->cache_file); const int mapsize = IMGSIZE_TO_MAPBYTES(image->filesize); image->cache_map = calloc(mapsize, 1); off_t cachelen = -1; @@ -214,6 +280,19 @@ static void connect_proxy_images() cachelen = lseek(ch, 0, SEEK_END); close(ch); } + else + { + ch = open(image->cache_file, O_WRONLY | O_CREAT, 0600); + if (ch >= 0) + { + // Pre-allocate disk space + printf("[DEBUG] Pre-allocating disk space...\n"); + lseek(ch, image->filesize - 1, SEEK_SET); + write(ch, &ch, 1); + close(ch); + printf("[DEBUG] Allocation complete.\n"); + } + } if (cachelen == image->filesize) { char mapfile[strlen(image->cache_file) + 5]; @@ -225,7 +304,7 @@ static void connect_proxy_images() memlogf("[WARNING] Existing cache map has wrong size."); else { - lseek(cmh, 0, SEEK_CUR); + lseek(cmh, 0, SEEK_SET); read(cmh, image->cache_map, mapsize); printf("[DEBUG] Found existing cache file and map for %s\n", image->low_name); } @@ -233,7 +312,8 @@ static void connect_proxy_images() } } } - memlogf("[INFO] Enabled relayed image %s", image->low_name); + if (image->working) + memlogf("[INFO] Enabled relayed image %s (%lld)", image->low_name, oct); } pthread_spin_unlock(&_spinlock); break; @@ -376,9 +456,11 @@ static void query_servers() NEW_POINTERLIST; char *image = XML_GETPROP(cur, "name"); char *ridstr = XML_GETPROP(cur, "rid"); - if (!image || !ridstr) + char *sizestr = XML_GETPROP(cur, "size"); + if (!image || !ridstr || !sizestr) goto free_current_image; - int rid = atoi(ridstr); + const int rid = atoi(ridstr); + const long long size = atoll(sizestr); if (rid <= 0) { printf("[DEBUG] Ignoring remote image with rid %d\n", rid); @@ -425,7 +507,10 @@ static void query_servers() newimage.config_group = xmlbuffer; newimage.rid = rid; if (_cache_dir) + { newimage.cache_file = create_cache_filename(xmlbuffer, rid, cachefile, 70); + printf("[DEBUG] Cache file is %s\n", newimage.cache_file); + } dnbd3_add_image(&newimage); pthread_spin_lock(&_spinlock); local_image = dnbd3_get_image(xmlbuffer, rid, FALSE); @@ -437,7 +522,10 @@ static void query_servers() { // Image is already KNOWN, add alt server if appropriate // TODO: Check if requested for namespace - add_alt_server(local_image, &server->host); + if (size != local_image->filesize) + printf("[DEBUG] Ignoring remote image '%s' because it has a different size from the local version!\n", local_image->config_group); + else + add_alt_server(local_image, &server->host); pthread_spin_unlock(&_spinlock); } // Cleanup |