diff --git a/src/client.c b/src/client.c index 20e6468..3aa9bd7 100644 --- a/src/client.c +++ b/src/client.c @@ -26,7 +26,7 @@ */ void write_not_zeroes(struct client* client, off64_t from, int len) { - char *map = client->serve->block_allocation_map; + struct bitset_mapping *map = client->serve->allocation_map; while (len > 0) { /* so we have to calculate how much of our input to consider @@ -36,17 +36,15 @@ void write_not_zeroes(struct client* client, off64_t from, int len) * how many blocks our write covers, then cut off the start * and end to get the exact number of bytes. */ - int first_bit = from/block_allocation_resolution; - int last_bit = (from+len+block_allocation_resolution-1) / - block_allocation_resolution; - int run = bit_run_count(map, first_bit, last_bit-first_bit) * - block_allocation_resolution; + + int run = bitset_run_count(map, from, len); - if (run > len) + debug("write_not_zeroes: from=%ld, len=%d, run=%d", from, len, run); + + if (run > len) { run = len; - - debug("write_not_zeroes: %ld+%d, first_bit=%d, last_bit=%d, run=%d", - from, len, first_bit, last_bit, run); + debug("(run adjusted to %d)", run); + } #define DO_READ(dst, len) CLIENT_ERROR_ON_FAILURE( \ readloop( \ @@ -57,8 +55,8 @@ void write_not_zeroes(struct client* client, off64_t from, int len) "read failed %ld+%d", from, (len) \ ) - if (bit_is_set(map, from/block_allocation_resolution)) { - debug("writing the lot"); + if (bitset_is_set_at(map, from)) { + debug("writing the lot: from=%ld, run=%d", from, run); /* already allocated, just write it all */ DO_READ(client->mapped + from, run); server_dirty(client->serve, from, run); @@ -69,16 +67,11 @@ void write_not_zeroes(struct client* client, off64_t from, int len) char zerobuffer[block_allocation_resolution]; /* not allocated, read in block_allocation_resoution */ while (run > 0) { - char *dst = client->mapped+from; - int bit = from/block_allocation_resolution; int blockrun = block_allocation_resolution - (from % block_allocation_resolution); if (blockrun > run) blockrun = run; - debug("writing partial: bit=%d, blockrun=%d (run=%d)", - bit, blockrun, run); - DO_READ(zerobuffer, blockrun); /* This reads the buffer twice in the worst case @@ -88,10 +81,9 @@ void write_not_zeroes(struct client* client, off64_t from, int len) */ if (zerobuffer[0] != 0 || memcmp(zerobuffer, zerobuffer + 1, blockrun - 1)) { - memcpy(dst, zerobuffer, blockrun); - bit_set(map, bit); + memcpy(client->mapped+from, zerobuffer, blockrun); + bitset_set_range(map, from, blockrun); server_dirty(client->serve, from, blockrun); - debug("non-zero, copied and set bit %d", bit); /* at this point we could choose to * short-cut the rest of the write for * faster I/O but by continuing to do it @@ -247,7 +239,7 @@ void client_reply_to_read( struct client* client, struct nbd_request request ) void client_reply_to_write( struct client* client, struct nbd_request request ) { debug("request write %ld+%d", request.from, request.len); - if (client->serve->block_allocation_map) { + if (client->serve->allocation_map) { write_not_zeroes( client, request.from, request.len ); } else { diff --git a/src/ioutil.c b/src/ioutil.c index f61ff12..159d6b9 100644 --- a/src/ioutil.c +++ b/src/ioutil.c @@ -14,10 +14,10 @@ #include "util.h" #include "bitset.h" -char* build_allocation_map(int fd, off64_t size, int resolution) +struct bitset_mapping* build_allocation_map(int fd, off64_t size, int resolution) { int i; - char *allocation_map = xmalloc((size+resolution)/resolution); + struct bitset_mapping* allocation_map = bitset_alloc(size, resolution); struct fiemap *fiemap_count, *fiemap; fiemap_count = (struct fiemap*) xmalloc(sizeof(struct fiemap)); @@ -49,27 +49,24 @@ char* build_allocation_map(int fd, off64_t size, int resolution) if (ioctl(fd, FS_IOC_FIEMAP, fiemap) < 0) return NULL; - for (i=0;ifm_mapped_extents;i++) { - int first_bit = fiemap->fm_extents[i].fe_logical / resolution; - int last_bit = (fiemap->fm_extents[i].fe_logical + - fiemap->fm_extents[i].fe_length + resolution - 1) / - resolution; - int run = last_bit - first_bit; - - bit_set_range(allocation_map, first_bit, run); - } + for (i=0;ifm_mapped_extents;i++) + bitset_set_range( + allocation_map, + fiemap->fm_extents[i].fe_logical, + fiemap->fm_extents[i].fe_length + ); for (i=0; i<16; i++) { debug("map[%d] = %d%d%d%d%d%d%d%d", i, - (allocation_map[i] & 1) == 1, - (allocation_map[i] & 2) == 2, - (allocation_map[i] & 4) == 4, - (allocation_map[i] & 8) == 8, - (allocation_map[i] & 16) == 16, - (allocation_map[i] & 32) == 32, - (allocation_map[i] & 64) == 64, - (allocation_map[i] & 128) == 128 + (allocation_map->bits[i] & 1) == 1, + (allocation_map->bits[i] & 2) == 2, + (allocation_map->bits[i] & 4) == 4, + (allocation_map->bits[i] & 8) == 8, + (allocation_map->bits[i] & 16) == 16, + (allocation_map->bits[i] & 32) == 32, + (allocation_map->bits[i] & 64) == 64, + (allocation_map->bits[i] & 128) == 128 ); } diff --git a/src/serve.c b/src/serve.c index f45dfaa..d211d8f 100644 --- a/src/serve.c +++ b/src/serve.c @@ -305,7 +305,7 @@ void serve_init_allocation_map(struct server* params) params->size = size; SERVER_ERROR_ON_FAILURE(size, "Couldn't find size of %s", params->filename); - params->block_allocation_map = + params->allocation_map = build_allocation_map(fd, size, block_allocation_resolution); close(fd); } @@ -336,7 +336,7 @@ void serve_cleanup(struct server* params) self_pipe_destroy( params->close_signal ); - free(params->block_allocation_map); + free(params->allocation_map); if (params->mirror) debug("mirror thread running! this should not happen!"); diff --git a/src/serve.h b/src/serve.h index 9cb4b48..9ec711a 100644 --- a/src/serve.h +++ b/src/serve.h @@ -69,7 +69,7 @@ struct server { int server_fd; int control_fd; - char* block_allocation_map; + struct bitset_mapping* allocation_map; struct { pthread_t thread; union mysockaddr address; } nbd_client[MAX_NBD_CLIENTS];