summaryrefslogtreecommitdiffstats
path: root/src/kernel
diff options
context:
space:
mode:
authorsr2012-09-03 15:27:36 +0200
committersr2012-09-03 15:27:36 +0200
commita55be46ec7a281f5c3d41d48edf32e57ef5e4ba1 (patch)
treed375eaf63e03a6e1b5e199712735a68b448c6d97 /src/kernel
parent[SERVER] Add list of trusted servers and namespaces (load, display) (diff)
downloaddnbd3-a55be46ec7a281f5c3d41d48edf32e57ef5e4ba1.tar.gz
dnbd3-a55be46ec7a281f5c3d41d48edf32e57ef5e4ba1.tar.xz
dnbd3-a55be46ec7a281f5c3d41d48edf32e57ef5e4ba1.zip
[*] Fixed and unified formatting
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/blk.c320
-rw-r--r--src/kernel/core.c60
-rw-r--r--src/kernel/dnbd3.h70
-rw-r--r--src/kernel/net.c1472
-rw-r--r--src/kernel/sysfs.c116
-rw-r--r--src/kernel/sysfs.h12
-rw-r--r--src/kernel/utils.c22
-rw-r--r--src/kernel/utils.h2
8 files changed, 1040 insertions, 1034 deletions
diff --git a/src/kernel/blk.c b/src/kernel/blk.c
index 35252c4..bc138c3 100644
--- a/src/kernel/blk.c
+++ b/src/kernel/blk.c
@@ -26,120 +26,120 @@
int dnbd3_blk_add_device(dnbd3_device_t *dev, int minor)
{
- struct gendisk *disk;
- struct request_queue *blk_queue;
+ struct gendisk *disk;
+ struct request_queue *blk_queue;
- init_waitqueue_head(&dev->process_queue_send);
- init_waitqueue_head(&dev->process_queue_receive);
- init_waitqueue_head(&dev->process_queue_discover);
- INIT_LIST_HEAD(&dev->request_queue_send);
- INIT_LIST_HEAD(&dev->request_queue_receive);
+ init_waitqueue_head(&dev->process_queue_send);
+ init_waitqueue_head(&dev->process_queue_receive);
+ init_waitqueue_head(&dev->process_queue_discover);
+ INIT_LIST_HEAD(&dev->request_queue_send);
+ INIT_LIST_HEAD(&dev->request_queue_receive);
- memset(&dev->cur_server, 0, sizeof(dev->cur_server));
- memset(&dev->initial_server, 0, sizeof(dev->initial_server));
- dev->better_sock = NULL;
+ memset(&dev->cur_server, 0, sizeof(dev->cur_server));
+ memset(&dev->initial_server, 0, sizeof(dev->initial_server));
+ dev->better_sock = NULL;
- dev->imgname = NULL;
- dev->rid = 0;
- dev->update_available = 0;
- memset(dev->alt_servers, 0, sizeof(dev->alt_servers[0])*NUMBER_SERVERS);
- dev->thread_send = NULL;
- dev->thread_receive = NULL;
- dev->thread_discover = NULL;
- dev->discover = 0;
- dev->panic = 0;
- dev->panic_count = 0;
- dev->reported_size = 0;
+ dev->imgname = NULL;
+ dev->rid = 0;
+ dev->update_available = 0;
+ memset(dev->alt_servers, 0, sizeof(dev->alt_servers[0])*NUMBER_SERVERS);
+ dev->thread_send = NULL;
+ dev->thread_receive = NULL;
+ dev->thread_discover = NULL;
+ dev->discover = 0;
+ dev->panic = 0;
+ dev->panic_count = 0;
+ dev->reported_size = 0;
- if (!(disk = alloc_disk(1)))
- {
- printk("ERROR: dnbd3 alloc_disk failed.\n");
- return -EIO;
- }
+ if (!(disk = alloc_disk(1)))
+ {
+ printk("ERROR: dnbd3 alloc_disk failed.\n");
+ return -EIO;
+ }
- disk->major = major;
- disk->first_minor = minor;
- sprintf(disk->disk_name, "dnbd%d", minor);
- set_capacity(disk, 0);
- set_disk_ro(disk, 1);
- disk->fops = &dnbd3_blk_ops;
+ disk->major = major;
+ disk->first_minor = minor;
+ sprintf(disk->disk_name, "dnbd%d", minor);
+ set_capacity(disk, 0);
+ set_disk_ro(disk, 1);
+ disk->fops = &dnbd3_blk_ops;
- spin_lock_init(&dev->blk_lock);
- if ((blk_queue = blk_init_queue(&dnbd3_blk_request, &dev->blk_lock)) == NULL)
- {
- printk("ERROR: dnbd3 blk_init_queue failed.\n");
- return -EIO;
- }
+ spin_lock_init(&dev->blk_lock);
+ if ((blk_queue = blk_init_queue(&dnbd3_blk_request, &dev->blk_lock)) == NULL)
+ {
+ printk("ERROR: dnbd3 blk_init_queue failed.\n");
+ return -EIO;
+ }
- blk_queue_logical_block_size(blk_queue, DNBD3_BLOCK_SIZE);
- blk_queue_physical_block_size(blk_queue, DNBD3_BLOCK_SIZE);
+ blk_queue_logical_block_size(blk_queue, DNBD3_BLOCK_SIZE);
+ blk_queue_physical_block_size(blk_queue, DNBD3_BLOCK_SIZE);
- disk->queue = blk_queue;
- disk->private_data = dev;
- queue_flag_set_unlocked(QUEUE_FLAG_NONROT, disk->queue);
- dev->disk = disk;
+ disk->queue = blk_queue;
+ disk->private_data = dev;
+ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, disk->queue);
+ dev->disk = disk;
- add_disk(disk);
- dnbd3_sysfs_init(dev);
- return 0;
+ add_disk(disk);
+ dnbd3_sysfs_init(dev);
+ return 0;
}
int dnbd3_blk_del_device(dnbd3_device_t *dev)
{
dnbd3_sysfs_exit(dev);
dnbd3_net_disconnect(dev);
- del_gendisk(dev->disk);
- put_disk(dev->disk);
- blk_cleanup_queue(dev->disk->queue);
- return 0;
+ del_gendisk(dev->disk);
+ put_disk(dev->disk);
+ blk_cleanup_queue(dev->disk->queue);
+ return 0;
}
struct block_device_operations dnbd3_blk_ops =
-{ .owner = THIS_MODULE, .ioctl = dnbd3_blk_ioctl, };
+ { .owner = THIS_MODULE, .ioctl = dnbd3_blk_ioctl, };
int dnbd3_blk_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg)
{
- int result = 0;
- dnbd3_device_t *dev = bdev->bd_disk->private_data;
- struct request_queue *blk_queue = dev->disk->queue;
- char *imgname = NULL;
- dnbd3_ioctl_t *msg = kmalloc(sizeof(*msg), GFP_KERNEL);
- unsigned long irqflags;
+ int result = 0;
+ dnbd3_device_t *dev = bdev->bd_disk->private_data;
+ struct request_queue *blk_queue = dev->disk->queue;
+ char *imgname = NULL;
+ dnbd3_ioctl_t *msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+ unsigned long irqflags;
- if (msg == NULL) return -ENOMEM;
- copy_from_user((char *)msg, (char *)arg, 2);
- if (msg->len != sizeof(*msg))
- {
- result = -ENOEXEC;
- goto cleanup_return;
- }
- copy_from_user((char *)msg, (char *)arg, sizeof(*msg));
- if (msg->imgname != NULL && msg->imgnamelen > 0)
- {
- imgname = kmalloc(msg->imgnamelen + 1, GFP_KERNEL);
- if (imgname == NULL)
- {
- result = -ENOMEM;
- goto cleanup_return;
- }
- copy_from_user(imgname, msg->imgname, msg->imgnamelen);
- imgname[msg->imgnamelen] = '\0';
- //printk("IOCTL Image name of len %d is %s\n", (int)msg->imgnamelen, imgname);
- }
+ if (msg == NULL) return -ENOMEM;
+ copy_from_user((char *)msg, (char *)arg, 2);
+ if (msg->len != sizeof(*msg))
+ {
+ result = -ENOEXEC;
+ goto cleanup_return;
+ }
+ copy_from_user((char *)msg, (char *)arg, sizeof(*msg));
+ if (msg->imgname != NULL && msg->imgnamelen > 0)
+ {
+ imgname = kmalloc(msg->imgnamelen + 1, GFP_KERNEL);
+ if (imgname == NULL)
+ {
+ result = -ENOMEM;
+ goto cleanup_return;
+ }
+ copy_from_user(imgname, msg->imgname, msg->imgnamelen);
+ imgname[msg->imgnamelen] = '\0';
+ //printk("IOCTL Image name of len %d is %s\n", (int)msg->imgnamelen, imgname);
+ }
- switch (cmd)
- {
- case IOCTL_OPEN:
- if (dev->imgname != NULL)
- {
- result = -EBUSY;
- }
- else if (imgname == NULL)
- {
- result = -EINVAL;
- }
- else
- {
+ switch (cmd)
+ {
+ case IOCTL_OPEN:
+ if (dev->imgname != NULL)
+ {
+ result = -EBUSY;
+ }
+ else if (imgname == NULL)
+ {
+ result = -EINVAL;
+ }
+ else
+ {
memcpy(dev->cur_server.hostaddr, msg->addr, 16);
dev->cur_server.port = msg->port;
dev->cur_server.hostaddrtype = msg->addrtype;
@@ -159,105 +159,105 @@ int dnbd3_blk_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, u
result = -ENOENT;
dev->imgname = NULL;
}
- }
- break;
+ }
+ break;
- case IOCTL_CLOSE:
- dnbd3_blk_fail_all_requests(dev);
- result = dnbd3_net_disconnect(dev);
- dnbd3_blk_fail_all_requests(dev);
- set_capacity(dev->disk, 0);
- if (dev->imgname)
- {
- kfree(dev->imgname);
- dev->imgname = NULL;
- }
- break;
+ case IOCTL_CLOSE:
+ dnbd3_blk_fail_all_requests(dev);
+ result = dnbd3_net_disconnect(dev);
+ dnbd3_blk_fail_all_requests(dev);
+ set_capacity(dev->disk, 0);
+ if (dev->imgname)
+ {
+ kfree(dev->imgname);
+ dev->imgname = NULL;
+ }
+ break;
- case IOCTL_SWITCH:
- dnbd3_net_disconnect(dev);
+ case IOCTL_SWITCH:
+ dnbd3_net_disconnect(dev);
memcpy(dev->cur_server.hostaddr, msg->addr, 16);
dev->cur_server.port = msg->port;
dev->cur_server.hostaddrtype = msg->addrtype;
- result = dnbd3_net_connect(dev);
- break;
+ result = dnbd3_net_connect(dev);
+ break;
- case IOCTL_ADD_SRV:
- case IOCTL_REM_SRV:
- if (dev->imgname == NULL)
- {
- result = -ENOENT;
- }
- else
- {
- spin_lock_irqsave(&dev->blk_lock, irqflags);
- if (dev->new_servers_num >= NUMBER_SERVERS)
- result = -EAGAIN;
- else
- {
+ case IOCTL_ADD_SRV:
+ case IOCTL_REM_SRV:
+ if (dev->imgname == NULL)
+ {
+ result = -ENOENT;
+ }
+ else
+ {
+ spin_lock_irqsave(&dev->blk_lock, irqflags);
+ if (dev->new_servers_num >= NUMBER_SERVERS)
+ result = -EAGAIN;
+ else
+ {
memcpy(dev->new_servers[dev->new_servers_num].hostaddr, msg->addr, 16);
dev->new_servers[dev->new_servers_num].port = msg->port;
dev->new_servers[dev->new_servers_num].hostaddrtype = msg->addrtype;
dev->new_servers[dev->new_servers_num].failures = (cmd == IOCTL_ADD_SRV ? 0 : 1); // 0 = ADD, 1 = REM
++dev->new_servers_num;
result = 0;
- }
- spin_unlock_irqrestore(&dev->blk_lock, irqflags);
- }
- break;
+ }
+ spin_unlock_irqrestore(&dev->blk_lock, irqflags);
+ }
+ break;
- case BLKFLSBUF:
- break;
+ case BLKFLSBUF:
+ break;
- default:
- result = -EIO;
- break;
- }
+ default:
+ result = -EIO;
+ break;
+ }
cleanup_return:
- if (msg) kfree(msg);
- if (imgname) kfree(imgname);
- return result;
+ if (msg) kfree(msg);
+ if (imgname) kfree(imgname);
+ return result;
}
void dnbd3_blk_request(struct request_queue *q)
{
- struct request *req;
- dnbd3_device_t *dev;
+ struct request *req;
+ dnbd3_device_t *dev;
- while ((req = blk_fetch_request(q)) != NULL)
- {
- dev = req->rq_disk->private_data;
+ while ((req = blk_fetch_request(q)) != NULL)
+ {
+ dev = req->rq_disk->private_data;
- if (dev->imgname == NULL)
- {
- __blk_end_request_all(req, -EIO);
- continue;
- }
+ if (dev->imgname == NULL)
+ {
+ __blk_end_request_all(req, -EIO);
+ continue;
+ }
- if (req->cmd_type != REQ_TYPE_FS)
- {
- __blk_end_request_all(req, 0);
- continue;
- }
+ if (req->cmd_type != REQ_TYPE_FS)
+ {
+ __blk_end_request_all(req, 0);
+ continue;
+ }
- if (dev->panic_count >= PROBE_COUNT_TIMEOUT)
- {
- __blk_end_request_all(req, -EIO);
- continue;
- }
+ if (dev->panic_count >= PROBE_COUNT_TIMEOUT)
+ {
+ __blk_end_request_all(req, -EIO);
+ continue;
+ }
- if (rq_data_dir(req) != READ)
- {
- __blk_end_request_all(req, -EACCES);
- continue;
- }
+ if (rq_data_dir(req) != READ)
+ {
+ __blk_end_request_all(req, -EACCES);
+ continue;
+ }
list_add_tail(&req->queuelist, &dev->request_queue_send);
spin_unlock_irq(q->queue_lock);
wake_up(&dev->process_queue_send);
spin_lock_irq(q->queue_lock);
- }
+ }
}
void dnbd3_blk_fail_all_requests(dnbd3_device_t *dev)
diff --git a/src/kernel/core.c b/src/kernel/core.c
index 1be29a2..4b4b093 100644
--- a/src/kernel/core.c
+++ b/src/kernel/core.c
@@ -27,47 +27,47 @@ static dnbd3_device_t *dnbd3_device;
static int __init dnbd3_init(void)
{
- int i;
+ int i;
- dnbd3_device = kcalloc(max_devs, sizeof(*dnbd3_device), GFP_KERNEL);
- if (!dnbd3_device)
- return -ENOMEM;
+ dnbd3_device = kcalloc(max_devs, sizeof(*dnbd3_device), GFP_KERNEL);
+ if (!dnbd3_device)
+ return -ENOMEM;
- // initialize block device
- if ((major = register_blkdev(0, "dnbd3")) == 0)
- {
- printk("ERROR: dnbd3 register_blkdev failed.\n");
- return -EIO;
- }
+ // initialize block device
+ if ((major = register_blkdev(0, "dnbd3")) == 0)
+ {
+ printk("ERROR: dnbd3 register_blkdev failed.\n");
+ return -EIO;
+ }
- printk("DNBD3 kernel module loaded. Machine type: " ENDIAN_MODE "\n");
+ printk("DNBD3 kernel module loaded. Machine type: " ENDIAN_MODE "\n");
- // add MAX_NUMBER_DEVICES devices
- for (i = 0; i < max_devs; i++)
- {
- if (dnbd3_blk_add_device(&dnbd3_device[i], i) != 0)
- {
- printk("ERROR: adding device failed.\n");
- return -EIO; // TODO: delete all devices added so far. it could happen that it's not the first one that fails. also call unregister_blkdev and free memory
- }
- }
+ // add MAX_NUMBER_DEVICES devices
+ for (i = 0; i < max_devs; i++)
+ {
+ if (dnbd3_blk_add_device(&dnbd3_device[i], i) != 0)
+ {
+ printk("ERROR: adding device failed.\n");
+ return -EIO; // TODO: delete all devices added so far. it could happen that it's not the first one that fails. also call unregister_blkdev and free memory
+ }
+ }
- printk("INFO: dnbd3 init successful (%i devices).\n", max_devs);
- return 0;
+ printk("INFO: dnbd3 init successful (%i devices).\n", max_devs);
+ return 0;
}
static void __exit dnbd3_exit(void)
{
- int i;
+ int i;
- for (i = 0; i < max_devs; i++)
- {
- dnbd3_blk_del_device(&dnbd3_device[i]);
- }
+ for (i = 0; i < max_devs; i++)
+ {
+ dnbd3_blk_del_device(&dnbd3_device[i]);
+ }
- unregister_blkdev(major, "dnbd3");
- kfree(dnbd3_device);
- printk("INFO: dnbd3 exit.\n");
+ unregister_blkdev(major, "dnbd3");
+ kfree(dnbd3_device);
+ printk("INFO: dnbd3 exit.\n");
}
module_init( dnbd3_init);
diff --git a/src/kernel/dnbd3.h b/src/kernel/dnbd3.h
index 00cc676..fb83575 100644
--- a/src/kernel/dnbd3.h
+++ b/src/kernel/dnbd3.h
@@ -35,48 +35,48 @@ extern int major;
typedef struct
{
- unsigned long rtts[4]; // Last four round trip time measurements in µs
- uint16_t port; // Port in network representation
- uint16_t protocol_version; // dnbd3 protocol version of this server
- uint8_t hostaddr[16]; // Address in network representation (IPv4 or IPv6)
- uint8_t hostaddrtype; // Address type (AF_INET or AF_INET6)
- uint8_t failures; // How many times the server was unreachable
+ unsigned long rtts[4]; // Last four round trip time measurements in µs
+ uint16_t port; // Port in network representation
+ uint16_t protocol_version; // dnbd3 protocol version of this server
+ uint8_t hostaddr[16]; // Address in network representation (IPv4 or IPv6)
+ uint8_t hostaddrtype; // Address type (AF_INET or AF_INET6)
+ uint8_t failures; // How many times the server was unreachable
} dnbd3_server_t;
typedef struct
{
- // block
- struct gendisk *disk;
- spinlock_t blk_lock;
+ // block
+ struct gendisk *disk;
+ spinlock_t blk_lock;
- // sysfs
- struct kobject kobj;
+ // sysfs
+ struct kobject kobj;
- // network
- char *imgname;
- struct socket *sock;
- dnbd3_server_t cur_server, initial_server;
- unsigned long cur_rtt;
- serialized_buffer_t payload_buffer;
- dnbd3_server_t alt_servers[NUMBER_SERVERS]; // array of alt servers
- int new_servers_num; // number of new alt servers that are waiting to be copied to above array
- dnbd3_server_entry_t new_servers[NUMBER_SERVERS]; // pending new alt servers
- uint8_t discover, panic, disconnecting, is_server, update_available, panic_count;
- uint16_t rid, heartbeat_count;
- uint64_t reported_size;
- // server switch
- struct socket *better_sock;
+ // network
+ char *imgname;
+ struct socket *sock;
+ dnbd3_server_t cur_server, initial_server;
+ unsigned long cur_rtt;
+ serialized_buffer_t payload_buffer;
+ dnbd3_server_t alt_servers[NUMBER_SERVERS]; // array of alt servers
+ int new_servers_num; // number of new alt servers that are waiting to be copied to above array
+ dnbd3_server_entry_t new_servers[NUMBER_SERVERS]; // pending new alt servers
+ uint8_t discover, panic, disconnecting, is_server, update_available, panic_count;
+ uint16_t rid, heartbeat_count;
+ uint64_t reported_size;
+ // server switch
+ struct socket *better_sock;
- // process
- struct task_struct *thread_send;
- struct task_struct *thread_receive;
- struct task_struct *thread_discover;
- struct timer_list hb_timer;
- wait_queue_head_t process_queue_send;
- wait_queue_head_t process_queue_receive;
- wait_queue_head_t process_queue_discover;
- struct list_head request_queue_send;
- struct list_head request_queue_receive;
+ // process
+ struct task_struct *thread_send;
+ struct task_struct *thread_receive;
+ struct task_struct *thread_discover;
+ struct timer_list hb_timer;
+ wait_queue_head_t process_queue_send;
+ wait_queue_head_t process_queue_receive;
+ wait_queue_head_t process_queue_discover;
+ struct list_head request_queue_send;
+ struct list_head request_queue_receive;
} dnbd3_device_t;
diff --git a/src/kernel/net.c b/src/kernel/net.c
index b116ad6..2cd3cac 100644
--- a/src/kernel/net.c
+++ b/src/kernel/net.c
@@ -77,21 +77,21 @@
#define error_alt_va(x, ...) goto error
#endif
-static inline int is_same_server(const dnbd3_server_t * const a, const dnbd3_server_t * const b)
+static inline int is_same_server(const dnbd3_server_t *const a, const dnbd3_server_t *const b)
{
return (a->hostaddrtype == b->hostaddrtype)
- && (a->port == b->port)
- && (0 == memcmp(a->hostaddr, b->hostaddr, (a->hostaddrtype == AF_INET ? 4 : 16)));
+ && (a->port == b->port)
+ && (0 == memcmp(a->hostaddr, b->hostaddr, (a->hostaddrtype == AF_INET ? 4 : 16)));
}
-static inline dnbd3_server_t* get_existing_server(const dnbd3_server_entry_t * const newserver, dnbd3_device_t * const dev)
+static inline dnbd3_server_t *get_existing_server(const dnbd3_server_entry_t *const newserver, dnbd3_device_t *const dev)
{
int i;
for (i = 0; i < NUMBER_SERVERS; ++i)
{
if ((newserver->hostaddrtype == dev->alt_servers[i].hostaddrtype)
- && (newserver->port == dev->alt_servers[i].port)
- && (0 == memcmp(newserver->hostaddr, dev->alt_servers[i].hostaddr, (newserver->hostaddrtype == AF_INET ? 4 : 16))))
+ && (newserver->port == dev->alt_servers[i].port)
+ && (0 == memcmp(newserver->hostaddr, dev->alt_servers[i].hostaddr, (newserver->hostaddrtype == AF_INET ? 4 : 16))))
{
return &dev->alt_servers[i];
break;
@@ -100,7 +100,7 @@ static inline dnbd3_server_t* get_existing_server(const dnbd3_server_entry_t * c
return NULL;
}
-static inline dnbd3_server_t* get_free_alt_server(dnbd3_device_t * const dev)
+static inline dnbd3_server_t *get_free_alt_server(dnbd3_device_t *const dev)
{
int i;
for (i = 0; i < NUMBER_SERVERS; ++i)
@@ -119,60 +119,61 @@ static inline dnbd3_server_t* get_free_alt_server(dnbd3_device_t * const dev)
int dnbd3_net_connect(dnbd3_device_t *dev)
{
- struct sockaddr_in sin;
- struct request *req1 = NULL;
-
- struct timeval timeout;
-
- char get_servers = 0, set_client = 0;
-
- timeout.tv_sec = SOCKET_TIMEOUT_CLIENT_DATA;
- timeout.tv_usec = 0;
-
- // do some checks before connecting
-
- if (is_same_server(&dev->cur_server, &dev->initial_server))
- {
- // Forget all known alt servers
- memset(dev->alt_servers, 0, sizeof(dev->alt_servers[0])*NUMBER_SERVERS);
- memcpy(dev->alt_servers, &dev->initial_server, sizeof(dev->alt_servers[0]));
- if (!dev->is_server)
- {
- get_servers = 1;
- }
- }
- if (dev->better_sock)
- {
- set_client = 1;
- }
-
- if (get_servers || set_client)
- {
+ struct sockaddr_in sin;
+ struct request *req1 = NULL;
+
+ struct timeval timeout;
+
+ char get_servers = 0, set_client = 0;
+
+ timeout.tv_sec = SOCKET_TIMEOUT_CLIENT_DATA;
+ timeout.tv_usec = 0;
+
+ // do some checks before connecting
+
+ if (is_same_server(&dev->cur_server, &dev->initial_server))
+ {
+ // Forget all known alt servers
+ memset(dev->alt_servers, 0, sizeof(dev->alt_servers[0])*NUMBER_SERVERS);
+ memcpy(dev->alt_servers, &dev->initial_server, sizeof(dev->alt_servers[0]));
+ if (!dev->is_server)
+ {
+ get_servers = 1;
+ }
+ }
+ if (dev->better_sock)
+ {
+ set_client = 1;
+ }
+
+ if (get_servers || set_client)
+ {
req1 = kmalloc(sizeof(*req1), GFP_ATOMIC);
if (!req1)
error_dev("FATAL: Kmalloc(1) failed.");
- }
-
- if (dev->cur_server.port == 0 || dev->cur_server.hostaddrtype == 0 || dev->imgname == NULL)
- error_dev("FATAL: Host, port or image name not set.");
- if (dev->sock)
- error_dev("ERROR: Already connected.");
-
- if (dev->cur_server.hostaddrtype != AF_INET)
- error_dev("ERROR: IPv6 not implemented.");
- else
- debug_dev("INFO: Connecting...");
-
- if (dev->better_sock == NULL)
- { // no established connection yet from discovery thread, start new one
- dnbd3_request_t dnbd3_request;
- dnbd3_reply_t dnbd3_reply;
- struct msghdr msg;
- struct kvec iov[2];
- uint16_t rid;
- char *name;
- int mlen;
- init_msghdr(msg);
+ }
+
+ if (dev->cur_server.port == 0 || dev->cur_server.hostaddrtype == 0 || dev->imgname == NULL)
+ error_dev("FATAL: Host, port or image name not set.");
+ if (dev->sock)
+ error_dev("ERROR: Already connected.");
+
+ if (dev->cur_server.hostaddrtype != AF_INET)
+ error_dev("ERROR: IPv6 not implemented.");
+ else
+ debug_dev("INFO: Connecting...");
+
+ if (dev->better_sock == NULL)
+ {
+ // no established connection yet from discovery thread, start new one
+ dnbd3_request_t dnbd3_request;
+ dnbd3_reply_t dnbd3_reply;
+ struct msghdr msg;
+ struct kvec iov[2];
+ uint16_t rid;
+ char *name;
+ int mlen;
+ init_msghdr(msg);
if (sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &dev->sock) < 0)
error_dev("ERROR: Couldn't create socket.");
kernel_setsockopt(dev->sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, sizeof(timeout));
@@ -183,107 +184,107 @@ int dnbd3_net_connect(dnbd3_device_t *dev)
sin.sin_port = dev->cur_server.port;
if (kernel_connect(dev->sock, (struct sockaddr *) &sin, sizeof(sin), 0) != 0)
error_dev("FATAL: Connection to host failed.");
- // Request filesize
+ // Request filesize
dnbd3_request.magic = dnbd3_packet_magic;
- dnbd3_request.cmd = CMD_GET_SIZE;
- iov[0].iov_base = &dnbd3_request;
- iov[0].iov_len = sizeof(dnbd3_request);
- serializer_reset_write(&dev->payload_buffer);
- serializer_put_uint16(&dev->payload_buffer, PROTOCOL_VERSION);
- serializer_put_string(&dev->payload_buffer, dev->imgname);
- serializer_put_uint16(&dev->payload_buffer, dev->rid);
- serializer_put_uint8(&dev->payload_buffer, dev->is_server);
- iov[1].iov_base = &dev->payload_buffer;
- dnbd3_request.size = iov[1].iov_len = serializer_get_written_length(&dev->payload_buffer);
- fixup_request(dnbd3_request);
- mlen = sizeof(dnbd3_request) + iov[1].iov_len;
- if (kernel_sendmsg(dev->sock, &msg, iov, 2, mlen) != mlen)
- error_dev("ERROR: Couldn't send CMD_SIZE_REQUEST.");
- // receive reply header
- iov[0].iov_base = &dnbd3_reply;
- iov[0].iov_len = sizeof(dnbd3_reply);
- if (kernel_recvmsg(dev->sock, &msg, iov, 1, sizeof(dnbd3_reply), msg.msg_flags) != sizeof(dnbd3_reply))
- error_dev("FATAL: Received corrupted reply header after CMD_SIZE_REQUEST.");
- // check reply header
- fixup_reply(dnbd3_reply);
- if (dnbd3_reply.cmd != CMD_GET_SIZE || dnbd3_reply.size < 3 || dnbd3_reply.size > MAX_PAYLOAD || dnbd3_reply.magic != dnbd3_packet_magic)
- error_dev("FATAL: Received invalid reply to CMD_SIZE_REQUEST, image doesn't exist on server.");
- // receive reply payload
- iov[0].iov_base = &dev->payload_buffer;
- iov[0].iov_len = dnbd3_reply.size;
- if (kernel_recvmsg(dev->sock, &msg, iov, 1, dnbd3_reply.size, msg.msg_flags) != dnbd3_reply.size)
- error_dev("FATAL: Cold not read CMD_GET_SIZE payload on handshake.");
- // handle/check reply payload
- serializer_reset_read(&dev->payload_buffer, dnbd3_reply.size);
- dev->cur_server.protocol_version = serializer_get_uint16(&dev->payload_buffer);
- if (dev->cur_server.protocol_version < MIN_SUPPORTED_SERVER)
- error_dev("FATAL: Server version is lower than min supported version.");
- name = serializer_get_string(&dev->payload_buffer);
- if (dev->rid != 0 && strcmp(name, dev->imgname) != 0)
- error_dev_va("FATAL: Server offers image '%s', requested '%s'", name, dev->imgname);
- if (strlen(dev->imgname) < strlen(name))
- {
- dev->imgname = krealloc(dev->imgname, strlen(name) + 1, GFP_ATOMIC);
- if (dev->imgname == NULL)
- error_dev("FATAL: Reallocating buffer for new image name failed");
- }
- strcpy(dev->imgname, name);
- rid = serializer_get_uint16(&dev->payload_buffer);
- if (dev->rid != 0 && dev->rid != rid)
- error_dev_va("FATAL: Server provides rid %d, requested was %d.", (int)rid, (int)dev->rid);
- dev->rid = rid;
- dev->reported_size = serializer_get_uint64(&dev->payload_buffer);
- // store image information
- set_capacity(dev->disk, dev->reported_size >> 9); /* 512 Byte blocks */
- debug_dev_va("INFO: Filesize: %llu.", dev->reported_size);
- dev->update_available = 0;
- }
- else // Switching server, connection is already established and size request was executed
- {
- debug_dev("INFO: On-the-fly server change.");
- dev->sock = dev->better_sock;
- dev->better_sock = NULL;
- kernel_setsockopt(dev->sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, sizeof(timeout));
- kernel_setsockopt(dev->sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof(timeout));
- }
-
- dev->panic = 0;
- dev->panic_count = 0;
-
- if (get_servers) // This connection is established to the initial server (from the ioctl call)
- {
+ dnbd3_request.cmd = CMD_GET_SIZE;
+ iov[0].iov_base = &dnbd3_request;
+ iov[0].iov_len = sizeof(dnbd3_request);
+ serializer_reset_write(&dev->payload_buffer);
+ serializer_put_uint16(&dev->payload_buffer, PROTOCOL_VERSION);
+ serializer_put_string(&dev->payload_buffer, dev->imgname);
+ serializer_put_uint16(&dev->payload_buffer, dev->rid);
+ serializer_put_uint8(&dev->payload_buffer, dev->is_server);
+ iov[1].iov_base = &dev->payload_buffer;
+ dnbd3_request.size = iov[1].iov_len = serializer_get_written_length(&dev->payload_buffer);
+ fixup_request(dnbd3_request);
+ mlen = sizeof(dnbd3_request) + iov[1].iov_len;
+ if (kernel_sendmsg(dev->sock, &msg, iov, 2, mlen) != mlen)
+ error_dev("ERROR: Couldn't send CMD_SIZE_REQUEST.");
+ // receive reply header
+ iov[0].iov_base = &dnbd3_reply;
+ iov[0].iov_len = sizeof(dnbd3_reply);
+ if (kernel_recvmsg(dev->sock, &msg, iov, 1, sizeof(dnbd3_reply), msg.msg_flags) != sizeof(dnbd3_reply))
+ error_dev("FATAL: Received corrupted reply header after CMD_SIZE_REQUEST.");
+ // check reply header
+ fixup_reply(dnbd3_reply);
+ if (dnbd3_reply.cmd != CMD_GET_SIZE || dnbd3_reply.size < 3 || dnbd3_reply.size > MAX_PAYLOAD || dnbd3_reply.magic != dnbd3_packet_magic)
+ error_dev("FATAL: Received invalid reply to CMD_SIZE_REQUEST, image doesn't exist on server.");
+ // receive reply payload
+ iov[0].iov_base = &dev->payload_buffer;
+ iov[0].iov_len = dnbd3_reply.size;
+ if (kernel_recvmsg(dev->sock, &msg, iov, 1, dnbd3_reply.size, msg.msg_flags) != dnbd3_reply.size)
+ error_dev("FATAL: Cold not read CMD_GET_SIZE payload on handshake.");
+ // handle/check reply payload
+ serializer_reset_read(&dev->payload_buffer, dnbd3_reply.size);
+ dev->cur_server.protocol_version = serializer_get_uint16(&dev->payload_buffer);
+ if (dev->cur_server.protocol_version < MIN_SUPPORTED_SERVER)
+ error_dev("FATAL: Server version is lower than min supported version.");
+ name = serializer_get_string(&dev->payload_buffer);
+ if (dev->rid != 0 && strcmp(name, dev->imgname) != 0)
+ error_dev_va("FATAL: Server offers image '%s', requested '%s'", name, dev->imgname);
+ if (strlen(dev->imgname) < strlen(name))
+ {
+ dev->imgname = krealloc(dev->imgname, strlen(name) + 1, GFP_ATOMIC);
+ if (dev->imgname == NULL)
+ error_dev("FATAL: Reallocating buffer for new image name failed");
+ }
+ strcpy(dev->imgname, name);
+ rid = serializer_get_uint16(&dev->payload_buffer);
+ if (dev->rid != 0 && dev->rid != rid)
+ error_dev_va("FATAL: Server provides rid %d, requested was %d.", (int)rid, (int)dev->rid);
+ dev->rid = rid;
+ dev->reported_size = serializer_get_uint64(&dev->payload_buffer);
+ // store image information
+ set_capacity(dev->disk, dev->reported_size >> 9); /* 512 Byte blocks */
+ debug_dev_va("INFO: Filesize: %llu.", dev->reported_size);
+ dev->update_available = 0;
+ }
+ else // Switching server, connection is already established and size request was executed
+ {
+ debug_dev("INFO: On-the-fly server change.");
+ dev->sock = dev->better_sock;
+ dev->better_sock = NULL;
+ kernel_setsockopt(dev->sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, sizeof(timeout));
+ kernel_setsockopt(dev->sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof(timeout));
+ }
+
+ dev->panic = 0;
+ dev->panic_count = 0;
+
+ if (get_servers) // This connection is established to the initial server (from the ioctl call)
+ {
// Enqueue request to request_queue_send for a fresh list of alt servers
req1->cmd_type = REQ_TYPE_SPECIAL;
req1->cmd_flags = CMD_GET_SERVERS;
list_add(&req1->queuelist, &dev->request_queue_send);
- }
- else if (set_client)
- {
- req1->cmd_type = REQ_TYPE_SPECIAL;
- req1->cmd_flags = CMD_SET_CLIENT_MODE;
- list_add(&req1->queuelist, &dev->request_queue_send);
- }
-
- // create required threads
- dev->thread_send = kthread_create(dnbd3_net_send, dev, dev->disk->disk_name);
- dev->thread_receive = kthread_create(dnbd3_net_receive, dev, dev->disk->disk_name);
- dev->thread_discover = kthread_create(dnbd3_net_discover, dev, dev->disk->disk_name);
- // start them up
- wake_up_process(dev->thread_send);
- wake_up_process(dev->thread_receive);
- wake_up_process(dev->thread_discover);
-
- wake_up(&dev->process_queue_send);
-
- // add heartbeat timer
- dev->heartbeat_count = 0;
- init_timer(&dev->hb_timer);
- dev->hb_timer.data = (unsigned long) dev;
- dev->hb_timer.function = dnbd3_net_heartbeat;
- dev->hb_timer.expires = jiffies + HZ;
- add_timer(&dev->hb_timer);
-
- return 0;
+ }
+ else if (set_client)
+ {
+ req1->cmd_type = REQ_TYPE_SPECIAL;
+ req1->cmd_flags = CMD_SET_CLIENT_MODE;
+ list_add(&req1->queuelist, &dev->request_queue_send);
+ }
+
+ // create required threads
+ dev->thread_send = kthread_create(dnbd3_net_send, dev, dev->disk->disk_name);
+ dev->thread_receive = kthread_create(dnbd3_net_receive, dev, dev->disk->disk_name);
+ dev->thread_discover = kthread_create(dnbd3_net_discover, dev, dev->disk->disk_name);
+ // start them up
+ wake_up_process(dev->thread_send);
+ wake_up_process(dev->thread_receive);
+ wake_up_process(dev->thread_discover);
+
+ wake_up(&dev->process_queue_send);
+
+ // add heartbeat timer
+ dev->heartbeat_count = 0;
+ init_timer(&dev->hb_timer);
+ dev->hb_timer.data = (unsigned long) dev;
+ dev->hb_timer.function = dnbd3_net_heartbeat;
+ dev->hb_timer.expires = jiffies + HZ;
+ add_timer(&dev->hb_timer);
+
+ return 0;
error:
if (dev->sock)
{
@@ -298,50 +299,50 @@ error:
int dnbd3_net_disconnect(dnbd3_device_t *dev)
{
- debug_dev("INFO: Disconnecting device.");
-
- dev->disconnecting = 1;
-
- // clear heartbeat timer
- if (&dev->hb_timer)
- del_timer(&dev->hb_timer);
-
- dev->discover = 0;
-
- if (dev->sock)
- kernel_sock_shutdown(dev->sock, SHUT_RDWR);
-
- // kill sending and receiving threads
- if (dev->thread_send)
- {
- kthread_stop(dev->thread_send);
- dev->thread_send = NULL;
- }
-
- if (dev->thread_receive)
- {
- kthread_stop(dev->thread_receive);
- dev->thread_receive = NULL;
- }
-
- if (dev->thread_discover)
- {
- kthread_stop(dev->thread_discover);
- dev->thread_discover = NULL;
- }
-
- // clear socket
- if (dev->sock)
- {
- sock_release(dev->sock);
- dev->sock = NULL;
- }
+ debug_dev("INFO: Disconnecting device.");
+
+ dev->disconnecting = 1;
+
+ // clear heartbeat timer
+ if (&dev->hb_timer)
+ del_timer(&dev->hb_timer);
+
+ dev->discover = 0;
+
+ if (dev->sock)
+ kernel_sock_shutdown(dev->sock, SHUT_RDWR);
+
+ // kill sending and receiving threads
+ if (dev->thread_send)
+ {
+ kthread_stop(dev->thread_send);
+ dev->thread_send = NULL;
+ }
+
+ if (dev->thread_receive)
+ {
+ kthread_stop(dev->thread_receive);
+ dev->thread_receive = NULL;
+ }
+
+ if (dev->thread_discover)
+ {
+ kthread_stop(dev->thread_discover);
+ dev->thread_discover = NULL;
+ }
+
+ // clear socket
+ if (dev->sock)
+ {
+ sock_release(dev->sock);
+ dev->sock = NULL;
+ }
dev->cur_server.hostaddrtype = 0;
dev->cur_server.port = 0;
dev->disconnecting = 0;
- return 0;
+ return 0;
}
void dnbd3_net_heartbeat(unsigned long arg)
@@ -349,13 +350,13 @@ void dnbd3_net_heartbeat(unsigned long arg)
// Because different events need different intervals, the timer is called once a second.
// Other intervals can be derived using dev->heartbeat_count.
#define timeout_seconds(x) (dev->heartbeat_count % (x) == 0)
- dnbd3_device_t *dev = (dnbd3_device_t *) arg;
+ dnbd3_device_t *dev = (dnbd3_device_t *) arg;
- if (!dev->panic)
- {
- if (timeout_seconds(TIMER_INTERVAL_KEEPALIVE_PACKET))
- {
+ if (!dev->panic)
+ {
+ if (timeout_seconds(TIMER_INTERVAL_KEEPALIVE_PACKET))
+ {
struct request *req = kmalloc(sizeof(struct request), GFP_ATOMIC);
// send keepalive
if (req)
@@ -369,288 +370,291 @@ void dnbd3_net_heartbeat(unsigned long arg)
{
debug_dev("ERROR: Couldn't create keepalive request.");
}
- }
- if (timeout_seconds(TIMER_INTERVAL_PROBE_NORMAL))
- {
+ }
+ if (timeout_seconds(TIMER_INTERVAL_PROBE_NORMAL))
+ {
// Normal discovery
dev->discover = 1;
wake_up(&dev->process_queue_discover);
- }
- }
- else if (timeout_seconds(TIMER_INTERVAL_PROBE_PANIC))
- {
+ }
+ }
+ else if (timeout_seconds(TIMER_INTERVAL_PROBE_PANIC))
+ {
// Panic discovery
dev->discover = 1;
wake_up(&dev->process_queue_discover);
- }
+ }
- dev->hb_timer.expires = jiffies + HZ;
+ dev->hb_timer.expires = jiffies + HZ;
- ++dev->heartbeat_count;
- add_timer(&dev->hb_timer);
+ ++dev->heartbeat_count;
+ add_timer(&dev->hb_timer);
#undef timeout_seconds
}
int dnbd3_net_discover(void *data)
{
- dnbd3_device_t *dev = data;
- struct sockaddr_in sin;
- struct socket *sock, *best_sock = NULL;
-
- dnbd3_request_t dnbd3_request;
- dnbd3_reply_t dnbd3_reply;
- dnbd3_server_t *alt_server;
- struct msghdr msg;
- struct kvec iov[2];
-
- char *buf, *name;
- serialized_buffer_t *payload;
- uint64_t filesize;
- uint16_t rid;
-
- struct timeval start, end;
- unsigned long rtt, best_rtt = 0;
- unsigned long irqflags;
- int i, best_server, current_server;
- int turn = 0;
- int ready = 0;
- int mlen;
-
- struct timeval timeout;
- timeout.tv_sec = SOCKET_TIMEOUT_CLIENT_DISCOVERY;
- timeout.tv_usec = 0;
-
- init_msghdr(msg);
-
- buf = kmalloc(4096, GFP_KERNEL);
- if (!buf)
- {
- debug_dev("FATAL: Kmalloc failed (discover)");
- return -1;
- }
- payload = (serialized_buffer_t*)buf; // Reuse this buffer to save kernel mem
-
- dnbd3_request.magic = dnbd3_packet_magic;
-
- for (;;)
- {
- wait_event_interruptible(dev->process_queue_discover,
- kthread_should_stop() || dev->discover);
-
- if (kthread_should_stop() || dev->imgname == NULL)
- break;
-
- if (!dev->discover)
- continue;
- dev->discover = 0;
-
- // Check if the list of alt servers needs to be updated and do so if neccessary
- if (dev->new_servers_num)
- {
- spin_lock_irqsave(&dev->blk_lock, irqflags);
- for (i = 0; i < dev->new_servers_num; ++i)
- {
- if (dev->new_servers[i].hostaddrtype != AF_INET) // Invalid entry.. (Add IPv6)
- continue;
- alt_server = get_existing_server(&dev->new_servers[i], dev);
- if (alt_server != NULL) // Server already known
- {
- if (dev->new_servers[i].failures == 1)
- { // REMOVE request
- alt_server->hostaddrtype = 0;
- continue;
- }
- // ADD, so just reset fail counter
- alt_server->failures = 0;
- continue;
- }
- if (dev->new_servers[i].failures == 1) // REMOVE, but server is not in list anyways
- continue;
- alt_server = get_free_alt_server(dev);
- if (alt_server == NULL) // All NUMBER_SERVERS slots are taken, ignore entry
- continue;
- // Add new server entry
- memcpy(alt_server->hostaddr, dev->new_servers[i].hostaddr, 16);
- alt_server->hostaddrtype = dev->new_servers[i].hostaddrtype;
- alt_server->port = dev->new_servers[i].port;
- alt_server->rtts[0] = alt_server->rtts[1]
- = alt_server->rtts[2] = alt_server->rtts[3]
- = RTT_UNREACHABLE;
- alt_server->protocol_version = 0;
- alt_server->failures = 0;
- }
- dev->new_servers_num = 0;
- spin_unlock_irqrestore(&dev->blk_lock, irqflags);
- }
-
- current_server = best_server = -1;
- best_rtt = 0xFFFFFFFul;
-
- for (i=0; i < NUMBER_SERVERS; ++i)
- {
- if (dev->alt_servers[i].hostaddrtype == 0) // Empty slot
- continue;
- if (!dev->panic && dev->alt_servers[i].failures > 50) // If not in panic mode, skip server if it failed too many times
- continue;
-
- // Initialize socket and connect
- if (sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &sock) < 0)
- {
- debug_alt("ERROR: Couldn't create socket (discover).");
- sock = NULL;
- continue;
- }
- kernel_setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, sizeof(timeout));
- kernel_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof(timeout));
- sock->sk->sk_allocation = GFP_NOIO;
- sin.sin_family = AF_INET; // add IPv6.....
- memcpy(&sin.sin_addr.s_addr, dev->alt_servers[i].hostaddr, 4);
- sin.sin_port = dev->alt_servers[i].port;
- if (kernel_connect(sock, (struct sockaddr *) &sin, sizeof(sin), 0) < 0)
- goto error;
-
- // Request filesize
- dnbd3_request.cmd = CMD_GET_SIZE;
- iov[0].iov_base = &dnbd3_request;
- iov[0].iov_len = sizeof(dnbd3_request);
- serializer_reset_write(payload);
- serializer_put_uint16(payload, PROTOCOL_VERSION);
- serializer_put_string(payload, dev->imgname);
- serializer_put_uint16(payload, dev->rid);
- serializer_put_uint8(payload, 1); // Pretend we're a proxy here to prevent the server from updating the atime TODO: Update status on server switch
- iov[1].iov_base = payload;
- dnbd3_request.size = iov[1].iov_len = serializer_get_written_length(payload);
- fixup_request(dnbd3_request);
- mlen = iov[1].iov_len + sizeof(dnbd3_request);
- if (kernel_sendmsg(sock, &msg, iov, 2, mlen) != mlen)
- error_alt("ERROR: Requesting image size failed.");
-
- // receive net reply
- iov[0].iov_base = &dnbd3_reply;
- iov[0].iov_len = sizeof(dnbd3_reply);
- if (kernel_recvmsg(sock, &msg, iov, 1, sizeof(dnbd3_reply), msg.msg_flags) != sizeof(dnbd3_reply))
- error_alt("ERROR: Receiving image size packet (header) failed (discover).");
- fixup_reply(dnbd3_reply);
- if (dnbd3_reply.magic != dnbd3_packet_magic || dnbd3_reply.cmd != CMD_GET_SIZE || dnbd3_reply.size < 4)
- error_alt("ERROR: Content of image size packet (header) mismatched (discover).");
-
- // receive data
- iov[0].iov_base = payload;
- iov[0].iov_len = dnbd3_reply.size;
- if (kernel_recvmsg(sock, &msg, iov, 1, dnbd3_reply.size, msg.msg_flags) != dnbd3_reply.size)
- error_alt("ERROR: Receiving image size packet (payload) failed (discover).");
- serializer_reset_read(payload, dnbd3_reply.size);
-
- dev->alt_servers[i].protocol_version = serializer_get_uint16(payload);
- if (dev->alt_servers[i].protocol_version < MIN_SUPPORTED_SERVER)
- error_alt_va("ERROR: Server version too old (client: %d, server: %d, min supported: %d).", (int)PROTOCOL_VERSION, (int)dev->alt_servers[i].protocol_version, (int)MIN_SUPPORTED_SERVER);
-
- name = serializer_get_string(payload);
- if (name == NULL)
- error_alt("ERROR: Server did not supply an image name (discover).");
-
- if (strcmp(name, dev->imgname) != 0)
- error_alt_va("ERROR: Image name does not match requested one (client: '%s', server: '%s') (discover).", dev->imgname, name);
-
- rid = serializer_get_uint16(payload);
- if (rid != dev->rid)
- error_alt_va("ERROR: Server supplied wrong rid (client: '%d', server: '%d') (discover).", (int)dev->rid, (int)rid);
-
- filesize = serializer_get_uint64(payload);
- if (filesize != dev->reported_size)
- error_alt_va("ERROR: Reported image size of %llu does not match expected value %llu.(discover).", (unsigned long long)filesize, (unsigned long long)dev->reported_size);
-
- // panic mode, take first responding server
- if (dev->panic)
- {
- printk("WARN: Panic mode (%s), taking server %pI4 : %d\n", dev->disk->disk_name, dev->alt_servers[i].hostaddr, (int)ntohs(dev->alt_servers[i].port));
- if (best_sock != NULL) sock_release(best_sock);
- dev->better_sock = sock; // Pass over socket to take a shortcut in *_connect();
- kfree(buf);
- dev->thread_discover = NULL;
- dnbd3_net_disconnect(dev);
- memcpy(&dev->cur_server, &dev->alt_servers[i], sizeof(dev->cur_server));
- dnbd3_net_connect(dev);
- return 0;
- }
-
- // Request block
- dnbd3_request.cmd = CMD_GET_BLOCK;
- // Pick random block
- if (sizeof(size_t) >= 8)
- {
+ dnbd3_device_t *dev = data;
+ struct sockaddr_in sin;
+ struct socket *sock, *best_sock = NULL;
+
+ dnbd3_request_t dnbd3_request;
+ dnbd3_reply_t dnbd3_reply;
+ dnbd3_server_t *alt_server;
+ struct msghdr msg;
+ struct kvec iov[2];
+
+ char *buf, *name;
+ serialized_buffer_t *payload;
+ uint64_t filesize;
+ uint16_t rid;
+
+ struct timeval start, end;
+ unsigned long rtt, best_rtt = 0;
+ unsigned long irqflags;
+ int i, best_server, current_server;
+ int turn = 0;
+ int ready = 0;
+ int mlen;
+
+ struct timeval timeout;
+ timeout.tv_sec = SOCKET_TIMEOUT_CLIENT_DISCOVERY;
+ timeout.tv_usec = 0;
+
+ init_msghdr(msg);
+
+ buf = kmalloc(4096, GFP_KERNEL);
+ if (!buf)
+ {
+ debug_dev("FATAL: Kmalloc failed (discover)");
+ return -1;
+ }
+ payload = (serialized_buffer_t *)buf; // Reuse this buffer to save kernel mem
+
+ dnbd3_request.magic = dnbd3_packet_magic;
+
+ for (;;)
+ {
+ wait_event_interruptible(dev->process_queue_discover,
+ kthread_should_stop() || dev->discover);
+
+ if (kthread_should_stop() || dev->imgname == NULL)
+ break;
+
+ if (!dev->discover)
+ continue;
+ dev->discover = 0;
+
+ // Check if the list of alt servers needs to be updated and do so if neccessary
+ if (dev->new_servers_num)
+ {
+ spin_lock_irqsave(&dev->blk_lock, irqflags);
+ for (i = 0; i < dev->new_servers_num; ++i)
+ {
+ if (dev->new_servers[i].hostaddrtype != AF_INET) // Invalid entry.. (Add IPv6)
+ continue;
+ alt_server = get_existing_server(&dev->new_servers[i], dev);
+ if (alt_server != NULL) // Server already known
+ {
+ if (dev->new_servers[i].failures == 1)
+ {
+ // REMOVE request
+ alt_server->hostaddrtype = 0;
+ continue;
+ }
+ // ADD, so just reset fail counter
+ alt_server->failures = 0;
+ continue;
+ }
+ if (dev->new_servers[i].failures == 1) // REMOVE, but server is not in list anyways
+ continue;
+ alt_server = get_free_alt_server(dev);
+ if (alt_server == NULL) // All NUMBER_SERVERS slots are taken, ignore entry
+ continue;
+ // Add new server entry
+ memcpy(alt_server->hostaddr, dev->new_servers[i].hostaddr, 16);
+ alt_server->hostaddrtype = dev->new_servers[i].hostaddrtype;
+ alt_server->port = dev->new_servers[i].port;
+ alt_server->rtts[0] = alt_server->rtts[1]
+ = alt_server->rtts[2] = alt_server->rtts[3]
+ = RTT_UNREACHABLE;
+ alt_server->protocol_version = 0;
+ alt_server->failures = 0;
+ }
+ dev->new_servers_num = 0;
+ spin_unlock_irqrestore(&dev->blk_lock, irqflags);
+ }
+
+ current_server = best_server = -1;
+ best_rtt = 0xFFFFFFFul;
+
+ for (i=0; i < NUMBER_SERVERS; ++i)
+ {
+ if (dev->alt_servers[i].hostaddrtype == 0) // Empty slot
+ continue;
+ if (!dev->panic && dev->alt_servers[i].failures > 50) // If not in panic mode, skip server if it failed too many times
+ continue;
+
+ // Initialize socket and connect
+ if (sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &sock) < 0)
+ {
+ debug_alt("ERROR: Couldn't create socket (discover).");
+ sock = NULL;
+ continue;
+ }
+ kernel_setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, sizeof(timeout));
+ kernel_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof(timeout));
+ sock->sk->sk_allocation = GFP_NOIO;
+ sin.sin_family = AF_INET; // add IPv6.....
+ memcpy(&sin.sin_addr.s_addr, dev->alt_servers[i].hostaddr, 4);
+ sin.sin_port = dev->alt_servers[i].port;
+ if (kernel_connect(sock, (struct sockaddr *) &sin, sizeof(sin), 0) < 0)
+ goto error;
+
+ // Request filesize
+ dnbd3_request.cmd = CMD_GET_SIZE;
+ iov[0].iov_base = &dnbd3_request;
+ iov[0].iov_len = sizeof(dnbd3_request);
+ serializer_reset_write(payload);
+ serializer_put_uint16(payload, PROTOCOL_VERSION);
+ serializer_put_string(payload, dev->imgname);
+ serializer_put_uint16(payload, dev->rid);
+ serializer_put_uint8(payload, 1); // Pretend we're a proxy here to prevent the server from updating the atime TODO: Update status on server switch
+ iov[1].iov_base = payload;
+ dnbd3_request.size = iov[1].iov_len = serializer_get_written_length(payload);
+ fixup_request(dnbd3_request);
+ mlen = iov[1].iov_len + sizeof(dnbd3_request);
+ if (kernel_sendmsg(sock, &msg, iov, 2, mlen) != mlen)
+ error_alt("ERROR: Requesting image size failed.");
+
+ // receive net reply
+ iov[0].iov_base = &dnbd3_reply;
+ iov[0].iov_len = sizeof(dnbd3_reply);
+ if (kernel_recvmsg(sock, &msg, iov, 1, sizeof(dnbd3_reply), msg.msg_flags) != sizeof(dnbd3_reply))
+ error_alt("ERROR: Receiving image size packet (header) failed (discover).");
+ fixup_reply(dnbd3_reply);
+ if (dnbd3_reply.magic != dnbd3_packet_magic || dnbd3_reply.cmd != CMD_GET_SIZE || dnbd3_reply.size < 4)
+ error_alt("ERROR: Content of image size packet (header) mismatched (discover).");
+
+ // receive data
+ iov[0].iov_base = payload;
+ iov[0].iov_len = dnbd3_reply.size;
+ if (kernel_recvmsg(sock, &msg, iov, 1, dnbd3_reply.size, msg.msg_flags) != dnbd3_reply.size)
+ error_alt("ERROR: Receiving image size packet (payload) failed (discover).");
+ serializer_reset_read(payload, dnbd3_reply.size);
+
+ dev->alt_servers[i].protocol_version = serializer_get_uint16(payload);
+ if (dev->alt_servers[i].protocol_version < MIN_SUPPORTED_SERVER)
+ error_alt_va("ERROR: Server version too old (client: %d, server: %d, min supported: %d).", (int)PROTOCOL_VERSION, (int)dev->alt_servers[i].protocol_version, (int)MIN_SUPPORTED_SERVER);
+
+ name = serializer_get_string(payload);
+ if (name == NULL)
+ error_alt("ERROR: Server did not supply an image name (discover).");
+
+ if (strcmp(name, dev->imgname) != 0)
+ error_alt_va("ERROR: Image name does not match requested one (client: '%s', server: '%s') (discover).", dev->imgname, name);
+
+ rid = serializer_get_uint16(payload);
+ if (rid != dev->rid)
+ error_alt_va("ERROR: Server supplied wrong rid (client: '%d', server: '%d') (discover).", (int)dev->rid, (int)rid);
+
+ filesize = serializer_get_uint64(payload);
+ if (filesize != dev->reported_size)
+ error_alt_va("ERROR: Reported image size of %llu does not match expected value %llu.(discover).", (unsigned long long)filesize, (unsigned long long)dev->reported_size);
+
+ // panic mode, take first responding server
+ if (dev->panic)
+ {
+ printk("WARN: Panic mode (%s), taking server %pI4 : %d\n", dev->disk->disk_name, dev->alt_servers[i].hostaddr, (int)ntohs(dev->alt_servers[i].port));
+ if (best_sock != NULL) sock_release(best_sock);
+ dev->better_sock = sock; // Pass over socket to take a shortcut in *_connect();
+ kfree(buf);
+ dev->thread_discover = NULL;
+ dnbd3_net_disconnect(dev);
+ memcpy(&dev->cur_server, &dev->alt_servers[i], sizeof(dev->cur_server));
+ dnbd3_net_connect(dev);
+ return 0;
+ }
+
+ // Request block
+ dnbd3_request.cmd = CMD_GET_BLOCK;
+ // Pick random block
+ if (sizeof(size_t) >= 8)
+ {
dnbd3_request.offset = ((((start.tv_usec << 12) ^ start.tv_usec) << 4) % dev->reported_size) & ~(uint64_t)(RTT_BLOCK_SIZE-1);
//printk("Random offset 64bit: %lluMiB\n", (unsigned long long)(dnbd3_request.offset >> 20));
- }
- else // On 32bit, prevent modulo on a 64bit data type. This limits the random block picking to the first 4GB of the image
- {
+ }
+ else // On 32bit, prevent modulo on a 64bit data type. This limits the random block picking to the first 4GB of the image
+ {
dnbd3_request.offset = ((((start.tv_usec << 12) ^ start.tv_usec) << 4) % (uint32_t)dev->reported_size) & ~(RTT_BLOCK_SIZE-1);
//printk("Random offset 32bit: %lluMiB\n", (unsigned long long)(dnbd3_request.offset >> 20));
- }
- dnbd3_request.size = RTT_BLOCK_SIZE;
- fixup_request(dnbd3_request);
- iov[0].iov_base = &dnbd3_request;
- iov[0].iov_len = sizeof(dnbd3_request);
-
- // start rtt measurement
- do_gettimeofday(&start);
-
- if (kernel_sendmsg(sock, &msg, iov, 1, sizeof(dnbd3_request)) <= 0)
- error_alt("ERROR: Requesting test block failed (discover).");
-
- // receive net reply
- iov[0].iov_base = &dnbd3_reply;
- iov[0].iov_len = sizeof(dnbd3_reply);
- if (kernel_recvmsg(sock, &msg, iov, 1, sizeof(dnbd3_reply), msg.msg_flags) != sizeof(dnbd3_reply))
- error_alt("ERROR: Receiving test block header packet failed (discover).");
- fixup_reply(dnbd3_reply);
- if (dnbd3_reply.magic != dnbd3_packet_magic || dnbd3_reply.cmd != CMD_GET_BLOCK || dnbd3_reply.size != RTT_BLOCK_SIZE)
- error_alt_va("ERROR: Unexpected reply to block request: cmd=%d, size=%d (discover).", (int)dnbd3_reply.cmd, (int)dnbd3_reply.size);
-
- // receive data
- iov[0].iov_base = buf;
- iov[0].iov_len = RTT_BLOCK_SIZE;
- if (kernel_recvmsg(sock, &msg, iov, 1, dnbd3_reply.size, msg.msg_flags) != RTT_BLOCK_SIZE)
- error_alt("ERROR: Receiving test block payload failed (discover).");
-
- do_gettimeofday(&end); // end rtt measurement
-
- dev->alt_servers[i].rtts[turn] = (unsigned long)(
- (end.tv_sec - start.tv_sec) * 1000000ull
- + (end.tv_usec - start.tv_usec)
- );
-
- rtt = ( dev->alt_servers[i].rtts[0]
- + dev->alt_servers[i].rtts[1]
- + dev->alt_servers[i].rtts[2]
- + dev->alt_servers[i].rtts[3] ) / 4;
-
- if (best_rtt > rtt)
- { // This one is better, keep socket open in case we switch
- best_rtt = rtt;
- best_server = i;
- if (best_sock != NULL) sock_release(best_sock);
- best_sock = sock;
- sock = NULL;
- }
- else
- { // Not better, discard connection
- sock_release(sock);
- sock = NULL;
- }
-
- // update cur servers rtt
- if (is_same_server(&dev->cur_server, &dev->alt_servers[i]))
- {
- dev->cur_rtt = rtt;
- current_server = i;
- }
-
- dev->alt_servers[i].failures = 0;
-
- continue;
-
- error:
+ }
+ dnbd3_request.size = RTT_BLOCK_SIZE;
+ fixup_request(dnbd3_request);
+ iov[0].iov_base = &dnbd3_request;
+ iov[0].iov_len = sizeof(dnbd3_request);
+
+ // start rtt measurement
+ do_gettimeofday(&start);
+
+ if (kernel_sendmsg(sock, &msg, iov, 1, sizeof(dnbd3_request)) <= 0)
+ error_alt("ERROR: Requesting test block failed (discover).");
+
+ // receive net reply
+ iov[0].iov_base = &dnbd3_reply;
+ iov[0].iov_len = sizeof(dnbd3_reply);
+ if (kernel_recvmsg(sock, &msg, iov, 1, sizeof(dnbd3_reply), msg.msg_flags) != sizeof(dnbd3_reply))
+ error_alt("ERROR: Receiving test block header packet failed (discover).");
+ fixup_reply(dnbd3_reply);
+ if (dnbd3_reply.magic != dnbd3_packet_magic || dnbd3_reply.cmd != CMD_GET_BLOCK || dnbd3_reply.size != RTT_BLOCK_SIZE)
+ error_alt_va("ERROR: Unexpected reply to block request: cmd=%d, size=%d (discover).", (int)dnbd3_reply.cmd, (int)dnbd3_reply.size);
+
+ // receive data
+ iov[0].iov_base = buf;
+ iov[0].iov_len = RTT_BLOCK_SIZE;
+ if (kernel_recvmsg(sock, &msg, iov, 1, dnbd3_reply.size, msg.msg_flags) != RTT_BLOCK_SIZE)
+ error_alt("ERROR: Receiving test block payload failed (discover).");
+
+ do_gettimeofday(&end); // end rtt measurement
+
+ dev->alt_servers[i].rtts[turn] = (unsigned long)(
+ (end.tv_sec - start.tv_sec) * 1000000ull
+ + (end.tv_usec - start.tv_usec)
+ );
+
+ rtt = ( dev->alt_servers[i].rtts[0]
+ + dev->alt_servers[i].rtts[1]
+ + dev->alt_servers[i].rtts[2]
+ + dev->alt_servers[i].rtts[3] ) / 4;
+
+ if (best_rtt > rtt)
+ {
+ // This one is better, keep socket open in case we switch
+ best_rtt = rtt;
+ best_server = i;
+ if (best_sock != NULL) sock_release(best_sock);
+ best_sock = sock;
+ sock = NULL;
+ }
+ else
+ {
+ // Not better, discard connection
+ sock_release(sock);
+ sock = NULL;
+ }
+
+ // update cur servers rtt
+ if (is_same_server(&dev->cur_server, &dev->alt_servers[i]))
+ {
+ dev->cur_rtt = rtt;
+ current_server = i;
+ }
+
+ dev->alt_servers[i].failures = 0;
+
+ continue;
+
+error:
++dev->alt_servers[i].failures;
sock_release(sock);
sock = NULL;
@@ -661,134 +665,135 @@ int dnbd3_net_discover(void *data)
current_server = i;
}
continue;
- }
+ }
+
+ if (dev->panic)
+ {
+ // After 21 retries, bail out by reporting errors to block layer
+ if (dev->panic_count < 255 && ++dev->panic_count == PROBE_COUNT_TIMEOUT+1)
+ dnbd3_blk_fail_all_requests(dev);
+ }
+
+ if (best_server == -1 || kthread_should_stop()) // No alt server could be reached at all or thread should stop
+ {
+ if (best_sock != NULL) // Should never happen actually
+ {
+ sock_release(best_sock);
+ best_sock = NULL;
+ }
+ continue;
+ }
- if (dev->panic)
- { // After 21 retries, bail out by reporting errors to block layer
- if (dev->panic_count < 255 && ++dev->panic_count == PROBE_COUNT_TIMEOUT+1)
- dnbd3_blk_fail_all_requests(dev);
+ // take server with lowest rtt (only if in client mode)
+ if (!dev->is_server && ready && best_server != current_server
+ && RTT_THRESHOLD_FACTOR(dev->cur_rtt) > best_rtt)
+ {
+ printk("INFO: Server %d on %s is faster (%lluµs vs. %lluµs)\n", best_server, dev->disk->disk_name, (unsigned long long)best_rtt, (unsigned long long)dev->cur_rtt);
+ kfree(buf);
+ dev->better_sock = best_sock; // Take shortcut by continuing to use open connection
+ dev->thread_discover = NULL;
+ dnbd3_net_disconnect(dev);
+ memcpy(&dev->cur_server, &dev->alt_servers[best_server], sizeof(dev->cur_server));
+ dev->cur_rtt = best_rtt;
+ dnbd3_net_connect(dev);
+ return 0;
}
- if (best_server == -1 || kthread_should_stop()) // No alt server could be reached at all or thread should stop
- {
- if (best_sock != NULL) // Should never happen actually
- {
- sock_release(best_sock);
- best_sock = NULL;
- }
- continue;
- }
-
- // take server with lowest rtt (only if in client mode)
- if (!dev->is_server && ready && best_server != current_server
- && RTT_THRESHOLD_FACTOR(dev->cur_rtt) > best_rtt)
- {
- printk("INFO: Server %d on %s is faster (%lluµs vs. %lluµs)\n", best_server, dev->disk->disk_name, (unsigned long long)best_rtt, (unsigned long long)dev->cur_rtt);
- kfree(buf);
- dev->better_sock = best_sock; // Take shortcut by continuing to use open connection
- dev->thread_discover = NULL;
- dnbd3_net_disconnect(dev);
- memcpy(&dev->cur_server, &dev->alt_servers[best_server], sizeof(dev->cur_server));
- dev->cur_rtt = best_rtt;
- dnbd3_net_connect(dev);
- return 0;
- }
-
- // Clean up connection that was held open for quicker server switch
- if (best_sock != NULL)
- {
+ // Clean up connection that was held open for quicker server switch
+ if (best_sock != NULL)
+ {
sock_release(best_sock);
best_sock = NULL;
- }
+ }
- turn = (turn + 1) % 4;
- if (turn == 3)
- ready = 1;
+ turn = (turn + 1) % 4;
+ if (turn == 3)
+ ready = 1;
- }
- kfree(buf);
- return 0;
+ }
+ kfree(buf);
+ return 0;
}
int dnbd3_net_send(void *data)
{
- dnbd3_device_t *dev = data;
- struct request *blk_request;
-
- dnbd3_request_t dnbd3_request;
- struct msghdr msg;
- struct kvec iov;
-
- unsigned long irqflags;
-
- init_msghdr(msg);
-
- dnbd3_request.magic = dnbd3_packet_magic;
-
- set_user_nice(current, -20);
-
- for (;;)
- {
- wait_event_interruptible(dev->process_queue_send,
- kthread_should_stop() || !list_empty(&dev->request_queue_send));
-
- if (kthread_should_stop())
- break;
-
- // extract block request
- spin_lock_irqsave(&dev->blk_lock, irqflags);
- if (list_empty(&dev->request_queue_send))
- {
- spin_unlock_irqrestore(&dev->blk_lock, irqflags);
- continue;
- }
- blk_request = list_entry(dev->request_queue_send.next, struct request, queuelist);
- spin_unlock_irqrestore(&dev->blk_lock, irqflags);
-
- // what to do?
- switch (blk_request->cmd_type)
- {
- case REQ_TYPE_FS:
- dnbd3_request.cmd = CMD_GET_BLOCK;
- dnbd3_request.offset = blk_rq_pos(blk_request) << 9; // *512
- dnbd3_request.size = blk_rq_bytes(blk_request); // bytes left to complete entire request
- // enqueue request to request_queue_receive
- spin_lock_irqsave(&dev->blk_lock, irqflags);
- list_del_init(&blk_request->queuelist);
- list_add_tail(&blk_request->queuelist, &dev->request_queue_receive);
- spin_unlock_irqrestore(&dev->blk_lock, irqflags);
- break;
-
- case REQ_TYPE_SPECIAL:
- dnbd3_request.cmd = blk_request->cmd_flags;
- dnbd3_request.size = 0;
- spin_lock_irqsave(&dev->blk_lock, irqflags);
- list_del_init(&blk_request->queuelist);
- spin_unlock_irqrestore(&dev->blk_lock, irqflags);
- break;
-
- default:
- printk("ERROR: Unknown command (send)\n");
- spin_lock_irqsave(&dev->blk_lock, irqflags);
- list_del_init(&blk_request->queuelist);
- spin_unlock_irqrestore(&dev->blk_lock, irqflags);
- continue;
- }
-
- // send net request
- dnbd3_request.handle = (uint64_t)(uintptr_t)blk_request; // Double cast to prevent warning on 32bit
- fixup_request(dnbd3_request);
- iov.iov_base = &dnbd3_request;
- iov.iov_len = sizeof(dnbd3_request);
- if (kernel_sendmsg(dev->sock, &msg, &iov, 1, sizeof(dnbd3_request)) != sizeof(dnbd3_request))
- {
- printk("Couldn't properly send a request header.\n");
- goto error;
- }
- wake_up(&dev->process_queue_receive);
- }
-
- return 0;
+ dnbd3_device_t *dev = data;
+ struct request *blk_request;
+
+ dnbd3_request_t dnbd3_request;
+ struct msghdr msg;
+ struct kvec iov;
+
+ unsigned long irqflags;
+
+ init_msghdr(msg);
+
+ dnbd3_request.magic = dnbd3_packet_magic;
+
+ set_user_nice(current, -20);
+
+ for (;;)
+ {
+ wait_event_interruptible(dev->process_queue_send,
+ kthread_should_stop() || !list_empty(&dev->request_queue_send));
+
+ if (kthread_should_stop())
+ break;
+
+ // extract block request
+ spin_lock_irqsave(&dev->blk_lock, irqflags);
+ if (list_empty(&dev->request_queue_send))
+ {
+ spin_unlock_irqrestore(&dev->blk_lock, irqflags);
+ continue;
+ }
+ blk_request = list_entry(dev->request_queue_send.next, struct request, queuelist);
+ spin_unlock_irqrestore(&dev->blk_lock, irqflags);
+
+ // what to do?
+ switch (blk_request->cmd_type)
+ {
+ case REQ_TYPE_FS:
+ dnbd3_request.cmd = CMD_GET_BLOCK;
+ dnbd3_request.offset = blk_rq_pos(blk_request) << 9; // *512
+ dnbd3_request.size = blk_rq_bytes(blk_request); // bytes left to complete entire request
+ // enqueue request to request_queue_receive
+ spin_lock_irqsave(&dev->blk_lock, irqflags);
+ list_del_init(&blk_request->queuelist);
+ list_add_tail(&blk_request->queuelist, &dev->request_queue_receive);
+ spin_unlock_irqrestore(&dev->blk_lock, irqflags);
+ break;
+
+ case REQ_TYPE_SPECIAL:
+ dnbd3_request.cmd = blk_request->cmd_flags;
+ dnbd3_request.size = 0;
+ spin_lock_irqsave(&dev->blk_lock, irqflags);
+ list_del_init(&blk_request->queuelist);
+ spin_unlock_irqrestore(&dev->blk_lock, irqflags);
+ break;
+
+ default:
+ printk("ERROR: Unknown command (send)\n");
+ spin_lock_irqsave(&dev->blk_lock, irqflags);
+ list_del_init(&blk_request->queuelist);
+ spin_unlock_irqrestore(&dev->blk_lock, irqflags);
+ continue;
+ }
+
+ // send net request
+ dnbd3_request.handle = (uint64_t)(uintptr_t)blk_request; // Double cast to prevent warning on 32bit
+ fixup_request(dnbd3_request);
+ iov.iov_base = &dnbd3_request;
+ iov.iov_len = sizeof(dnbd3_request);
+ if (kernel_sendmsg(dev->sock, &msg, &iov, 1, sizeof(dnbd3_request)) != sizeof(dnbd3_request))
+ {
+ printk("Couldn't properly send a request header.\n");
+ goto error;
+ }
+ wake_up(&dev->process_queue_receive);
+ }
+
+ return 0;
error:
printk("ERROR: Connection to server %pI4 : %d lost (send)\n", dev->cur_server.hostaddr, (int)ntohs(dev->cur_server.port));
@@ -807,164 +812,165 @@ error:
int dnbd3_net_receive(void *data)
{
- dnbd3_device_t *dev = data;
- struct request *blk_request, *tmp_request, *received_request;
-
- dnbd3_reply_t dnbd3_reply;
- struct msghdr msg;
- struct kvec iov;
- struct req_iterator iter;
- struct bio_vec *bvec;
- void *kaddr;
- unsigned long irqflags;
- sigset_t blocked, oldset;
- uint16_t rid;
-
- int count, remaining, ret, recv_timeout = 0;
-
- init_msghdr(msg);
- set_user_nice(current, -20);
-
- while (!kthread_should_stop())
- {
- // receive net reply
- iov.iov_base = &dnbd3_reply;
- iov.iov_len = sizeof(dnbd3_reply);
- ret = kernel_recvmsg(dev->sock, &msg, &iov, 1, sizeof(dnbd3_reply), msg.msg_flags);
- if (ret == -EAGAIN)
- {
- if ((recv_timeout += SOCKET_TIMEOUT_CLIENT_DATA) > SOCKET_KEEPALIVE_TIMEOUT)
- error_dev("ERROR: Receive timeout reached.");
- continue;
- }
- if (ret <= 0)
- error_dev_va("Connection closed (%d).", ret);
- if (ret != sizeof(dnbd3_reply))
- error_dev("ERROR: Recv msg header.");
- fixup_reply(dnbd3_reply);
-
- // check error
- if (dnbd3_reply.magic != dnbd3_packet_magic)
- error_dev("ERROR: Wrong packet magic (Receive).");
- if (dnbd3_reply.cmd == 0)
- error_dev("ERROR: Command was 0 (Receive).");
-
- recv_timeout = 0;
-
- // what to do?
- switch (dnbd3_reply.cmd)
- {
- case CMD_GET_BLOCK:
- // search for replied request in queue
- blk_request = NULL;
- spin_lock_irqsave(&dev->blk_lock, irqflags);
- list_for_each_entry_safe(received_request, tmp_request, &dev->request_queue_receive, queuelist)
- {
- if ((uint64_t)(uintptr_t)received_request == dnbd3_reply.handle) // Double cast to prevent warning on 32bit
- {
- blk_request = received_request;
- break;
- }
- }
- spin_unlock_irqrestore(&dev->blk_lock, irqflags);
- if (blk_request == NULL)
- error_dev_va("ERROR: Received block data for unrequested handle (%llu: %llu).\n",
- (unsigned long long)dnbd3_reply.handle, (unsigned long long)dnbd3_reply.size);
- // receive data and answer to block layer
- rq_for_each_segment(bvec, blk_request, iter)
- {
- siginitsetinv(&blocked, sigmask(SIGKILL));
- sigprocmask(SIG_SETMASK, &blocked, &oldset);
-
- kaddr = kmap(bvec->bv_page) + bvec->bv_offset;
- iov.iov_base = kaddr;
- iov.iov_len = bvec->bv_len;
- if (kernel_recvmsg(dev->sock, &msg, &iov, 1, bvec->bv_len, msg.msg_flags) != bvec->bv_len)
- {
- kunmap(bvec->bv_page);
- sigprocmask(SIG_SETMASK, &oldset, NULL);
- error_dev("ERROR: Receiving from net to block layer.");
- }
- kunmap(bvec->bv_page);
-
- sigprocmask(SIG_SETMASK, &oldset, NULL);
- }
- spin_lock_irqsave(&dev->blk_lock, irqflags);
- list_del_init(&blk_request->queuelist);
- __blk_end_request_all(blk_request, 0);
- spin_unlock_irqrestore(&dev->blk_lock, irqflags);
- continue;
-
- case CMD_GET_SERVERS:
- if (dev->is_server || !is_same_server(&dev->cur_server, &dev->initial_server))
- { // If not connected to initial server, or device is in proxy mode, ignore this message
- remaining = dnbd3_reply.size;
- goto clear_remaining_payload;
- }
- spin_lock_irqsave(&dev->blk_lock, irqflags);
- dev->new_servers_num = 0;
- spin_unlock_irqrestore(&dev->blk_lock, irqflags);
- count = MIN(NUMBER_SERVERS, dnbd3_reply.size / sizeof(dnbd3_server_entry_t));
-
- if (count != 0)
- {
+ dnbd3_device_t *dev = data;
+ struct request *blk_request, *tmp_request, *received_request;
+
+ dnbd3_reply_t dnbd3_reply;
+ struct msghdr msg;
+ struct kvec iov;
+ struct req_iterator iter;
+ struct bio_vec *bvec;
+ void *kaddr;
+ unsigned long irqflags;
+ sigset_t blocked, oldset;
+ uint16_t rid;
+
+ int count, remaining, ret, recv_timeout = 0;
+
+ init_msghdr(msg);
+ set_user_nice(current, -20);
+
+ while (!kthread_should_stop())
+ {
+ // receive net reply
+ iov.iov_base = &dnbd3_reply;
+ iov.iov_len = sizeof(dnbd3_reply);
+ ret = kernel_recvmsg(dev->sock, &msg, &iov, 1, sizeof(dnbd3_reply), msg.msg_flags);
+ if (ret == -EAGAIN)
+ {
+ if ((recv_timeout += SOCKET_TIMEOUT_CLIENT_DATA) > SOCKET_KEEPALIVE_TIMEOUT)
+ error_dev("ERROR: Receive timeout reached.");
+ continue;
+ }
+ if (ret <= 0)
+ error_dev_va("Connection closed (%d).", ret);
+ if (ret != sizeof(dnbd3_reply))
+ error_dev("ERROR: Recv msg header.");
+ fixup_reply(dnbd3_reply);
+
+ // check error
+ if (dnbd3_reply.magic != dnbd3_packet_magic)
+ error_dev("ERROR: Wrong packet magic (Receive).");
+ if (dnbd3_reply.cmd == 0)
+ error_dev("ERROR: Command was 0 (Receive).");
+
+ recv_timeout = 0;
+
+ // what to do?
+ switch (dnbd3_reply.cmd)
+ {
+ case CMD_GET_BLOCK:
+ // search for replied request in queue
+ blk_request = NULL;
+ spin_lock_irqsave(&dev->blk_lock, irqflags);
+ list_for_each_entry_safe(received_request, tmp_request, &dev->request_queue_receive, queuelist)
+ {
+ if ((uint64_t)(uintptr_t)received_request == dnbd3_reply.handle) // Double cast to prevent warning on 32bit
+ {
+ blk_request = received_request;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&dev->blk_lock, irqflags);
+ if (blk_request == NULL)
+ error_dev_va("ERROR: Received block data for unrequested handle (%llu: %llu).\n",
+ (unsigned long long)dnbd3_reply.handle, (unsigned long long)dnbd3_reply.size);
+ // receive data and answer to block layer
+ rq_for_each_segment(bvec, blk_request, iter)
+ {
+ siginitsetinv(&blocked, sigmask(SIGKILL));
+ sigprocmask(SIG_SETMASK, &blocked, &oldset);
+
+ kaddr = kmap(bvec->bv_page) + bvec->bv_offset;
+ iov.iov_base = kaddr;
+ iov.iov_len = bvec->bv_len;
+ if (kernel_recvmsg(dev->sock, &msg, &iov, 1, bvec->bv_len, msg.msg_flags) != bvec->bv_len)
+ {
+ kunmap(bvec->bv_page);
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+ error_dev("ERROR: Receiving from net to block layer.");
+ }
+ kunmap(bvec->bv_page);
+
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+ }
+ spin_lock_irqsave(&dev->blk_lock, irqflags);
+ list_del_init(&blk_request->queuelist);
+ __blk_end_request_all(blk_request, 0);
+ spin_unlock_irqrestore(&dev->blk_lock, irqflags);
+ continue;
+
+ case CMD_GET_SERVERS:
+ if (dev->is_server || !is_same_server(&dev->cur_server, &dev->initial_server))
+ {
+ // If not connected to initial server, or device is in proxy mode, ignore this message
+ remaining = dnbd3_reply.size;
+ goto clear_remaining_payload;
+ }
+ spin_lock_irqsave(&dev->blk_lock, irqflags);
+ dev->new_servers_num = 0;
+ spin_unlock_irqrestore(&dev->blk_lock, irqflags);
+ count = MIN(NUMBER_SERVERS, dnbd3_reply.size / sizeof(dnbd3_server_entry_t));
+
+ if (count != 0)
+ {
iov.iov_base = dev->new_servers;
iov.iov_len = count * sizeof(dnbd3_server_entry_t);
if (kernel_recvmsg(dev->sock, &msg, &iov, 1, (count * sizeof(dnbd3_server_entry_t)), msg.msg_flags) != (count * sizeof(dnbd3_server_entry_t)))
error_dev("ERROR: Recv CMD_GET_SERVERS payload.");
- spin_lock_irqsave(&dev->blk_lock, irqflags);
- dev->new_servers_num = count;
- spin_unlock_irqrestore(&dev->blk_lock, irqflags);
- }
- // If there were more servers than accepted, remove the remaining data from the socket buffer
- remaining = dnbd3_reply.size - (count * sizeof(dnbd3_server_entry_t));
+ spin_lock_irqsave(&dev->blk_lock, irqflags);
+ dev->new_servers_num = count;
+ spin_unlock_irqrestore(&dev->blk_lock, irqflags);
+ }
+ // If there were more servers than accepted, remove the remaining data from the socket buffer
+ remaining = dnbd3_reply.size - (count * sizeof(dnbd3_server_entry_t));
clear_remaining_payload:
- while (remaining > 0)
- {
- count = MIN(sizeof(dnbd3_reply), remaining); // Abuse the reply struct as the receive buffer
- iov.iov_base = &dnbd3_reply;
- iov.iov_len = count;
- ret = kernel_recvmsg(dev->sock, &msg, &iov, 1, iov.iov_len, msg.msg_flags);
- if (ret <= 0)
- error_dev("ERROR: Recv additional payload from CMD_GET_SERVERS.");
- remaining -= ret;
- }
- continue;
-
- case CMD_LATEST_RID:
- if (dnbd3_reply.size != 2)
- {
- printk("ERROR: CMD_LATEST_RID.size != 2.\n");
- continue;
- }
- iov.iov_base = &rid;
- iov.iov_len = sizeof(rid);
- if (kernel_recvmsg(dev->sock, &msg, &iov, 1, iov.iov_len, msg.msg_flags) <= 0)
- {
- printk("ERROR: Could not receive CMD_LATEST_RID payload.\n");
- }
- else
- {
- rid = net_order_16(rid);
- printk("Latest rid of %s is %d (currently using %d)\n", dev->imgname, (int)rid, (int)dev->rid);
- dev->update_available = (rid > dev->rid ? 1 : 0);
- }
- continue;
-
- case CMD_KEEPALIVE:
- if (dnbd3_reply.size != 0)
- printk("ERROR: keep alive packet with payload.\n");
- continue;
-
- default:
- printk("ERROR: Unknown command (Receive)\n");
- continue;
-
- }
- }
-
- printk("dnbd3_net_receive terminated normally.\n");
- return 0;
+ while (remaining > 0)
+ {
+ count = MIN(sizeof(dnbd3_reply), remaining); // Abuse the reply struct as the receive buffer
+ iov.iov_base = &dnbd3_reply;
+ iov.iov_len = count;
+ ret = kernel_recvmsg(dev->sock, &msg, &iov, 1, iov.iov_len, msg.msg_flags);
+ if (ret <= 0)
+ error_dev("ERROR: Recv additional payload from CMD_GET_SERVERS.");
+ remaining -= ret;
+ }
+ continue;
+
+ case CMD_LATEST_RID:
+ if (dnbd3_reply.size != 2)
+ {
+ printk("ERROR: CMD_LATEST_RID.size != 2.\n");
+ continue;
+ }
+ iov.iov_base = &rid;
+ iov.iov_len = sizeof(rid);
+ if (kernel_recvmsg(dev->sock, &msg, &iov, 1, iov.iov_len, msg.msg_flags) <= 0)
+ {
+ printk("ERROR: Could not receive CMD_LATEST_RID payload.\n");
+ }
+ else
+ {
+ rid = net_order_16(rid);
+ printk("Latest rid of %s is %d (currently using %d)\n", dev->imgname, (int)rid, (int)dev->rid);
+ dev->update_available = (rid > dev->rid ? 1 : 0);
+ }
+ continue;
+
+ case CMD_KEEPALIVE:
+ if (dnbd3_reply.size != 0)
+ printk("ERROR: keep alive packet with payload.\n");
+ continue;
+
+ default:
+ printk("ERROR: Unknown command (Receive)\n");
+ continue;
+
+ }
+ }
+
+ printk("dnbd3_net_receive terminated normally.\n");
+ return 0;
error:
// move already sent requests to request_queue_send again
diff --git a/src/kernel/sysfs.c b/src/kernel/sysfs.c
index d502194..596e745 100644
--- a/src/kernel/sysfs.c
+++ b/src/kernel/sysfs.c
@@ -39,7 +39,7 @@ ssize_t show_cur_server_addr(char *buf, dnbd3_device_t *dev)
ssize_t show_cur_server_rtt(char *buf, dnbd3_device_t *dev)
{
- return MIN(snprintf(buf, PAGE_SIZE, "%llu\n", (unsigned long long)dev->cur_rtt), PAGE_SIZE);
+ return MIN(snprintf(buf, PAGE_SIZE, "%llu\n", (unsigned long long)dev->cur_rtt), PAGE_SIZE);
}
ssize_t show_alt_server_num(char *buf, dnbd3_device_t *dev)
@@ -49,7 +49,7 @@ ssize_t show_alt_server_num(char *buf, dnbd3_device_t *dev)
{
if (dev->alt_servers[i].hostaddrtype) ++num;
}
- return MIN(snprintf(buf, PAGE_SIZE, "%d\n", num), PAGE_SIZE);
+ return MIN(snprintf(buf, PAGE_SIZE, "%d\n", num), PAGE_SIZE);
}
ssize_t show_alt_servers(char *buf, dnbd3_device_t *dev)
@@ -59,18 +59,18 @@ ssize_t show_alt_servers(char *buf, dnbd3_device_t *dev)
{
if (dev->alt_servers[i].hostaddrtype == AF_INET)
ret = MIN(snprintf(buf, size, "%pI4,%d,%llu,%d\n",
- dev->alt_servers[i].hostaddr,
- (int)ntohs(dev->alt_servers[i].port),
- (unsigned long long)((dev->alt_servers[i].rtts[0] + dev->alt_servers[i].rtts[1] + dev->alt_servers[i].rtts[2] + dev->alt_servers[i].rtts[3]) / 4),
- (int)dev->alt_servers[i].failures)
- , size);
+ dev->alt_servers[i].hostaddr,
+ (int)ntohs(dev->alt_servers[i].port),
+ (unsigned long long)((dev->alt_servers[i].rtts[0] + dev->alt_servers[i].rtts[1] + dev->alt_servers[i].rtts[2] + dev->alt_servers[i].rtts[3]) / 4),
+ (int)dev->alt_servers[i].failures)
+ , size);
else if (dev->alt_servers[i].hostaddrtype == AF_INET6)
ret = MIN(snprintf(buf, size, "%pI6,%d,%llu,%d\n",
- dev->alt_servers[i].hostaddr,
- (int)ntohs(dev->alt_servers[i].port),
- (unsigned long long)((dev->alt_servers[i].rtts[0] + dev->alt_servers[i].rtts[1] + dev->alt_servers[i].rtts[2] + dev->alt_servers[i].rtts[3]) / 4),
- (int)dev->alt_servers[i].failures)
- , size);
+ dev->alt_servers[i].hostaddr,
+ (int)ntohs(dev->alt_servers[i].port),
+ (unsigned long long)((dev->alt_servers[i].rtts[0] + dev->alt_servers[i].rtts[1] + dev->alt_servers[i].rtts[2] + dev->alt_servers[i].rtts[3]) / 4),
+ (int)dev->alt_servers[i].failures)
+ , size);
else
continue;
size -= ret;
@@ -81,122 +81,122 @@ ssize_t show_alt_servers(char *buf, dnbd3_device_t *dev)
break;
}
}
- return PAGE_SIZE - size;
+ return PAGE_SIZE - size;
}
ssize_t show_image_name(char *buf, dnbd3_device_t *dev)
{
if (dev->imgname == NULL) return sprintf(buf, "(null)");
- return MIN(snprintf(buf, PAGE_SIZE, "%s\n", dev->imgname), PAGE_SIZE);
+ return MIN(snprintf(buf, PAGE_SIZE, "%s\n", dev->imgname), PAGE_SIZE);
}
ssize_t show_rid(char *buf, dnbd3_device_t *dev)
{
- return MIN(snprintf(buf, PAGE_SIZE, "%d\n", dev->rid), PAGE_SIZE);
+ return MIN(snprintf(buf, PAGE_SIZE, "%d\n", dev->rid), PAGE_SIZE);
}
ssize_t show_update_available(char *buf, dnbd3_device_t *dev)
{
- return MIN(snprintf(buf, PAGE_SIZE, "%d\n", dev->update_available), PAGE_SIZE);
+ return MIN(snprintf(buf, PAGE_SIZE, "%d\n", dev->update_available), PAGE_SIZE);
}
device_attr_t cur_server_addr =
{
- .attr = {.name = "cur_server_addr", .mode = 0444 },
- .show = show_cur_server_addr,
- .store = NULL,
+ .attr = {.name = "cur_server_addr", .mode = 0444 },
+ .show = show_cur_server_addr,
+ .store = NULL,
};
device_attr_t cur_server_rtt =
{
- .attr = {.name = "cur_server_rtt", .mode = 0444 },
- .show = show_cur_server_rtt,
- .store = NULL,
+ .attr = {.name = "cur_server_rtt", .mode = 0444 },
+ .show = show_cur_server_rtt,
+ .store = NULL,
};
device_attr_t alt_server_num =
{
- .attr = {.name = "alt_server_num", .mode = 0444 },
- .show = show_alt_server_num,
- .store = NULL,
+ .attr = {.name = "alt_server_num", .mode = 0444 },
+ .show = show_alt_server_num,
+ .store = NULL,
};
device_attr_t alt_servers =
{
- .attr = {.name = "alt_servers", .mode = 0444 },
- .show = show_alt_servers,
- .store = NULL,
+ .attr = {.name = "alt_servers", .mode = 0444 },
+ .show = show_alt_servers,
+ .store = NULL,
};
device_attr_t image_name =
{
- .attr = {.name = "image_name", .mode = 0444 },
- .show = show_image_name,
- .store = NULL,
+ .attr = {.name = "image_name", .mode = 0444 },
+ .show = show_image_name,
+ .store = NULL,
};
device_attr_t rid =
{
- .attr = {.name = "rid", .mode = 0444 },
- .show = show_rid,
- .store = NULL,
+ .attr = {.name = "rid", .mode = 0444 },
+ .show = show_rid,
+ .store = NULL,
};
device_attr_t update_available =
{
- .attr = {.name = "update_available", .mode = 0444 },
- .show = show_update_available,
- .store = NULL,
+ .attr = {.name = "update_available", .mode = 0444 },
+ .show = show_update_available,
+ .store = NULL,
};
ssize_t device_show(struct kobject *kobj, struct attribute *attr, char *buf)
{
- device_attr_t *device_attr = container_of(attr, device_attr_t, attr);
- dnbd3_device_t *dev = container_of(kobj, dnbd3_device_t, kobj);
- return device_attr->show(buf, dev);
+ device_attr_t *device_attr = container_of(attr, device_attr_t, attr);
+ dnbd3_device_t *dev = container_of(kobj, dnbd3_device_t, kobj);
+ return device_attr->show(buf, dev);
}
struct attribute *device_attrs[] =
{
- &cur_server_addr.attr,
- &cur_server_rtt.attr,
- &alt_server_num.attr,
- &alt_servers.attr,
- &image_name.attr,
- &rid.attr,
- &update_available.attr,
- NULL,
+ &cur_server_addr.attr,
+ &cur_server_rtt.attr,
+ &alt_server_num.attr,
+ &alt_servers.attr,
+ &image_name.attr,
+ &rid.attr,
+ &update_available.attr,
+ NULL,
};
struct sysfs_ops device_ops =
{
- .show = device_show,
+ .show = device_show,
};
void release(struct kobject *kobj)
{
- kobj->state_initialized = 0;
+ kobj->state_initialized = 0;
}
struct kobj_type device_ktype =
{
- .default_attrs = device_attrs,
- .sysfs_ops = &device_ops,
- .release = release,
+ .default_attrs = device_attrs,
+ .sysfs_ops = &device_ops,
+ .release = release,
};
void dnbd3_sysfs_init(dnbd3_device_t *dev)
{
- struct kobject *kobj = &dev->kobj;
- struct kobj_type *ktype = &device_ktype;
- struct kobject *parent = &disk_to_dev(dev->disk)->kobj;
+ struct kobject *kobj = &dev->kobj;
+ struct kobj_type *ktype = &device_ktype;
+ struct kobject *parent = &disk_to_dev(dev->disk)->kobj;
- kobject_init_and_add(kobj, ktype, parent, "net");
+ kobject_init_and_add(kobj, ktype, parent, "net");
}
void dnbd3_sysfs_exit(dnbd3_device_t *dev)
{
- kobject_put(&dev->kobj);
+ kobject_put(&dev->kobj);
}
diff --git a/src/kernel/sysfs.h b/src/kernel/sysfs.h
index ab5ceb5..0a747a5 100644
--- a/src/kernel/sysfs.h
+++ b/src/kernel/sysfs.h
@@ -29,16 +29,16 @@ void dnbd3_sysfs_exit(dnbd3_device_t *dev);
typedef struct
{
- struct attribute attr;
- ssize_t (*show)(char *, dnbd3_device_t *);
- ssize_t (*store)(const char *, size_t, dnbd3_device_t *);
+ struct attribute attr;
+ ssize_t (*show)(char *, dnbd3_device_t *);
+ ssize_t (*store)(const char *, size_t, dnbd3_device_t *);
} device_attr_t;
typedef struct
{
- struct attribute attr;
- ssize_t (*show)(char *, dnbd3_server_t *);
- ssize_t (*store)(const char *, size_t, dnbd3_server_t *);
+ struct attribute attr;
+ ssize_t (*show)(char *, dnbd3_server_t *);
+ ssize_t (*store)(const char *, size_t, dnbd3_server_t *);
} server_attr_t;
diff --git a/src/kernel/utils.c b/src/kernel/utils.c
index 221dc4d..902025f 100644
--- a/src/kernel/utils.c
+++ b/src/kernel/utils.c
@@ -24,18 +24,18 @@
unsigned int inet_addr(char *str)
{
- int a, b, c, d;
- char arr[4];
- sscanf(str, "%d.%d.%d.%d", &a, &b, &c, &d);
- arr[0] = a;
- arr[1] = b;
- arr[2] = c;
- arr[3] = d;
- return *(unsigned int*) arr;
+ int a, b, c, d;
+ char arr[4];
+ sscanf(str, "%d.%d.%d.%d", &a, &b, &c, &d);
+ arr[0] = a;
+ arr[1] = b;
+ arr[2] = c;
+ arr[3] = d;
+ return *(unsigned int *) arr;
}
-void inet_ntoa(struct in_addr addr, char* str)
+void inet_ntoa(struct in_addr addr, char *str)
{
- unsigned char *ptr = (unsigned char *) &addr;
- sprintf(str, "%d.%d.%d.%d", ptr[0] & 0xff, ptr[1] & 0xff, ptr[2] & 0xff, ptr[3] & 0xff);
+ unsigned char *ptr = (unsigned char *) &addr;
+ sprintf(str, "%d.%d.%d.%d", ptr[0] & 0xff, ptr[1] & 0xff, ptr[2] & 0xff, ptr[3] & 0xff);
}
diff --git a/src/kernel/utils.h b/src/kernel/utils.h
index b2c5fb1..e54b3cf 100644
--- a/src/kernel/utils.h
+++ b/src/kernel/utils.h
@@ -24,6 +24,6 @@
#include <linux/in.h>
unsigned int inet_addr(char *str);
-void inet_ntoa(struct in_addr addr, char* str);
+void inet_ntoa(struct in_addr addr, char *str);
#endif /* UTILS_H_ */