Non-functioning commit, half-way through adding sparse bitmap feature.
This commit is contained in:
135
flexnbd.c
135
flexnbd.c
@@ -18,6 +18,10 @@
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/sendfile.h>
|
#include <sys/sendfile.h>
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/fiemap.h>
|
||||||
|
|
||||||
/* http://linux.derkeiler.com/Mailing-Lists/Kernel/2003-09/2332.html */
|
/* http://linux.derkeiler.com/Mailing-Lists/Kernel/2003-09/2332.html */
|
||||||
#define INIT_PASSWD "NBDMAGIC"
|
#define INIT_PASSWD "NBDMAGIC"
|
||||||
#define INIT_MAGIC 0x0000420281861253
|
#define INIT_MAGIC 0x0000420281861253
|
||||||
@@ -105,11 +109,18 @@ void error(int consult_errno, int close_socket, const char* format, ...)
|
|||||||
#define SERVER_ERROR_ON_FAILURE(test, msg, ...) \
|
#define SERVER_ERROR_ON_FAILURE(test, msg, ...) \
|
||||||
if (test < 0) { error(1, 0, msg, ##__VA_ARGS__); }
|
if (test < 0) { error(1, 0, msg, ##__VA_ARGS__); }
|
||||||
|
|
||||||
|
void* xrealloc(void* ptr, size_t size)
|
||||||
|
{
|
||||||
|
void* p = realloc(ptr, size);
|
||||||
|
if (p == NULL)
|
||||||
|
SERVER_ERROR("couldn't xrealloc %d bytes", size);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
void* xmalloc(size_t size)
|
void* xmalloc(size_t size)
|
||||||
{
|
{
|
||||||
void* p = malloc(size);
|
void* p = xrealloc(NULL, size);
|
||||||
if (p == NULL)
|
memset(p, 0, size);
|
||||||
SERVER_ERROR("couldn't malloc %d bytes", size);
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,8 +143,11 @@ struct mode_serve_params {
|
|||||||
char* filename;
|
char* filename;
|
||||||
int tcp_backlog;
|
int tcp_backlog;
|
||||||
|
|
||||||
int server;
|
int server;
|
||||||
int threads;
|
int threads;
|
||||||
|
|
||||||
|
pthread_mutex_t block_allocation_map_lock;
|
||||||
|
char* block_allocation_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mode_readwrite_params {
|
struct mode_readwrite_params {
|
||||||
@@ -151,13 +165,94 @@ struct client_params {
|
|||||||
int fileno;
|
int fileno;
|
||||||
off64_t size;
|
off64_t size;
|
||||||
char* mapped;
|
char* mapped;
|
||||||
};
|
|
||||||
|
pthread_mutex_t block_allocation_map_lock;
|
||||||
|
char* block_allocation_map;
|
||||||
|
}};
|
||||||
|
|
||||||
union mode_params {
|
union mode_params {
|
||||||
struct mode_serve_params serve;
|
struct mode_serve_params serve;
|
||||||
struct mode_readwrite_params readwrite;
|
struct mode_readwrite_params readwrite;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline int char_with_bit_set(int num) {
|
||||||
|
return 1<<(num%8);
|
||||||
|
}
|
||||||
|
static inline int bit_is_set(char* b, int idx) {
|
||||||
|
return (b[idx/8] & char_with_bit_set(idx)) != 0;
|
||||||
|
}
|
||||||
|
static inline int bit_is_clear(char* b, int idx) {
|
||||||
|
return !bit_is_set(b, idx);
|
||||||
|
}
|
||||||
|
static inline void bit_set(char* b, int idx) {
|
||||||
|
b[idx/8] &= char_with_bit_set(idx);
|
||||||
|
}
|
||||||
|
static inline void bit_clear(char* b, int idx) {
|
||||||
|
b[idx/8] &= ~char_with_bit_set(idx);
|
||||||
|
}
|
||||||
|
static inline void bit_set_range(char* b, int from, int len) {
|
||||||
|
for (; b%8 != 0 && len > 0; len--)
|
||||||
|
bit_set(b, from++, 1);
|
||||||
|
if (len >= 8)
|
||||||
|
memset(b+(from/8), 255, len/8);
|
||||||
|
for (; len > 0; len--)
|
||||||
|
bit_set(b, from++);
|
||||||
|
}
|
||||||
|
static inline void bit_clear_range(char* b, int from, int len) {
|
||||||
|
for (; b%8 != 0 && len > 0; len--)
|
||||||
|
bit_clear(b, from++, 1);
|
||||||
|
if (len >= 8)
|
||||||
|
memset(b+(from/8), 0, len/8);
|
||||||
|
for (; len > 0; len--)
|
||||||
|
bit_clear(b, from++);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char* build_allocation_map(int fd, off64_t size, int resolution)
|
||||||
|
{
|
||||||
|
char *allocation_map = xmalloc((size+resolution)/resolution);
|
||||||
|
struct fiemap *fiemap;
|
||||||
|
|
||||||
|
fiemap = (struct fiemap*) xmalloc(sizeof(struct fiemap));
|
||||||
|
|
||||||
|
fiemap->fm_start = from;
|
||||||
|
fiemap->fm_length = len;
|
||||||
|
fiemap->fm_flags = 0;
|
||||||
|
fiemap->fm_extent_count = 0;
|
||||||
|
fiemap->fm_mapped_extents = 0;
|
||||||
|
|
||||||
|
/* Find out how many extents there are */
|
||||||
|
if (ioctl(fd, FS_IOC_FIEMAP, fiemap) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Resize fiemap to allow us to read in the extents */
|
||||||
|
fiemap = (struct fiemap*)xrealloc(
|
||||||
|
fiemap,
|
||||||
|
sizeof(struct fiemap) + (
|
||||||
|
sizeof(struct fiemap_extent) *
|
||||||
|
fiemap->fm_mapped_extents
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
fiemap->fm_extent_count = fiemap->fm_mapped_extents;
|
||||||
|
fiemap->fm_mapped_extents = 0;
|
||||||
|
|
||||||
|
if (ioctl(fd, FS_IOC_FIEMAP, fiemap) < -1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i=0;i<fiemap->fm_mapped_extents;i++)
|
||||||
|
bit_set_range(
|
||||||
|
allocation_map,
|
||||||
|
fiemap->fm_extents[i].fe_logical / resolution,
|
||||||
|
fiemap->fm_extents[i].fe_length / resolution
|
||||||
|
);
|
||||||
|
|
||||||
|
free(fiemap);
|
||||||
|
|
||||||
|
return allocation_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int writeloop(int filedes, const void *buffer, size_t size)
|
int writeloop(int filedes, const void *buffer, size_t size)
|
||||||
{
|
{
|
||||||
size_t written=0;
|
size_t written=0;
|
||||||
@@ -223,6 +318,7 @@ int client_serve_request(struct client_params* client)
|
|||||||
off64_t offset;
|
off64_t offset;
|
||||||
struct nbd_request request;
|
struct nbd_request request;
|
||||||
struct nbd_reply reply;
|
struct nbd_reply reply;
|
||||||
|
struct unallocated_block** unallocated;
|
||||||
|
|
||||||
if (readloop(client->socket, &request, sizeof(request)) == -1) {
|
if (readloop(client->socket, &request, sizeof(request)) == -1) {
|
||||||
if (errno == 0) {
|
if (errno == 0) {
|
||||||
@@ -273,7 +369,7 @@ int client_serve_request(struct client_params* client)
|
|||||||
case REQUEST_READ:
|
case REQUEST_READ:
|
||||||
debug("request read %ld+%d", be64toh(request.from), be32toh(request.len));
|
debug("request read %ld+%d", be64toh(request.from), be32toh(request.len));
|
||||||
write(client->socket, &reply, sizeof(reply));
|
write(client->socket, &reply, sizeof(reply));
|
||||||
|
|
||||||
offset = be64toh(request.from);
|
offset = be64toh(request.from);
|
||||||
CLIENT_ERROR_ON_FAILURE(
|
CLIENT_ERROR_ON_FAILURE(
|
||||||
sendfileloop(
|
sendfileloop(
|
||||||
@@ -290,6 +386,21 @@ int client_serve_request(struct client_params* client)
|
|||||||
|
|
||||||
case REQUEST_WRITE:
|
case REQUEST_WRITE:
|
||||||
debug("request write %ld+%d", be64toh(request.from), be32toh(request.len));
|
debug("request write %ld+%d", be64toh(request.from), be32toh(request.len));
|
||||||
|
#ifdef _LINUX_FIEMAP_H
|
||||||
|
unallocated = read_unallocated_blocks(
|
||||||
|
client->fileno,
|
||||||
|
be64toh(request.from),
|
||||||
|
be32toh(request.len)
|
||||||
|
);
|
||||||
|
if (unallocated == NULL)
|
||||||
|
CLIENT_ERROR("Couldn't read unallocated blocks list");
|
||||||
|
|
||||||
|
CLIENT_ERROR_ON_FAILURE(
|
||||||
|
read_from_socket_avoiding_holes(
|
||||||
|
client->socket,
|
||||||
|
);
|
||||||
|
free(fiemap);
|
||||||
|
#else
|
||||||
CLIENT_ERROR_ON_FAILURE(
|
CLIENT_ERROR_ON_FAILURE(
|
||||||
readloop(
|
readloop(
|
||||||
client->socket,
|
client->socket,
|
||||||
@@ -300,6 +411,7 @@ int client_serve_request(struct client_params* client)
|
|||||||
be64toh(request.from),
|
be64toh(request.from),
|
||||||
be32toh(request.len)
|
be32toh(request.len)
|
||||||
);
|
);
|
||||||
|
#endif
|
||||||
write(client->socket, &reply, sizeof(reply));
|
write(client->socket, &reply, sizeof(reply));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -356,7 +468,6 @@ void* client_serve(void* client_uncast)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME */
|
|
||||||
static int testmasks[9] = { 0,128,192,224,240,248,252,254,255 };
|
static int testmasks[9] = { 0,128,192,224,240,248,252,254,255 };
|
||||||
|
|
||||||
int is_included_in_acl(int list_length, struct ip_and_mask** list, struct sockaddr* test)
|
int is_included_in_acl(int list_length, struct ip_and_mask** list, struct sockaddr* test)
|
||||||
@@ -434,7 +545,7 @@ void serve_accept_loop(struct mode_serve_params* params)
|
|||||||
pthread_t client_thread;
|
pthread_t client_thread;
|
||||||
struct sockaddr client_address;
|
struct sockaddr client_address;
|
||||||
struct client_params* client_params;
|
struct client_params* client_params;
|
||||||
socklen_t socket_length;
|
socklen_t socket_length=0;
|
||||||
|
|
||||||
int client_socket = accept(params->server, &client_address,
|
int client_socket = accept(params->server, &client_address,
|
||||||
&socket_length);
|
&socket_length);
|
||||||
@@ -451,6 +562,10 @@ void serve_accept_loop(struct mode_serve_params* params)
|
|||||||
client_params = xmalloc(sizeof(struct client_params));
|
client_params = xmalloc(sizeof(struct client_params));
|
||||||
client_params->socket = client_socket;
|
client_params->socket = client_socket;
|
||||||
client_params->filename = params->filename;
|
client_params->filename = params->filename;
|
||||||
|
client_params->block_allocation_map =
|
||||||
|
params->block_allocation_map;
|
||||||
|
client_params->block_allocation_map_lock =
|
||||||
|
params->block_allocation_map_lock;
|
||||||
|
|
||||||
client_thread = pthread_create(&client_thread, NULL,
|
client_thread = pthread_create(&client_thread, NULL,
|
||||||
client_serve, client_params);
|
client_serve, client_params);
|
||||||
@@ -685,8 +800,6 @@ void params_serve(
|
|||||||
if (parsed != acl_entries)
|
if (parsed != acl_entries)
|
||||||
SERVER_ERROR("Bad ACL entry '%s'", s_acl_entries[parsed]);
|
SERVER_ERROR("Bad ACL entry '%s'", s_acl_entries[parsed]);
|
||||||
|
|
||||||
debug("%p %d", out->acl, out->acl_entries);
|
|
||||||
|
|
||||||
out->bind_to.v4.sin_port = atoi(s_port);
|
out->bind_to.v4.sin_port = atoi(s_port);
|
||||||
if (out->bind_to.v4.sin_port < 0 || out->bind_to.v4.sin_port > 65535)
|
if (out->bind_to.v4.sin_port < 0 || out->bind_to.v4.sin_port > 65535)
|
||||||
SERVER_ERROR("Port number must be >= 0 and <= 65535");
|
SERVER_ERROR("Port number must be >= 0 and <= 65535");
|
||||||
|
Reference in New Issue
Block a user