From a55be46ec7a281f5c3d41d48edf32e57ef5e4ba1 Mon Sep 17 00:00:00 2001 From: sr Date: Mon, 3 Sep 2012 15:27:36 +0200 Subject: [*] Fixed and unified formatting --- src/kernel/blk.c | 320 ++++++------ src/kernel/core.c | 60 +-- src/kernel/dnbd3.h | 70 +-- src/kernel/net.c | 1472 ++++++++++++++++++++++++++-------------------------- src/kernel/sysfs.c | 116 ++--- src/kernel/sysfs.h | 12 +- src/kernel/utils.c | 22 +- src/kernel/utils.h | 2 +- 8 files changed, 1040 insertions(+), 1034 deletions(-) (limited to 'src/kernel') 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 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_ */ -- cgit v1.2.3-55-g7522