summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/kernel/dnbd3.h1
-rw-r--r--src/kernel/net.c170
2 files changed, 139 insertions, 32 deletions
diff --git a/src/kernel/dnbd3.h b/src/kernel/dnbd3.h
index 0e39dfb..787c7f1 100644
--- a/src/kernel/dnbd3.h
+++ b/src/kernel/dnbd3.h
@@ -70,6 +70,7 @@ typedef struct dnbd3_device {
struct mutex device_lock;
// network
+ uint8_t socks_active;
dnbd3_sock socks[NUMBER_CONNECTIONS];
char *imgname;
// struct socket *sock;
diff --git a/src/kernel/net.c b/src/kernel/net.c
index 0c3993d..2931aea 100644
--- a/src/kernel/net.c
+++ b/src/kernel/net.c
@@ -47,8 +47,10 @@
} while (0)
+static int dnbd3_socket_connect(dnbd3_device *dev, dnbd3_server *server);
+static int dnbd3_socket_disconnect(dnbd3_device *dev, dnbd3_server *server, dnbd3_sock *sock);
-static void printHost(struct dnbd3_host_t *host, char *msg)
+static void print_host(struct dnbd3_host_t *host, char *msg)
{
if (host->type == HOST_IP4) {
printk(KERN_INFO "dnbd3: %s %pI4:%d\n", msg, host->addr, host->port);
@@ -57,13 +59,13 @@ static void printHost(struct dnbd3_host_t *host, char *msg)
}
}
-static void printServerList(struct dnbd3_device *dev)
+static void print_server_list(struct dnbd3_device *dev)
{
int i;
- printHost(&dev->initial_server.host, "initial server is");
+ print_host(&dev->initial_server.host, "initial server is");
for (i = 0; i < NUMBER_SERVERS; i++) {
if (dev->alt_servers[i].host.addr[0] != 0) {
- printHost(&dev->alt_servers[i].host, "alternative server is");
+ print_host(&dev->alt_servers[i].host, "alternative server is");
}
}
}
@@ -263,7 +265,7 @@ consume_payload:
}
reported_size = serializer_get_uint64(&payload_buffer);
- if (dev->reported_size == NULL) {
+ if (!dev->reported_size) {
if (reported_size < 4096) {
printk(KERN_ERR "dnbd3: reported size by server is < 4096\n");
goto error;
@@ -290,7 +292,6 @@ error:
void dnbd3_keepalive(struct timer_list *arg)
{
struct dnbd3_sock *sock = container_of(arg, struct dnbd3_sock, keepalive_timer);
-// schedule_work(&sock->keepalive);
queue_work(dnbd3_wq, &sock->keepalive);
sock->keepalive_timer.expires = KEEPALIVE_TIMER;
add_timer(&sock->keepalive_timer);
@@ -328,37 +329,88 @@ static void discovery(struct work_struct *work)
struct dnbd3_device *dev = container_of(work, struct dnbd3_device, discovery);
dnbd3_sock *sock = &dev->socks[0]; // we use the first sock for discovery
struct request *req;
+ int i, j;
+ struct dnbd3_server *existing_server = NULL;
+ struct dnbd3_server *free_server = NULL;
+ struct dnbd3_server *failed_server = NULL;
+ dnbd3_server_entry_t *new_server;
printk(KERN_DEBUG "dnbd3: starting discovery worker\n");
mutex_lock(&sock->lock);
req = kmalloc(sizeof(struct request), GFP_ATOMIC );
// send keepalive
if (req) {
dnbd3_cmd_to_priv(req, CMD_GET_SERVERS);
- dnbd3_send_request(dev, sock, req); // we do not need the device for keepalive
+ dnbd3_send_request(dev, sock, req);
kfree(req);
} else {
printk(KERN_WARNING "dnbd3: could not create get servers request\n");
}
mutex_unlock(&sock->lock);
-}
+ printk(KERN_DEBUG "dnbd3: new server num is %d\n", dev->new_servers_num);
+ if (dev->new_servers_num) {
+ mutex_lock(&dev->device_lock);
-static int dnbd3_socket_connect(dnbd3_device *dev, dnbd3_sock *sock)
-{
- int result = -EIO;
- struct request *req = NULL;
- struct timeval timeout;
- struct dnbd3_server *server = sock->server;
- printk(KERN_DEBUG "dnbd3: socket connect device %i\n", dev->minor);
+ for (i = 0; i < dev->new_servers_num; i++) {
+ new_server = &dev->new_servers[i];
+ if (new_server->host.type == HOST_IP4 || new_server->host.type == HOST_IP6) {
+
+ // find servers in alt servers
+ for (j = 0; j < NUMBER_SERVERS; j++) {
+ if ((new_server->host.type == dev->alt_servers[j].host.type)
+ && (new_server->host.port == dev->alt_servers[j].host.port)
+ && (0 == memcmp(new_server->host.addr, dev->alt_servers[j].host.addr,
+ (new_server->host.type == HOST_IP4 ? 4 : 16)))) {
+
+ existing_server = &dev->alt_servers[j];
+ } else if (dev->alt_servers[j].host.type == 0) {
+ free_server = &dev->alt_servers[j];
+ } else if (dev->alt_servers[j].failures > 20) {
+ failed_server = &dev->alt_servers[j];
+ }
+ }
+
+ if (existing_server) {
+ if (new_server->failures == 1) { // remove is requested
+ print_host(&existing_server->host, "remove server");
+ dnbd3_socket_disconnect(dev, existing_server, NULL); // TODO what to do when only one connection?
+ existing_server->host.type = 0;
+ }
+ // ADD, so just reset fail counter
+// existing_server->failures = 0; makes no sense?
+ continue;
+ } else if (free_server) {
+ free_server->host = new_server->host;
+ } else if (failed_server) {
+ failed_server->host = new_server->host;
+ free_server = failed_server;
+ } else {
+ //no server found to replace
+ continue;
+ }
+ print_host(&free_server->host, "got new alt server");
+ free_server->failures = 0;
+ free_server->protocol_version = 0;
+ free_server->rtts[0] = free_server->rtts[1] = free_server->rtts[2] = free_server->rtts[3] = RTT_UNREACHABLE;
+ }
+ }
+ dev->new_servers_num = 0;
+ mutex_unlock(&dev->device_lock);
+ }
+
+ // measure rtt for all alt servers
+ for (i = 0; i < NUMBER_SERVERS; i++) {
+
+ }
+}
+static int __dnbd3_socket_connect(dnbd3_server * server, dnbd3_sock *sock)
+{
+ struct timeval timeout;
mutex_init(&sock->lock);
mutex_lock(&sock->lock);
- if (sock->pending) {
- printk(KERN_DEBUG "dnbd3: socket still in request\n");
- while (sock->pending)
- schedule();
- }
+
if (server->host.port == 0 || server->host.type == 0) {
printk(KERN_ERR "dnbd3: host or port not set\n");
goto error;
@@ -371,13 +423,6 @@ static int dnbd3_socket_connect(dnbd3_device *dev, dnbd3_sock *sock)
timeout.tv_sec = SOCKET_TIMEOUT_CLIENT_DATA;
timeout.tv_usec = 0;
- req = kmalloc(sizeof(*req), GFP_ATOMIC );
- if (!req) {
- printk(KERN_ERR "dnbd3: kmalloc failed\n");
- goto error;
- }
-
-
if (dnbd3_sock_create(server->host.type, SOCK_STREAM, IPPROTO_TCP, &sock->sock) < 0) {
printk(KERN_ERR "dnbd3: could not create socket\n");
goto error;
@@ -407,6 +452,49 @@ static int dnbd3_socket_connect(dnbd3_device *dev, dnbd3_sock *sock)
goto error;
}
}
+ mutex_unlock(&sock->lock);
+
+ return 0;
+error:
+ if (sock->sock) {
+ sock_release(sock->sock);
+ sock->sock = NULL;
+ }
+ mutex_unlock(&sock->lock);
+ mutex_destroy(&sock->lock);
+ return -EIO;
+}
+
+static int dnbd3_socket_connect(dnbd3_device *dev, dnbd3_server *server)
+{
+ int i;
+ int result = -EIO;
+ struct dnbd3_sock *sock = NULL;
+ struct request *req = NULL;
+ for (i = 0; i < NUMBER_CONNECTIONS; i++) {
+ if (!dev->socks[i].sock) {
+ sock = &dev->socks[i];
+ break;
+ }
+ }
+ if (sock == NULL) {
+ printk(KERN_WARNING "dnbd3: could not connect to socket, to many connections\n");
+ return -EIO;
+ }
+ sock->server = server;
+
+ printk(KERN_DEBUG "dnbd3: socket connect device %i\n", dev->minor);
+
+ __dnbd3_socket_connect(server, sock);
+
+ mutex_lock(&sock->lock);
+ req = kmalloc(sizeof(*req), GFP_ATOMIC );
+ if (!req) {
+ printk(KERN_ERR "dnbd3: kmalloc failed\n");
+ goto error;
+ }
+
+
dnbd3_connect(req);
result = dnbd3_send_request(dev, sock, req);
if (result) {
@@ -440,8 +528,22 @@ error:
return result;
}
-static int dnbd3_socket_disconnect(dnbd3_device *dev, dnbd3_sock *sock)
+
+static int dnbd3_socket_disconnect(dnbd3_device *dev, dnbd3_server *server, dnbd3_sock *sock)
{
+ int i;
+ if (sock == NULL) {
+ for (i = 0; i < NUMBER_CONNECTIONS; i++) {
+ if (dev->socks[i].server == server) {
+ sock = &dev->socks[i];
+ break;
+ }
+ }
+ if (!sock) {
+ printk(KERN_WARNING "dnbd3: could not find socket to disconnect\n");
+ return -EIO;
+ }
+ }
printk(KERN_DEBUG "dnbd3: socket disconnect device %i\n", dev->minor);
mutex_lock(&sock->lock);
@@ -460,6 +562,7 @@ static int dnbd3_socket_disconnect(dnbd3_device *dev, dnbd3_sock *sock)
mutex_unlock(&sock->lock);
mutex_destroy(&sock->lock);
+ sock->server = NULL;
return 0;
}
@@ -470,7 +573,7 @@ int dnbd3_net_disconnect(struct dnbd3_device *dev)
del_timer_sync(&dev->discovery_timer);
for (i = 0; i < NUMBER_CONNECTIONS; i++) {
if (dev->socks[i].sock) {
- if (dnbd3_socket_disconnect(dev, &dev->socks[i])) {
+ if (dnbd3_socket_disconnect(dev, NULL, &dev->socks[i])) {
result = -EIO;
}
}
@@ -482,15 +585,18 @@ int dnbd3_net_disconnect(struct dnbd3_device *dev)
int dnbd3_net_connect(struct dnbd3_device *dev) {
// TODO decide which socket to connect
int result;
- dev->socks[0].server = &dev->initial_server;
- if (dnbd3_socket_connect(dev, &dev->socks[0]) == 0) {
- printServerList(dev);
+ dev->socks_active = 0;
+ if (dnbd3_socket_connect(dev, &dev->alt_servers[0]) == 0) {
+ print_server_list(dev);
INIT_WORK(&dev->discovery, discovery);
timer_setup(&dev->discovery_timer, dnbd3_discovery, 0);
dev->discovery_timer.expires = DISCOVERY_TIMER;
add_timer(&dev->discovery_timer);
+ // let it discover alt servers
+ queue_work(dnbd3_wq, &dev->discovery);
+
result = 0;
} else {
printk(KERN_ERR "dnbd3: failed to connect to initial server\n");