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/client/client.c | 433 +++++++-------- 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 +- src/serialize.c | 2 +- src/serialize.h | 2 +- src/server/ipc.c | 27 +- src/server/ipc.h | 8 +- src/server/job.c | 24 +- src/server/job.h | 2 +- src/server/memlog.c | 20 +- src/server/memlog.h | 2 +- src/server/net.c | 535 +++++++++---------- src/server/server.c | 405 +++++++------- src/server/server.h | 34 +- src/server/utils.c | 121 +++-- src/server/utils.h | 2 +- src/types.h | 30 +- 23 files changed, 1873 insertions(+), 1848 deletions(-) diff --git a/src/client/client.c b/src/client/client.c index 81a727f..b94076f 100644 --- a/src/client/client.c +++ b/src/client/client.c @@ -35,232 +35,233 @@ char *_config_file_name = DEFAULT_CLIENT_CONFIG_FILE; -void dnbd3_print_help(char* argv_0) +void dnbd3_print_help(char *argv_0) { - printf("\nUsage: %s\n" - "\t-h -i [-r ] -d [-a ] || -f || -c \n\n", argv_0); - printf("Start the DNBD3 client.\n"); - printf("-f or --file \t\t Configuration file (default /etc/dnbd3-client.conf)\n"); - printf("-h or --host \t\t Host running dnbd3-server.\n"); - printf("-i or --image \t\t Image name of exported image.\n"); - printf("-r or --rid \t\t Release-ID of exported image (default 0, latest).\n"); - printf("-d or --device \t\t DNBD3 device name.\n"); - printf("-a or --ahead \t\t Read ahead in KByte (default %i).\n", DEFAULT_READ_AHEAD_KB); - printf("-c or --close \t\t Disconnect and close device.\n"); - printf("-s or --switch \t\t Switch dnbd3-server on device (DEBUG).\n"); - printf("-H or --help \t\t Show this help text and quit.\n"); - printf("-V or --version \t Show version and quit.\n\n"); - exit(EXIT_SUCCESS); + printf("\nUsage: %s\n" + "\t-h -i [-r ] -d [-a ] || -f || -c \n\n", argv_0); + printf("Start the DNBD3 client.\n"); + printf("-f or --file \t\t Configuration file (default /etc/dnbd3-client.conf)\n"); + printf("-h or --host \t\t Host running dnbd3-server.\n"); + printf("-i or --image \t\t Image name of exported image.\n"); + printf("-r or --rid \t\t Release-ID of exported image (default 0, latest).\n"); + printf("-d or --device \t\t DNBD3 device name.\n"); + printf("-a or --ahead \t\t Read ahead in KByte (default %i).\n", DEFAULT_READ_AHEAD_KB); + printf("-c or --close \t\t Disconnect and close device.\n"); + printf("-s or --switch \t\t Switch dnbd3-server on device (DEBUG).\n"); + printf("-H or --help \t\t Show this help text and quit.\n"); + printf("-V or --version \t Show version and quit.\n\n"); + exit(EXIT_SUCCESS); } void dnbd3_print_version() { - printf("Version: %s\n", VERSION_STRING); - exit(EXIT_SUCCESS); + printf("Version: %s\n", VERSION_STRING); + exit(EXIT_SUCCESS); } -static void dnbd3_get_ip(char* hostname, uint8_t *target, uint8_t *addrtype) +static void dnbd3_get_ip(char *hostname, uint8_t *target, uint8_t *addrtype) { - struct hostent *host; - - if ((host = gethostbyname(hostname)) == NULL) - { - printf("FATAL: Unknown host '%s'\n", hostname); - exit(EXIT_FAILURE); - } - - *addrtype = (uint8_t)host->h_addrtype; - if (host->h_addrtype == AF_INET) - memcpy(target, host->h_addr, 4); - else if (host->h_addrtype == AF_INET6) - memcpy(target, host->h_addr, 16); - else - { - printf("FATAL: Unknown address type: %d\n", host->h_addrtype); - exit(EXIT_FAILURE); - } + struct hostent *host; + + if ((host = gethostbyname(hostname)) == NULL) + { + printf("FATAL: Unknown host '%s'\n", hostname); + exit(EXIT_FAILURE); + } + + *addrtype = (uint8_t)host->h_addrtype; + if (host->h_addrtype == AF_INET) + memcpy(target, host->h_addr, 4); + else if (host->h_addrtype == AF_INET6) + memcpy(target, host->h_addr, 16); + else + { + printf("FATAL: Unknown address type: %d\n", host->h_addrtype); + exit(EXIT_FAILURE); + } } int main(int argc, char *argv[]) { - int fd; - char *dev = NULL; - - int close_dev = 0; - int switch_host = 0; - - dnbd3_ioctl_t msg; - memset(&msg, 0, sizeof(dnbd3_ioctl_t)); - msg.len = (uint16_t)sizeof(dnbd3_ioctl_t); - msg.read_ahead_kb = DEFAULT_READ_AHEAD_KB; - msg.port = htons(PORT); - msg.addrtype = 0; - msg.imgname = NULL; - msg.is_server = FALSE; - - int opt = 0; - int longIndex = 0; - static const char *optString = "f:h:i:r:d:a:c:s:HV?"; - static const struct option longOpts[] = - { - { "file", required_argument, NULL, 'f' }, - { "host", required_argument, NULL, 'h' }, - { "image", required_argument, NULL, 'i' }, - { "rid", required_argument, NULL, 'r' }, - { "device", required_argument, NULL, 'd' }, - { "ahead", required_argument, NULL, 'a' }, - { "close", required_argument, NULL, 'c' }, - { "switch", required_argument, NULL, 's' }, - { "help", no_argument, NULL, 'H' }, - { "version", no_argument, NULL, 'V' }, }; - - opt = getopt_long(argc, argv, optString, longOpts, &longIndex); - - while (opt != -1) - { - switch (opt) - { - case 'f': - _config_file_name = strdup(optarg); - break; - case 'h': - dnbd3_get_ip(optarg, msg.addr, &msg.addrtype); - printf("Host set to %s (type %d)\n", inet_ntoa(*(struct in_addr*)msg.addr), (int)msg.addrtype); - break; - case 'i': - msg.imgname = strdup(optarg); - printf("Image: %s\n", msg.imgname); - break; - case 'r': - msg.rid = atoi(optarg); - break; - case 'd': - dev = strdup(optarg); - printf("Device is %s\n", dev); - break; - case 'a': - msg.read_ahead_kb = atoi(optarg); - break; - case 'c': - dev = strdup(optarg); - close_dev = 1; - break; - case 's': - dnbd3_get_ip(optarg, msg.addr, &msg.addrtype); - switch_host = 1; - break; - case 'H': - dnbd3_print_help(argv[0]); - break; - case 'V': - dnbd3_print_version(); - break; - case '?': - dnbd3_print_help(argv[0]); - break; - } - opt = getopt_long(argc, argv, optString, longOpts, &longIndex); - } - - // close device - if (close_dev && msg.addrtype == 0 && dev && (msg.imgname == NULL)) - { - fd = open(dev, O_WRONLY); - printf("INFO: Closing device %s\n", dev); - - const int ret = ioctl(fd, IOCTL_CLOSE, &msg); - if (ret < 0) - { - printf("ERROR: ioctl not successful (close, %s (%d))\n", strerror(-ret), ret); - exit(EXIT_FAILURE); - } - - close(fd); - exit(EXIT_SUCCESS); - } - - // switch host - if (switch_host && msg.addrtype != 0 && dev && (msg.imgname == NULL)) - { - fd = open(dev, O_WRONLY); - printf("INFO: Switching device %s to %s\n", dev, ""); - - const int ret = ioctl(fd, IOCTL_SWITCH, &msg); - if (ret < 0) - { - printf("ERROR: ioctl not successful (switch, %s (%d))\n", strerror(-ret), ret); - exit(EXIT_FAILURE); - } - - close(fd); - exit(EXIT_SUCCESS); - } - - // connect - if (msg.addrtype != 0 && dev && (msg.imgname != NULL)) - { - msg.imgnamelen = (uint16_t)strlen(msg.imgname); - fd = open(dev, O_WRONLY); - printf("INFO: Connecting %s to %s (%s rid:%i)\n", dev, "", msg.imgname, msg.rid); - - const int ret = ioctl(fd, IOCTL_OPEN, &msg); - if (ret < 0) - { - printf("ERROR: ioctl not successful (connect, %s (%d))\n", strerror(-ret), ret); - exit(EXIT_FAILURE); - } - - close(fd); - exit(EXIT_SUCCESS); - } - - // use configuration file if exist - GKeyFile* gkf; - int i = 0; - size_t j = 0; - - gkf = g_key_file_new(); - - if (g_key_file_load_from_file(gkf, _config_file_name, G_KEY_FILE_NONE, NULL)) - { - gchar **groups = NULL; - groups = g_key_file_get_groups(gkf, &j); - - for (i = 0; i < j; i++) - { - dnbd3_get_ip(g_key_file_get_string(gkf, groups[i], "server", NULL), msg.addr, &msg.addrtype); - msg.imgname = g_key_file_get_string(gkf, groups[i], "name", NULL); - msg.rid = g_key_file_get_integer(gkf, groups[i], "rid", NULL); - dev = g_key_file_get_string(gkf, groups[i], "device", NULL); - - msg.read_ahead_kb = g_key_file_get_integer(gkf, groups[i], "ahead", NULL); - if (!msg.read_ahead_kb) - msg.read_ahead_kb = DEFAULT_READ_AHEAD_KB; - - fd = open(dev, O_WRONLY); - printf("INFO: Connecting %s to %s (%s rid:%i)\n", dev, "", msg.imgname, msg.rid); - - const int ret = ioctl(fd, IOCTL_OPEN, &msg); - if (ret < 0) - { - printf("ERROR: ioctl not successful (config file, %s (%d))\n", strerror(-ret), ret); - exit(EXIT_FAILURE); - } - - close(fd); - } - - g_strfreev(groups); - g_key_file_free(gkf); - exit(EXIT_SUCCESS); - } - else - { - printf("ERROR: Config file not found: %s\n", _config_file_name); - } - - g_key_file_free(gkf); - - dnbd3_print_help(argv[0]); - exit(EXIT_FAILURE); + int fd; + char *dev = NULL; + + int close_dev = 0; + int switch_host = 0; + + dnbd3_ioctl_t msg; + memset(&msg, 0, sizeof(dnbd3_ioctl_t)); + msg.len = (uint16_t)sizeof(dnbd3_ioctl_t); + msg.read_ahead_kb = DEFAULT_READ_AHEAD_KB; + msg.port = htons(PORT); + msg.addrtype = 0; + msg.imgname = NULL; + msg.is_server = FALSE; + + int opt = 0; + int longIndex = 0; + static const char *optString = "f:h:i:r:d:a:c:s:HV?"; + static const struct option longOpts[] = + { + { "file", required_argument, NULL, 'f' }, + { "host", required_argument, NULL, 'h' }, + { "image", required_argument, NULL, 'i' }, + { "rid", required_argument, NULL, 'r' }, + { "device", required_argument, NULL, 'd' }, + { "ahead", required_argument, NULL, 'a' }, + { "close", required_argument, NULL, 'c' }, + { "switch", required_argument, NULL, 's' }, + { "help", no_argument, NULL, 'H' }, + { "version", no_argument, NULL, 'V' }, + }; + + opt = getopt_long(argc, argv, optString, longOpts, &longIndex); + + while (opt != -1) + { + switch (opt) + { + case 'f': + _config_file_name = strdup(optarg); + break; + case 'h': + dnbd3_get_ip(optarg, msg.addr, &msg.addrtype); + printf("Host set to %s (type %d)\n", inet_ntoa(*(struct in_addr *)msg.addr), (int)msg.addrtype); + break; + case 'i': + msg.imgname = strdup(optarg); + printf("Image: %s\n", msg.imgname); + break; + case 'r': + msg.rid = atoi(optarg); + break; + case 'd': + dev = strdup(optarg); + printf("Device is %s\n", dev); + break; + case 'a': + msg.read_ahead_kb = atoi(optarg); + break; + case 'c': + dev = strdup(optarg); + close_dev = 1; + break; + case 's': + dnbd3_get_ip(optarg, msg.addr, &msg.addrtype); + switch_host = 1; + break; + case 'H': + dnbd3_print_help(argv[0]); + break; + case 'V': + dnbd3_print_version(); + break; + case '?': + dnbd3_print_help(argv[0]); + break; + } + opt = getopt_long(argc, argv, optString, longOpts, &longIndex); + } + + // close device + if (close_dev && msg.addrtype == 0 && dev && (msg.imgname == NULL)) + { + fd = open(dev, O_WRONLY); + printf("INFO: Closing device %s\n", dev); + + const int ret = ioctl(fd, IOCTL_CLOSE, &msg); + if (ret < 0) + { + printf("ERROR: ioctl not successful (close, %s (%d))\n", strerror(-ret), ret); + exit(EXIT_FAILURE); + } + + close(fd); + exit(EXIT_SUCCESS); + } + + // switch host + if (switch_host && msg.addrtype != 0 && dev && (msg.imgname == NULL)) + { + fd = open(dev, O_WRONLY); + printf("INFO: Switching device %s to %s\n", dev, ""); + + const int ret = ioctl(fd, IOCTL_SWITCH, &msg); + if (ret < 0) + { + printf("ERROR: ioctl not successful (switch, %s (%d))\n", strerror(-ret), ret); + exit(EXIT_FAILURE); + } + + close(fd); + exit(EXIT_SUCCESS); + } + + // connect + if (msg.addrtype != 0 && dev && (msg.imgname != NULL)) + { + msg.imgnamelen = (uint16_t)strlen(msg.imgname); + fd = open(dev, O_WRONLY); + printf("INFO: Connecting %s to %s (%s rid:%i)\n", dev, "", msg.imgname, msg.rid); + + const int ret = ioctl(fd, IOCTL_OPEN, &msg); + if (ret < 0) + { + printf("ERROR: ioctl not successful (connect, %s (%d))\n", strerror(-ret), ret); + exit(EXIT_FAILURE); + } + + close(fd); + exit(EXIT_SUCCESS); + } + + // use configuration file if exist + GKeyFile *gkf; + int i = 0; + size_t j = 0; + + gkf = g_key_file_new(); + + if (g_key_file_load_from_file(gkf, _config_file_name, G_KEY_FILE_NONE, NULL)) + { + gchar **groups = NULL; + groups = g_key_file_get_groups(gkf, &j); + + for (i = 0; i < j; i++) + { + dnbd3_get_ip(g_key_file_get_string(gkf, groups[i], "server", NULL), msg.addr, &msg.addrtype); + msg.imgname = g_key_file_get_string(gkf, groups[i], "name", NULL); + msg.rid = g_key_file_get_integer(gkf, groups[i], "rid", NULL); + dev = g_key_file_get_string(gkf, groups[i], "device", NULL); + + msg.read_ahead_kb = g_key_file_get_integer(gkf, groups[i], "ahead", NULL); + if (!msg.read_ahead_kb) + msg.read_ahead_kb = DEFAULT_READ_AHEAD_KB; + + fd = open(dev, O_WRONLY); + printf("INFO: Connecting %s to %s (%s rid:%i)\n", dev, "", msg.imgname, msg.rid); + + const int ret = ioctl(fd, IOCTL_OPEN, &msg); + if (ret < 0) + { + printf("ERROR: ioctl not successful (config file, %s (%d))\n", strerror(-ret), ret); + exit(EXIT_FAILURE); + } + + close(fd); + } + + g_strfreev(groups); + g_key_file_free(gkf); + exit(EXIT_SUCCESS); + } + else + { + printf("ERROR: Config file not found: %s\n", _config_file_name); + } + + g_key_file_free(gkf); + + dnbd3_print_help(argv[0]); + exit(EXIT_FAILURE); } 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_ */ diff --git a/src/serialize.c b/src/serialize.c index 932df14..e67939e 100644 --- a/src/serialize.c +++ b/src/serialize.c @@ -41,7 +41,7 @@ uint64_t serializer_get_uint64(serialized_buffer_t *buffer) return net_order_64(ret); } -char* serializer_get_string(serialized_buffer_t *buffer) +char *serializer_get_string(serialized_buffer_t *buffer) { char *ptr = buffer->buffer_pointer, *start = buffer->buffer_pointer; if (ptr >= buffer->buffer_end) return NULL; diff --git a/src/serialize.h b/src/serialize.h index 0d9620a..b6ce145 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -24,7 +24,7 @@ uint16_t serializer_get_uint16(serialized_buffer_t *buffer); uint64_t serializer_get_uint64(serialized_buffer_t *buffer); -char* serializer_get_string(serialized_buffer_t *buffer); +char *serializer_get_string(serialized_buffer_t *buffer); // diff --git a/src/server/ipc.c b/src/server/ipc.c index e988abc..339dcc6 100644 --- a/src/server/ipc.c +++ b/src/server/ipc.c @@ -600,7 +600,8 @@ get_info_reply_cleanup: xmlFree(image.file); xmlFree(image.cache_file); } - } END_FOR_EACH; + } + END_FOR_EACH; if (count == 0) header.error = htonl(ERROR_MISSING_ARGUMENT); } @@ -723,11 +724,12 @@ void dnbd3_ipc_send(int cmd) wname = MAX(wname, xmlStrlen(vid)); wrid = MAX(wrid, xmlStrlen(rid)); // Too lazy to free vars, client will exit anyways - } END_FOR_EACH; + } + END_FOR_EACH; char format[100]; snprintf(format, 100, - "%%-%ds %%-%ds %%%ds %%s\n", watime, wname, wrid); + "%%-%ds %%-%ds %%%ds %%s\n", watime, wname, wrid); // Print images printf("Exported images\n"); @@ -745,7 +747,8 @@ void dnbd3_ipc_send(int cmd) xmlChar *file = xmlGetNoNsProp(cur, BAD_CAST "file"); printf(format, atime, vid, rid, file); // Too lazy to free vars, client will exit anyways - } END_FOR_EACH; + } + END_FOR_EACH; char_repeat_br('=', term_width); printf("\nNumber of images: %d\n\n", count); @@ -762,7 +765,8 @@ void dnbd3_ipc_send(int cmd) xmlChar *file = xmlGetNoNsProp(cur, BAD_CAST "file"); printf("%-40s %s\n", ip, file); // Too lazy to free vars, client will exit anyways - } END_FOR_EACH; + } + END_FOR_EACH; char_repeat_br('=', term_width); printf("\nNumber clients: %d\n\n", count); @@ -796,7 +800,8 @@ void dnbd3_ipc_send(int cmd) putchar('\n'); } // Too lazy to free vars, client will exit anyways - } END_FOR_EACH; + } + END_FOR_EACH; char_repeat_br('=', term_width); printf("\nNumber servers: %d\n\n", count); @@ -831,7 +836,7 @@ static int is_password_correct(xmlDocPtr doc) xmlChar *pass = getTextFromPath(doc, "/data/password"); if (pass == NULL) return 0; - if (strcmp((char*)pass, _ipc_password) == 0) + if (strcmp((char *)pass, _ipc_password) == 0) { xmlFree(pass); return 1; @@ -842,8 +847,8 @@ static int is_password_correct(xmlDocPtr doc) static int get_terminal_width() { - struct winsize w; - if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) < 0) - return 80; - return w.ws_col; + struct winsize w; + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) < 0) + return 80; + return w.ws_col; } diff --git a/src/server/ipc.h b/src/server/ipc.h index d4ec7db..36d1f60 100644 --- a/src/server/ipc.h +++ b/src/server/ipc.h @@ -27,7 +27,7 @@ #define IPC_ADDIMG 3 #define IPC_DELIMG 4 -void* dnbd3_ipc_mainloop(); +void *dnbd3_ipc_mainloop(); void dnbd3_ipc_shutdown(); @@ -38,9 +38,9 @@ void dnbd3_ipc_send(int cmd); typedef struct { uint32_t handle;// 4byte - uint32_t cmd; // 4byte - uint32_t size; // 4byte - uint32_t error; // 4byte + uint32_t cmd; // 4byte + uint32_t size; // 4byte + uint32_t error; // 4byte } dnbd3_ipc_t; #pragma pack(0) diff --git a/src/server/job.c b/src/server/job.c index b50a7f3..1f10cb6 100644 --- a/src/server/job.c +++ b/src/server/job.c @@ -32,12 +32,12 @@ static int num_devices = 0; static char keep_running = TRUE; // Private functions -static char* get_free_device(); +static char *get_free_device(); static void query_servers(); // -void* dnbd3_job_thread(void *data) +void *dnbd3_job_thread(void *data) { int i, j; // Determine number of available dnbd3 devices, which are needed for proxy mode @@ -74,18 +74,18 @@ void* dnbd3_job_thread(void *data) const time_t starttime = time(NULL); // // TODO: Update image atime - // Call image deletion function if last call is more than 5 minutes ago - if (starttime < next_delete_invocation) - { - next_delete_invocation = starttime + 300; - dnbd3_exec_delete(TRUE); - } + // Call image deletion function if last call is more than 5 minutes ago + if (starttime < next_delete_invocation) + { + next_delete_invocation = starttime + 300; + dnbd3_exec_delete(TRUE); + } // TODO: Replicate proxied images (limited bandwidth) // Query other servers for new images/status/... - query_servers(); + query_servers(); // TODO: Switch server of dnbd device based on more sophisticated inputs than just rtt - // Calc sleep timeout for next iteration - sleep(30 - (time(NULL) - starttime)); // Sleep 30 seconds, but account for the time it took to execute the loop + // Calc sleep timeout for next iteration + sleep(30 - (time(NULL) - starttime)); // Sleep 30 seconds, but account for the time it took to execute the loop } // free(devices); @@ -114,7 +114,7 @@ static void query_servers() * Get full name of an available dnbd3 device, eg. /dev/dnbd4 * Returned buffer is owned by this module, do not modify or free! */ -static char* get_free_device() +static char *get_free_device() { if (devices == NULL) return NULL; diff --git a/src/server/job.h b/src/server/job.h index 87be5d5..d8bb090 100644 --- a/src/server/job.h +++ b/src/server/job.h @@ -1,6 +1,6 @@ #ifndef JOB_H_ #define JOB_H_ -void* dnbd3_job_thread(void *data); +void *dnbd3_job_thread(void *data); #endif diff --git a/src/server/memlog.c b/src/server/memlog.c index 9809e64..6d4ec09 100644 --- a/src/server/memlog.c +++ b/src/server/memlog.c @@ -58,11 +58,11 @@ void memlogf(const char *fmt, ...) va_list ap; int ret; time_t rawtime; - struct tm * timeinfo; + struct tm *timeinfo; time(&rawtime); timeinfo = localtime(&rawtime); pthread_spin_lock(&logLock); - LogLine * const line = (LogLine *)&(logBuffer[bufferPos % LINE_COUNT]); + LogLine *const line = (LogLine *)&(logBuffer[bufferPos % LINE_COUNT]); const size_t offset = strftime(line->text, LINE_LEN, "[%d.%m. %H:%M:%S] ", timeinfo); if (offset == 0) *line->text = '\0'; va_start(ap, fmt); @@ -79,7 +79,7 @@ void memlogf(const char *fmt, ...) puts(line->text); } -char * fetchlog(int maxlines) +char *fetchlog(int maxlines) { if (!logBuffer) return NULL; if (maxlines <= 0 || maxlines > LINE_COUNT) maxlines = LINE_COUNT; @@ -88,8 +88,10 @@ char * fetchlog(int maxlines) //printf("Outputting log from %d to %d\n", start, bufferPos); pthread_spin_lock(&logLock); // Determine required buffer space for all log lines - for (i = start; i < bufferPos; ++i) { - if (logBuffer[i % LINE_COUNT].len > 0) { + for (i = start; i < bufferPos; ++i) + { + if (logBuffer[i % LINE_COUNT].len > 0) + { len += logBuffer[i % LINE_COUNT].len + 1; } } @@ -99,9 +101,11 @@ char * fetchlog(int maxlines) if (retval == NULL) goto endFunction; // Concatenate all log lines, delimit using '\n' char *pos = retval; - for (i = start; i < bufferPos; ++i) { - LogLine * const line = (LogLine *)&(logBuffer[i % LINE_COUNT]); - if (line->len > 0) { + for (i = start; i < bufferPos; ++i) + { + LogLine *const line = (LogLine *)&(logBuffer[i % LINE_COUNT]); + if (line->len > 0) + { memcpy(pos, (char *)line->text, line->len); pos += line->len; *pos++ = '\n'; diff --git a/src/server/memlog.h b/src/server/memlog.h index 24e3880..38c4349 100644 --- a/src/server/memlog.h +++ b/src/server/memlog.h @@ -34,6 +34,6 @@ void memlogf(char *text, ...); * Returns NULL on error * maxlines - Limit number of lines returned, 0 = everything */ -char * fetchlog(int maxlines); +char *fetchlog(int maxlines); #endif /* MEMLOG_H_ */ diff --git a/src/server/net.c b/src/server/net.c index bcbf056..afb7077 100644 --- a/src/server/net.c +++ b/src/server/net.c @@ -43,29 +43,29 @@ static inline char recv_request_header(int sock, dnbd3_request_t *request) { int ret; // Read request header from socket - if ((ret = recv(sock, request, sizeof(*request), MSG_WAITALL)) != sizeof(*request)) - { - if (ret == 0) return 0; - printf("[DEBUG] Error receiving request: Could not read message header (%d/%d)\n", ret, (int)sizeof(*request)); - return 0; - } - // Make sure all bytes are in the right order (endianness) - fixup_request(*request); - if (request->magic != dnbd3_packet_magic) - { - printf("[DEBUG] Magic in client request incorrect (cmd: %d, len: %d)\n", (int)request->cmd, (int)request->size); - return 0; - } - // Payload sanity check - if (request->cmd != CMD_GET_BLOCK && request->size > MAX_PAYLOAD) - { - memlogf("[WARNING] Client tries to send a packet of type %d with %d bytes payload. Dropping client.", (int)request->cmd, (int)request->size); - return 0; - } + if ((ret = recv(sock, request, sizeof(*request), MSG_WAITALL)) != sizeof(*request)) + { + if (ret == 0) return 0; + printf("[DEBUG] Error receiving request: Could not read message header (%d/%d)\n", ret, (int)sizeof(*request)); + return 0; + } + // Make sure all bytes are in the right order (endianness) + fixup_request(*request); + if (request->magic != dnbd3_packet_magic) + { + printf("[DEBUG] Magic in client request incorrect (cmd: %d, len: %d)\n", (int)request->cmd, (int)request->size); + return 0; + } + // Payload sanity check + if (request->cmd != CMD_GET_BLOCK && request->size > MAX_PAYLOAD) + { + memlogf("[WARNING] Client tries to send a packet of type %d with %d bytes payload. Dropping client.", (int)request->cmd, (int)request->size); + return 0; + } #ifdef _DEBUG - if (_fake_delay) usleep(_fake_delay); + if (_fake_delay) usleep(_fake_delay); #endif - return 1; + return 1; } static inline char recv_request_payload(int sock, uint32_t size, serialized_buffer_t *payload) @@ -120,44 +120,44 @@ static inline char send_reply(int sock, dnbd3_reply_t *reply, void *payload) void *dnbd3_handle_query(void *dnbd3_client) { - dnbd3_client_t *client = (dnbd3_client_t *) (uintptr_t) dnbd3_client; - dnbd3_request_t request; - dnbd3_reply_t reply; - - dnbd3_image_t *image = NULL; - int image_file = -1, image_cache = -1; - - int i, num; - - uint64_t map_y; - char map_x, bit_mask; - serialized_buffer_t payload; - char *image_name; - uint16_t rid, client_version; - - uint64_t todo_size = 0; - uint64_t todo_offset = 0; - uint64_t cur_offset = 0; - uint64_t last_offset = 0; - - dnbd3_server_entry_t server_list[NUMBER_SERVERS]; - - int dirty = 0; - - reply.magic = dnbd3_packet_magic; - - // Receive first packet. This must be CMD_GET_SIZE by protocol specification - if (recv_request_header(client->sock, &request)) - { - if (request.cmd != CMD_GET_SIZE) - { - printf("[DEBUG] Client sent invalid handshake (%d). Dropping Client\n", (int)request.cmd); - } - else - { - if (recv_request_payload(client->sock, request.size, &payload)) - { - client_version = serializer_get_uint16(&payload); + dnbd3_client_t *client = (dnbd3_client_t *) (uintptr_t) dnbd3_client; + dnbd3_request_t request; + dnbd3_reply_t reply; + + dnbd3_image_t *image = NULL; + int image_file = -1, image_cache = -1; + + int i, num; + + uint64_t map_y; + char map_x, bit_mask; + serialized_buffer_t payload; + char *image_name; + uint16_t rid, client_version; + + uint64_t todo_size = 0; + uint64_t todo_offset = 0; + uint64_t cur_offset = 0; + uint64_t last_offset = 0; + + dnbd3_server_entry_t server_list[NUMBER_SERVERS]; + + int dirty = 0; + + reply.magic = dnbd3_packet_magic; + + // Receive first packet. This must be CMD_GET_SIZE by protocol specification + if (recv_request_header(client->sock, &request)) + { + if (request.cmd != CMD_GET_SIZE) + { + printf("[DEBUG] Client sent invalid handshake (%d). Dropping Client\n", (int)request.cmd); + } + else + { + if (recv_request_payload(client->sock, request.size, &payload)) + { + client_version = serializer_get_uint16(&payload); image_name = serializer_get_string(&payload); rid = serializer_get_uint16(&payload); client->is_server = serializer_get_uint8(&payload); @@ -182,7 +182,7 @@ void *dnbd3_handle_query(void *dnbd3_client) printf("[DEBUG] Client requested non-existent image '%s' (rid:%d)\n", image_name, (int)rid); } else if ((image->delete_soft != 0 && image->delete_soft < now) - || (image->delete_hard != 0 && image->delete_hard < now)) + || (image->delete_hard != 0 && image->delete_hard < now)) { printf("[DEBUG] Client requested end-of-life image '%s' (rid:%d)\n", image_name, (int)rid); } @@ -220,221 +220,224 @@ void *dnbd3_handle_query(void *dnbd3_client) pthread_spin_unlock(&_spinlock); } } - } + } } - if (image) while (recv_request_header(client->sock, &request)) - { - switch (request.cmd) - { - - case CMD_GET_BLOCK: - if (request.offset >= image->filesize) - { // Sanity check - memlogf("[WARNING] Client requested non-existent block"); - reply.size = 0; - reply.cmd = CMD_ERROR; - send_reply(client->sock, &reply, NULL); - break; - } - if (request.offset + request.size > image->filesize) - { // Sanity check - memlogf("[WARNING] Client requested data block that extends beyond image size"); - reply.size = 0; - reply.cmd = CMD_ERROR; - send_reply(client->sock, &reply, NULL); - break; - } - if (request.size > image->filesize) - { // Sanity check - memlogf("[WARNING] Client requested data block that is bigger than the image size"); - reply.size = 0; - reply.cmd = CMD_ERROR; - send_reply(client->sock, &reply, NULL); - break; - } - - reply.cmd = CMD_GET_BLOCK; - reply.size = request.size; - reply.handle = request.handle; - - fixup_reply(reply); - if (send(client->sock, &reply, sizeof(dnbd3_reply_t), MSG_MORE) != sizeof(dnbd3_reply_t)) + if (image) while (recv_request_header(client->sock, &request)) + { + switch (request.cmd) { - printf("[DEBUG] Sending CMD_GET_BLOCK header failed\n"); - return 0; + + case CMD_GET_BLOCK: + if (request.offset >= image->filesize) + { + // Sanity check + memlogf("[WARNING] Client requested non-existent block"); + reply.size = 0; + reply.cmd = CMD_ERROR; + send_reply(client->sock, &reply, NULL); + break; + } + if (request.offset + request.size > image->filesize) + { + // Sanity check + memlogf("[WARNING] Client requested data block that extends beyond image size"); + reply.size = 0; + reply.cmd = CMD_ERROR; + send_reply(client->sock, &reply, NULL); + break; + } + if (request.size > image->filesize) + { + // Sanity check + memlogf("[WARNING] Client requested data block that is bigger than the image size"); + reply.size = 0; + reply.cmd = CMD_ERROR; + send_reply(client->sock, &reply, NULL); + break; + } + + reply.cmd = CMD_GET_BLOCK; + reply.size = request.size; + reply.handle = request.handle; + + fixup_reply(reply); + if (send(client->sock, &reply, sizeof(dnbd3_reply_t), MSG_MORE) != sizeof(dnbd3_reply_t)) + { + printf("[DEBUG] Sending CMD_GET_BLOCK header failed\n"); + return 0; + } + + if (request.size == 0) // Request for 0 bytes, done after sending header + break; + + // caching is off + if (image_cache == -1) + { + if (sendfile(client->sock, image_file, (off_t *)&request.offset, request.size) != request.size) + { + printf("[ERROR] sendfile failed (image to net)\n"); + close(client->sock); + client->sock = -1; + } + break; + } + + // caching is on + dirty = 0; + todo_size = 0; + todo_offset = request.offset; + cur_offset = request.offset; + last_offset = request.offset + request.size; + + // first make sure the whole requested part is in the local cache file + while(cur_offset < last_offset) + { + map_y = cur_offset >> 15; // div 32768 + map_x = (cur_offset >> 12) & 7; // (X div 4096) mod 8 + bit_mask = 0b00000001 << (map_x); + + cur_offset += 4096; + + if ((image->cache_map[map_y] & bit_mask) != 0) // cache hit + { + if (todo_size != 0) // fetch missing chunks + { + lseek(image_cache, todo_offset, SEEK_SET); + if (sendfile(image_cache, image_file, (off_t *) &todo_offset, todo_size) != todo_size) + { + printf("[ERROR] sendfile failed (copy to cache 1)\n"); + close(client->sock); + client->sock = -1; + // Reset these so we don't update the cache map with false information + dirty = 0; + todo_size = 0; + break; + } + todo_size = 0; + dirty = 1; + } + todo_offset = cur_offset; + } + else + { + todo_size += 4096; + } + } + + // whole request was missing + if (todo_size != 0) + { + lseek(image_cache, todo_offset, SEEK_SET); + if (sendfile(image_cache, image_file, (off_t *) &todo_offset, todo_size) != todo_size) + { + printf("[ERROR] sendfile failed (copy to cache 2)\n"); + close(client->sock); + client->sock = -1; + break; + } + dirty = 1; + } + + if (dirty) // cache map needs to be updated as something was missing locally + { + // set 1 in cache map for whole request + cur_offset = request.offset; + while(cur_offset < last_offset) + { + map_y = cur_offset >> 15; + map_x = (cur_offset >> 12) & 7; // mod 8 + bit_mask = 0b00000001 << (map_x); + image->cache_map[map_y] |= bit_mask; + cur_offset += 4096; + } + } + + // send data to client + if (sendfile(client->sock, image_cache, (off_t *) &request.offset, request.size) != request.size) + { + memlogf("[ERROR] sendfile failed (cache to net)\n"); + close(client->sock); + client->sock = -1; + } + break; + + + case CMD_GET_SERVERS: + client->is_server = FALSE; // Only clients request list of servers + // Build list of known working alt servers + num = 0; + for (i = 0; i < NUMBER_SERVERS; i++) + { + if (image->servers[i].hostaddrtype == 0 || image->servers[i].failures > 200) continue; + memcpy(server_list + num++, image->servers + i, sizeof(dnbd3_server_entry_t)); + } + reply.cmd = CMD_GET_SERVERS; + reply.size = num * sizeof(dnbd3_server_entry_t); + send_reply(client->sock, &reply, server_list); + break; + + case CMD_KEEPALIVE: + reply.cmd = CMD_KEEPALIVE; + reply.size = 0; + send_reply(client->sock, &reply, NULL); + break; + + case CMD_SET_CLIENT_MODE: + client->is_server = FALSE; + break; + + default: + memlogf("ERROR: Unknown command\n"); + break; + } - if (request.size == 0) // Request for 0 bytes, done after sending header - break; - - // caching is off - if (image_cache == -1) - { - if (sendfile(client->sock, image_file, (off_t *)&request.offset, request.size) != request.size) - { - printf("[ERROR] sendfile failed (image to net)\n"); - close(client->sock); - client->sock = -1; - } - break; - } - - // caching is on - dirty = 0; - todo_size = 0; - todo_offset = request.offset; - cur_offset = request.offset; - last_offset = request.offset + request.size; - - // first make sure the whole requested part is in the local cache file - while(cur_offset < last_offset) - { - map_y = cur_offset >> 15; // div 32768 - map_x = (cur_offset >> 12) & 7; // (X div 4096) mod 8 - bit_mask = 0b00000001 << (map_x); - - cur_offset += 4096; - - if ((image->cache_map[map_y] & bit_mask) != 0) // cache hit - { - if (todo_size != 0) // fetch missing chunks - { - lseek(image_cache, todo_offset, SEEK_SET); - if (sendfile(image_cache, image_file, (off_t *) &todo_offset, todo_size) != todo_size) - { - printf("[ERROR] sendfile failed (copy to cache 1)\n"); - close(client->sock); - client->sock = -1; - // Reset these so we don't update the cache map with false information - dirty = 0; - todo_size = 0; - break; - } - todo_size = 0; - dirty = 1; - } - todo_offset = cur_offset; - } - else - { - todo_size += 4096; - } - } - - // whole request was missing - if (todo_size != 0) - { - lseek(image_cache, todo_offset, SEEK_SET); - if (sendfile(image_cache, image_file, (off_t *) &todo_offset, todo_size) != todo_size) - { - printf("[ERROR] sendfile failed (copy to cache 2)\n"); - close(client->sock); - client->sock = -1; - break; - } - dirty = 1; - } - - if (dirty) // cache map needs to be updated as something was missing locally - { - // set 1 in cache map for whole request - cur_offset = request.offset; - while(cur_offset < last_offset) - { - map_y = cur_offset >> 15; - map_x = (cur_offset >> 12) & 7; // mod 8 - bit_mask = 0b00000001 << (map_x); - image->cache_map[map_y] |= bit_mask; - cur_offset += 4096; - } - } - - // send data to client - if (sendfile(client->sock, image_cache, (off_t *) &request.offset, request.size) != request.size) - { - memlogf("[ERROR] sendfile failed (cache to net)\n"); - close(client->sock); - client->sock = -1; - } - break; - - - case CMD_GET_SERVERS: - client->is_server = FALSE; // Only clients request list of servers - // Build list of known working alt servers - num = 0; - for (i = 0; i < NUMBER_SERVERS; i++) - { - if (image->servers[i].hostaddrtype == 0 || image->servers[i].failures > 200) continue; - memcpy(server_list + num++, image->servers + i, sizeof(dnbd3_server_entry_t)); - } - reply.cmd = CMD_GET_SERVERS; - reply.size = num * sizeof(dnbd3_server_entry_t); - send_reply(client->sock, &reply, server_list); - break; - - case CMD_KEEPALIVE: - reply.cmd = CMD_KEEPALIVE; - reply.size = 0; - send_reply(client->sock, &reply, NULL); - break; - - case CMD_SET_CLIENT_MODE: - client->is_server = FALSE; - break; - - default: - memlogf("ERROR: Unknown command\n"); - break; - - } - - } - pthread_spin_lock(&_spinlock); - _dnbd3_clients = g_slist_remove(_dnbd3_clients, client); - pthread_spin_unlock(&_spinlock); - if (client->sock != -1) - close(client->sock); - if (image_file != -1) close(image_file); - if (image_cache != -1) close(image_cache); - g_free(client); - pthread_exit((void *) 0); + } + pthread_spin_lock(&_spinlock); + _dnbd3_clients = g_slist_remove(_dnbd3_clients, client); + pthread_spin_unlock(&_spinlock); + if (client->sock != -1) + close(client->sock); + if (image_file != -1) close(image_file); + if (image_cache != -1) close(image_cache); + g_free(client); + pthread_exit((void *) 0); } int dnbd3_setup_socket() { - int sock; - struct sockaddr_in server; - - // Create socket - sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sock < 0) - { - memlogf("ERROR: Socket setup failure\n"); - return -1; - } - const int opt = 1; + int sock; + struct sockaddr_in server; + + // Create socket + sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock < 0) + { + memlogf("ERROR: Socket setup failure\n"); + return -1; + } + const int opt = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); - memset(&server, 0, sizeof(server)); - server.sin_family = AF_INET; // IPv4 - server.sin_addr.s_addr = htonl(INADDR_ANY); // Take all IPs - server.sin_port = htons(PORT); // set port number - - // Bind to socket - if (bind(sock, (struct sockaddr*) &server, sizeof(server)) < 0) - { - memlogf("ERROR: Bind failure\n"); - return -1; - } - - // Listen on socket - if (listen(sock, 100) == -1) - { - memlogf("ERROR: Listen failure\n"); - return -1; - } - - return sock; + memset(&server, 0, sizeof(server)); + server.sin_family = AF_INET; // IPv4 + server.sin_addr.s_addr = htonl(INADDR_ANY); // Take all IPs + server.sin_port = htons(PORT); // set port number + + // Bind to socket + if (bind(sock, (struct sockaddr *) &server, sizeof(server)) < 0) + { + memlogf("ERROR: Bind failure\n"); + return -1; + } + + // Listen on socket + if (listen(sock, 100) == -1) + { + memlogf("ERROR: Listen failure\n"); + return -1; + } + + return sock; } diff --git a/src/server/server.c b/src/server/server.c index feee30b..9fc5383 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -49,225 +49,226 @@ char *_ipc_password = NULL; GSList *_dnbd3_images = NULL; // of dnbd3_image_t GSList *_trusted_servers = NULL; -void dnbd3_print_help(char* argv_0) +void dnbd3_print_help(char *argv_0) { - printf("Usage: %s [OPTIONS]...\n", argv_0); - printf("Start the DNBD3 server\n"); - printf("-f or --file Configuration file (default /etc/dnbd3-server.conf)\n"); + printf("Usage: %s [OPTIONS]...\n", argv_0); + printf("Start the DNBD3 server\n"); + printf("-f or --file Configuration file (default /etc/dnbd3-server.conf)\n"); #ifdef _DEBUG - printf("-d or --delay Add a fake network delay of X µs\n"); + printf("-d or --delay Add a fake network delay of X µs\n"); #endif - printf("-n or --nodaemon Start server in foreground\n"); - printf("-r or --reload Reload configuration file\n"); - printf("-s or --stop Stop running dnbd3-server\n"); - printf("-i or --info Print connected clients and used images\n"); - printf("-H or --help Show this help text and quit\n"); - printf("-V or --version Show version and quit\n"); - exit(0); + printf("-n or --nodaemon Start server in foreground\n"); + printf("-r or --reload Reload configuration file\n"); + printf("-s or --stop Stop running dnbd3-server\n"); + printf("-i or --info Print connected clients and used images\n"); + printf("-H or --help Show this help text and quit\n"); + printf("-V or --version Show version and quit\n"); + exit(0); } void dnbd3_print_version() { - printf("Version: %s\n", VERSION_STRING); - exit(0); + printf("Version: %s\n", VERSION_STRING); + exit(0); } void dnbd3_cleanup() { - int fd; - memlogf("INFO: Cleanup...\n"); - - close(sock); - sock = -1; - - dnbd3_ipc_shutdown(); - - pthread_spin_lock(&_spinlock); - GSList *iterator = NULL; - for (iterator = _dnbd3_clients; iterator; iterator = iterator->next) - { - dnbd3_client_t *client = iterator->data; - shutdown(client->sock, SHUT_RDWR); - pthread_join(client->thread, NULL); - g_free(client); - } - g_slist_free(_dnbd3_clients); - - - for (iterator = _dnbd3_images; iterator; iterator = iterator->next) - { - // save cache maps to files - dnbd3_image_t *image = iterator->data; - if (image->cache_file) - { - char tmp[strlen(image->cache_file)+4]; - strcpy(tmp, image->cache_file); - strcat(tmp, ".map"); - fd = open(tmp, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); - - if (fd > 0) - write(fd, image->cache_map, ((image->filesize + (1 << 15) - 1) >> 15) * sizeof(char)); - - close(fd); - } - - free(image->cache_map); - free(image->config_group); - free(image->low_name); - free(image->file); - free(image->cache_file); - g_free(image); - } - g_slist_free(_dnbd3_images); - - pthread_spin_unlock(&_spinlock); + int fd; + memlogf("INFO: Cleanup...\n"); + + close(sock); + sock = -1; + + dnbd3_ipc_shutdown(); + + pthread_spin_lock(&_spinlock); + GSList *iterator = NULL; + for (iterator = _dnbd3_clients; iterator; iterator = iterator->next) + { + dnbd3_client_t *client = iterator->data; + shutdown(client->sock, SHUT_RDWR); + pthread_join(client->thread, NULL); + g_free(client); + } + g_slist_free(_dnbd3_clients); + + + for (iterator = _dnbd3_images; iterator; iterator = iterator->next) + { + // save cache maps to files + dnbd3_image_t *image = iterator->data; + if (image->cache_file) + { + char tmp[strlen(image->cache_file)+4]; + strcpy(tmp, image->cache_file); + strcat(tmp, ".map"); + fd = open(tmp, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); + + if (fd > 0) + write(fd, image->cache_map, ((image->filesize + (1 << 15) - 1) >> 15) * sizeof(char)); + + close(fd); + } + + free(image->cache_map); + free(image->config_group); + free(image->low_name); + free(image->file); + free(image->cache_file); + g_free(image); + } + g_slist_free(_dnbd3_images); + + pthread_spin_unlock(&_spinlock); #ifndef IPC_TCP - unlink(UNIX_SOCKET); + unlink(UNIX_SOCKET); #endif - exit(EXIT_SUCCESS); + exit(EXIT_SUCCESS); } -int main(int argc, char* argv[]) +int main(int argc, char *argv[]) { - int demonize = 1; - int opt = 0; - int longIndex = 0; - static const char *optString = "f:d:nrsiHV?"; - static const struct option longOpts[] = - { - { "file", required_argument, NULL, 'f' }, - { "delay", required_argument, NULL, 'd' }, - { "nodaemon", no_argument, NULL, 'n' }, - { "reload", no_argument, NULL, 'r' }, - { "stop", no_argument, NULL, 's' }, - { "info", no_argument, NULL, 'i' }, - { "help", no_argument, NULL, 'H' }, - { "version", no_argument, NULL, 'V' } }; - - opt = getopt_long(argc, argv, optString, longOpts, &longIndex); - - while (opt != -1) - { - switch (opt) - { - case 'f': - _config_file_name = strdup(optarg); - break; - case 'd': + int demonize = 1; + int opt = 0; + int longIndex = 0; + static const char *optString = "f:d:nrsiHV?"; + static const struct option longOpts[] = + { + { "file", required_argument, NULL, 'f' }, + { "delay", required_argument, NULL, 'd' }, + { "nodaemon", no_argument, NULL, 'n' }, + { "reload", no_argument, NULL, 'r' }, + { "stop", no_argument, NULL, 's' }, + { "info", no_argument, NULL, 'i' }, + { "help", no_argument, NULL, 'H' }, + { "version", no_argument, NULL, 'V' } + }; + + opt = getopt_long(argc, argv, optString, longOpts, &longIndex); + + while (opt != -1) + { + switch (opt) + { + case 'f': + _config_file_name = strdup(optarg); + break; + case 'd': #ifdef _DEBUG - _fake_delay = atoi(optarg); - break; + _fake_delay = atoi(optarg); + break; #else - printf("This option is only available in debug builds.\n\n"); - return EXIT_FAILURE; + printf("This option is only available in debug builds.\n\n"); + return EXIT_FAILURE; #endif - case 'n': - demonize = 0; - break; - case 'r': - printf("INFO: Reloading configuration file...\n\n"); - dnbd3_ipc_send(IPC_RELOAD); - return EXIT_SUCCESS; - case 's': - printf("INFO: Stopping running server...\n\n"); - dnbd3_ipc_send(IPC_EXIT); - return EXIT_SUCCESS; - case 'i': - printf("INFO: Requesting information...\n\n"); - dnbd3_ipc_send(IPC_INFO); - return EXIT_SUCCESS; - case 'H': - dnbd3_print_help(argv[0]); - break; - case 'V': - dnbd3_print_version(); - break; - case '?': - dnbd3_print_help(argv[0]); - break; - } - opt = getopt_long(argc, argv, optString, longOpts, &longIndex); - } - - if (demonize) - daemon(1, 0); - - pthread_spin_init(&_spinlock, PTHREAD_PROCESS_PRIVATE); - - initmemlog(); - memlogf("DNBD3 server starting.... Machine type: " ENDIAN_MODE); - - // load config file - dnbd3_load_config(); - - // setup signal handler - signal(SIGPIPE, dnbd3_handle_sigpipe); - signal(SIGTERM, dnbd3_handle_sigterm); - signal(SIGINT, dnbd3_handle_sigterm); - - // setup network - sock = dnbd3_setup_socket(); - if (sock < 0) - exit(EXIT_FAILURE); - struct sockaddr_in client; - unsigned int len = sizeof(client); - int fd; - struct timeval timeout; - timeout.tv_sec = SOCKET_TIMEOUT_SERVER; - timeout.tv_usec = 0; - - // setup ipc - pthread_t thread_ipc; - pthread_create(&(thread_ipc), NULL, &dnbd3_ipc_mainloop, NULL); - - memlogf("[INFO] Server is ready..."); - - // main loop - while (1) - { - fd = accept(sock, (struct sockaddr*) &client, &len); - if (fd < 0) - { - memlogf("[ERROR] Accept failure"); - continue; - } - //memlogf("INFO: Client %s connected\n", inet_ntoa(client.sin_addr)); - - setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof(timeout)); - setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, sizeof(timeout)); - - dnbd3_client_t *dnbd3_client = g_new0(dnbd3_client_t, 1); - if (dnbd3_client == NULL) - { - memlogf("[ERROR] Could not alloc dnbd3_client_t for new client."); - close(fd); - continue; - } - // TODO: Extend this if you ever want to add IPv6 (something like:) - // dnbd3_client->addrtype = AF_INET6; - // memcpy(dnbd3_client->ipaddr, &(client.sin6_addr), 16); - dnbd3_client->addrtype = AF_INET; - memcpy(dnbd3_client->ipaddr, &(client.sin_addr), 4); - dnbd3_client->sock = fd; - dnbd3_client->image = NULL; - - // This has to be done before creating the thread, otherwise a race condition might occur when the new thread dies faster than this thread adds the client to the list after creating the thread - pthread_spin_lock(&_spinlock); - _dnbd3_clients = g_slist_prepend(_dnbd3_clients, dnbd3_client); - pthread_spin_unlock(&_spinlock); - - if (0 != pthread_create(&(dnbd3_client->thread), NULL, dnbd3_handle_query, (void *) (uintptr_t) dnbd3_client)) - { - memlogf("[ERROR] Could not start thread for new client."); - pthread_spin_lock(&_spinlock); - _dnbd3_clients = g_slist_remove(_dnbd3_clients, dnbd3_client); - pthread_spin_unlock(&_spinlock); - g_free(dnbd3_client); - close(fd); - continue; - } - pthread_detach(dnbd3_client->thread); - } - - dnbd3_cleanup(); + case 'n': + demonize = 0; + break; + case 'r': + printf("INFO: Reloading configuration file...\n\n"); + dnbd3_ipc_send(IPC_RELOAD); + return EXIT_SUCCESS; + case 's': + printf("INFO: Stopping running server...\n\n"); + dnbd3_ipc_send(IPC_EXIT); + return EXIT_SUCCESS; + case 'i': + printf("INFO: Requesting information...\n\n"); + dnbd3_ipc_send(IPC_INFO); + return EXIT_SUCCESS; + case 'H': + dnbd3_print_help(argv[0]); + break; + case 'V': + dnbd3_print_version(); + break; + case '?': + dnbd3_print_help(argv[0]); + break; + } + opt = getopt_long(argc, argv, optString, longOpts, &longIndex); + } + + if (demonize) + daemon(1, 0); + + pthread_spin_init(&_spinlock, PTHREAD_PROCESS_PRIVATE); + + initmemlog(); + memlogf("DNBD3 server starting.... Machine type: " ENDIAN_MODE); + + // load config file + dnbd3_load_config(); + + // setup signal handler + signal(SIGPIPE, dnbd3_handle_sigpipe); + signal(SIGTERM, dnbd3_handle_sigterm); + signal(SIGINT, dnbd3_handle_sigterm); + + // setup network + sock = dnbd3_setup_socket(); + if (sock < 0) + exit(EXIT_FAILURE); + struct sockaddr_in client; + unsigned int len = sizeof(client); + int fd; + struct timeval timeout; + timeout.tv_sec = SOCKET_TIMEOUT_SERVER; + timeout.tv_usec = 0; + + // setup ipc + pthread_t thread_ipc; + pthread_create(&(thread_ipc), NULL, &dnbd3_ipc_mainloop, NULL); + + memlogf("[INFO] Server is ready..."); + + // main loop + while (1) + { + fd = accept(sock, (struct sockaddr *) &client, &len); + if (fd < 0) + { + memlogf("[ERROR] Accept failure"); + continue; + } + //memlogf("INFO: Client %s connected\n", inet_ntoa(client.sin_addr)); + + setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof(timeout)); + setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, sizeof(timeout)); + + dnbd3_client_t *dnbd3_client = g_new0(dnbd3_client_t, 1); + if (dnbd3_client == NULL) + { + memlogf("[ERROR] Could not alloc dnbd3_client_t for new client."); + close(fd); + continue; + } + // TODO: Extend this if you ever want to add IPv6 (something like:) + // dnbd3_client->addrtype = AF_INET6; + // memcpy(dnbd3_client->ipaddr, &(client.sin6_addr), 16); + dnbd3_client->addrtype = AF_INET; + memcpy(dnbd3_client->ipaddr, &(client.sin_addr), 4); + dnbd3_client->sock = fd; + dnbd3_client->image = NULL; + + // This has to be done before creating the thread, otherwise a race condition might occur when the new thread dies faster than this thread adds the client to the list after creating the thread + pthread_spin_lock(&_spinlock); + _dnbd3_clients = g_slist_prepend(_dnbd3_clients, dnbd3_client); + pthread_spin_unlock(&_spinlock); + + if (0 != pthread_create(&(dnbd3_client->thread), NULL, dnbd3_handle_query, (void *) (uintptr_t) dnbd3_client)) + { + memlogf("[ERROR] Could not start thread for new client."); + pthread_spin_lock(&_spinlock); + _dnbd3_clients = g_slist_remove(_dnbd3_clients, dnbd3_client); + pthread_spin_unlock(&_spinlock); + g_free(dnbd3_client); + close(fd); + continue; + } + pthread_detach(dnbd3_client->thread); + } + + dnbd3_cleanup(); } diff --git a/src/server/server.h b/src/server/server.h index 1e17048..c608066 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -41,27 +41,27 @@ typedef struct { char *config_group; // exact name of group in config file that represents this image char *low_name; // full (global) name of image, lowercased for comparison, eg. "uni-freiburg/rz/ubuntu-12.04" - int rid; // revision of provided image - char *file; // path to image file or device - uint64_t filesize; // size of image - dnbd3_server_entry_t servers[NUMBER_SERVERS]; // known alt servers that also offer that image - time_t atime; // last access time - uint8_t *cache_map; // cache map telling which parts are locally cached - char *cache_file; // path to local cache of image (in case the image is read from a dnbd3 device) - char working; // whether this image is considered working. local images are "working" if the local file exists, proxied images have to have at least one working upstream server or a complete local cache file - time_t delete_soft; // unixtime telling when this image should be deleted. if there are still clients using this image it weill be kept, but new clients requesting the image will be rejected. 0 = never - time_t delete_hard; // unixtime telling when this image should be deleted, no matter if there are still clients connected. 0 = never - uint8_t relayed; // TRUE if relayed from other server (needs dnbd3 client module loaded) + int rid; // revision of provided image + char *file; // path to image file or device + uint64_t filesize; // size of image + dnbd3_server_entry_t servers[NUMBER_SERVERS]; // known alt servers that also offer that image + time_t atime; // last access time + uint8_t *cache_map; // cache map telling which parts are locally cached + char *cache_file; // path to local cache of image (in case the image is read from a dnbd3 device) + char working; // whether this image is considered working. local images are "working" if the local file exists, proxied images have to have at least one working upstream server or a complete local cache file + time_t delete_soft; // unixtime telling when this image should be deleted. if there are still clients using this image it weill be kept, but new clients requesting the image will be rejected. 0 = never + time_t delete_hard; // unixtime telling when this image should be deleted, no matter if there are still clients connected. 0 = never + uint8_t relayed; // TRUE if relayed from other server (needs dnbd3 client module loaded) } dnbd3_image_t; typedef struct { - int sock; - uint8_t ipaddr[16]; - uint8_t addrtype; // ip version (AF_INET or AF_INET6) - uint8_t is_server; // TRUE if a server in proxy mode, FALSE if real client - pthread_t thread; - dnbd3_image_t *image; + int sock; + uint8_t ipaddr[16]; + uint8_t addrtype; // ip version (AF_INET or AF_INET6) + uint8_t is_server; // TRUE if a server in proxy mode, FALSE if real client + pthread_t thread; + dnbd3_image_t *image; } dnbd3_client_t; typedef struct diff --git a/src/server/utils.c b/src/server/utils.c index dc3d6c4..ad40322 100644 --- a/src/server/utils.c +++ b/src/server/utils.c @@ -32,13 +32,13 @@ #include "memlog.h" // Keep parsed config file in memory so it doesn't need to be parsed again every time it's modified -static GKeyFile* _config_handle = NULL; +static GKeyFile *_config_handle = NULL; static char parse_address(char *string, uint8_t *af, uint8_t *addr, uint16_t *port); static char is_valid_namespace(char *namespace); static char is_valid_imagename(char *namespace); static void strtolower(char *string); -static dnbd3_image_t* prepare_image(char *image_name, int rid, char *image_file, char *cache_file, gchar **servers, gsize num_servers); +static dnbd3_image_t *prepare_image(char *image_name, int rid, char *image_file, char *cache_file, gchar **servers, gsize num_servers); static int save_config(); //static char* get_local_image_name(char *global_name); @@ -120,8 +120,8 @@ static char is_valid_namespace(char *namespace) while (*namespace) { if (*namespace != '/' && *namespace != '-' && (*namespace < 'a' || *namespace > 'z') - && (*namespace < 'A' || *namespace > 'Z') - && (*namespace < '0' || *namespace > '9')) + && (*namespace < 'A' || *namespace > 'Z') + && (*namespace < '0' || *namespace > '9')) return 0; ++namespace; } @@ -135,11 +135,12 @@ static char is_valid_imagename(char *namespace) if (*namespace == '\0' || *namespace == ' ') return 0; // Invalid: Length = 0 or starting with a space while (*namespace) - { // Check for invalid chars + { + // Check for invalid chars if (*namespace != '.' && *namespace != '-' && *namespace != ' ' - && *namespace != '(' && *namespace != ')' - && (*namespace < 'a' || *namespace > 'z') && (*namespace < 'A' || *namespace > 'Z') - && (*namespace < '0' || *namespace > '9')) + && *namespace != '(' && *namespace != ')' + && (*namespace < 'a' || *namespace > 'z') && (*namespace < 'A' || *namespace > 'Z') + && (*namespace < '0' || *namespace > '9')) return 0; ++namespace; } @@ -148,11 +149,11 @@ static char is_valid_imagename(char *namespace) return 1; } -static inline int is_same_server(const dnbd3_trusted_server_t * const a, const dnbd3_trusted_server_t * const b) +static inline int is_same_server(const dnbd3_trusted_server_t *const a, const dnbd3_trusted_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 void strtolower(char *string) @@ -220,6 +221,7 @@ void dnbd3_load_config() if (strcmp(keys[j], "address") == 0) continue; char *flags = g_key_file_get_string(_config_handle, groups[i], keys[j], NULL); + g_key_file_remove_key(_config_handle, groups[i], keys[j], NULL); dnbd3_add_trusted_namespace(server, keys[j], flags); g_free(flags); } @@ -290,19 +292,19 @@ int dnbd3_add_image(dnbd3_image_t *image) } // Adding image was successful, write config file - g_key_file_set_integer(_config_handle, image->config_group, "rid", image->rid); - g_key_file_set_string(_config_handle, image->config_group, "file", image->file); - //g_key_file_set_string(_config_handle, image->name, "servers", image->serverss); // TODO: Save servers as string - g_key_file_set_string(_config_handle, image->config_group, "cache", image->cache_file); - - pthread_spin_unlock(&_spinlock); - - const int ret = save_config(); - if (ret == ERROR_OK) - memlogf("[INFO] Added new image '%s' (rid %d)", newimage->config_group, newimage->rid); - else - memlogf("[INFO] Added new image '%s' (rid %d), but config file could not be written (%s)", newimage->config_group, newimage->rid, _config_file_name); - return ret; + g_key_file_set_integer(_config_handle, image->config_group, "rid", image->rid); + g_key_file_set_string(_config_handle, image->config_group, "file", image->file); + //g_key_file_set_string(_config_handle, image->name, "servers", image->serverss); // TODO: Save servers as string + g_key_file_set_string(_config_handle, image->config_group, "cache", image->cache_file); + + pthread_spin_unlock(&_spinlock); + + const int ret = save_config(); + if (ret == ERROR_OK) + memlogf("[INFO] Added new image '%s' (rid %d)", newimage->config_group, newimage->rid); + else + memlogf("[INFO] Added new image '%s' (rid %d), but config file could not be written (%s)", newimage->config_group, newimage->rid, _config_file_name); + return ret; } int dnbd3_del_image(dnbd3_image_t *image) @@ -326,41 +328,41 @@ int dnbd3_del_image(dnbd3_image_t *image) dnbd3_exec_delete(FALSE); existing_image = NULL; - const int ret = save_config(); - if (ret == ERROR_OK) - memlogf("[INFO] Marked for deletion: '%s' (rid %d)", image->config_group, image->rid); - else - memlogf("[WARNING] Marked for deletion: '%s' (rid %d), but config file could not be written (%s)", image->config_group, image->rid, _config_file_name); - return ret; + const int ret = save_config(); + if (ret == ERROR_OK) + memlogf("[INFO] Marked for deletion: '%s' (rid %d)", image->config_group, image->rid); + else + memlogf("[WARNING] Marked for deletion: '%s' (rid %d), but config file could not be written (%s)", image->config_group, image->rid, _config_file_name); + return ret; } static int save_config() { pthread_spin_lock(&_spinlock); - char* data = (char*)g_key_file_to_data(_config_handle, NULL, NULL); - if (data == NULL) - { - pthread_spin_unlock(&_spinlock); - memlogf("[ERROR] g_key_file_to_data() failed"); - return ERROR_UNSPECIFIED_ERROR; - } - - FILE *f = fopen(_config_file_name, "w"); - if (f < 0) - { - pthread_spin_unlock(&_spinlock); - g_free(data); - return ERROR_CONFIG_FILE_PERMISSIONS; - } - fputs("# Do not edit this file while dnbd3-server is running\n", f); - fputs(data, f); - fclose(f); - pthread_spin_unlock(&_spinlock); - g_free(data); - return 0; + char *data = (char *)g_key_file_to_data(_config_handle, NULL, NULL); + if (data == NULL) + { + pthread_spin_unlock(&_spinlock); + memlogf("[ERROR] g_key_file_to_data() failed"); + return ERROR_UNSPECIFIED_ERROR; + } + + FILE *f = fopen(_config_file_name, "w"); + if (f < 0) + { + pthread_spin_unlock(&_spinlock); + g_free(data); + return ERROR_CONFIG_FILE_PERMISSIONS; + } + fputs("# Do not edit this file while dnbd3-server is running\n", f); + fputs(data, f); + fclose(f); + pthread_spin_unlock(&_spinlock); + g_free(data); + return 0; } -dnbd3_image_t* dnbd3_get_image(char *name_orig, int rid, const char do_lock) +dnbd3_image_t *dnbd3_get_image(char *name_orig, int rid, const char do_lock) { dnbd3_image_t *result = NULL, *image; GSList *iterator; @@ -450,7 +452,8 @@ static dnbd3_image_t *prepare_image(char *image_name, int rid, char *image_file, } if (strchr(image_name, '/') == NULL) - { // Local image, build global name + { + // Local image, build global name image->low_name = calloc(strlen(_local_namespace) + strlen(image_name) + 2, sizeof(char)); sprintf(image->low_name, "%s/%s", _local_namespace, image_name); } @@ -494,14 +497,14 @@ static dnbd3_image_t *prepare_image(char *image_name, int rid, char *image_file, if (size <= 0) { memlogf("[ERROR] File '%s' of image '%s' has size '%lld'. Image ignored.", - image->file, image_name, (long long)size); + image->file, image_name, (long long)size); goto error; } image->filesize = (uint64_t)size; if (image->filesize & 4095) { memlogf("[WARNING] Size of image '%s' is not a multiple of 4096. Last incomplete block will be ignored!", - image->file); + image->file); image->filesize &= ~(uint64_t)4095; } close(fd); @@ -513,7 +516,7 @@ static dnbd3_image_t *prepare_image(char *image_name, int rid, char *image_file, for (k = 0, j = 0; j < MIN(num_servers, NUMBER_SERVERS); ++j) { if (parse_address(servers[j], &(image->servers[k].hostaddrtype), image->servers[k].hostaddr, - &(image->servers[k].port))) + &(image->servers[k].port))) { ++k; continue; @@ -533,7 +536,8 @@ static dnbd3_image_t *prepare_image(char *image_name, int rid, char *image_file, close(fd); } if (image->filesize & 4095) - { // Cache files should always be truncated to 4kib boundaries already + { + // Cache files should always be truncated to 4kib boundaries already memlogf("[WARNING] Size of cache file '%s' is not a multiple of 4096. Something's fishy!", image->cache_file); image->filesize = 0; } @@ -649,7 +653,8 @@ void dnbd3_exec_delete(int save_if_changed) { const dnbd3_client_t *client = client_iterator->data; if (client->image == image) - { // Yep, still in use, keep it + { + // Yep, still in use, keep it delete_now = FALSE; break; } diff --git a/src/server/utils.h b/src/server/utils.h index 53dc076..e254cfd 100644 --- a/src/server/utils.h +++ b/src/server/utils.h @@ -47,7 +47,7 @@ int dnbd3_del_image(dnbd3_image_t *image); void dnbd3_exec_delete(int save_if_changed); -dnbd3_image_t* dnbd3_get_image(char *name, int rid, const char do_lock); +dnbd3_image_t *dnbd3_get_image(char *name, int rid, const char do_lock); dnbd3_trusted_server_t *dnbd3_get_trusted_server(char *address, char create_if_not_found); int dnbd3_add_trusted_namespace(dnbd3_trusted_server_t *server, char *namespace, char *flags); diff --git a/src/types.h b/src/types.h index 72449da..d41111a 100644 --- a/src/types.h +++ b/src/types.h @@ -63,14 +63,14 @@ static const uint16_t dnbd3_packet_magic = (0x73) | (0x72 << 8); typedef struct { uint16_t len; - uint8_t addrtype; - uint8_t addr[16]; // network representation - uint16_t port; // network representation - uint16_t imgnamelen; - char *imgname; - int rid; - int read_ahead_kb; - uint8_t is_server; // FALSE = automatic (real client), TRUE = manual control (proxy) + uint8_t addrtype; + uint8_t addr[16]; // network representation + uint16_t port; // network representation + uint16_t imgnamelen; + char *imgname; + int rid; + int read_ahead_kb; + uint8_t is_server; // FALSE = automatic (real client), TRUE = manual control (proxy) } dnbd3_ioctl_t; // network @@ -86,10 +86,10 @@ typedef struct typedef struct { uint16_t magic; // 2byte - uint16_t cmd; // 2byte - uint32_t size; // 4byte - uint64_t offset; // 8byte - uint64_t handle; // 8byte + uint16_t cmd; // 2byte + uint32_t size; // 4byte + uint64_t offset; // 8byte + uint64_t handle; // 8byte } dnbd3_request_t; #pragma pack(0) @@ -97,9 +97,9 @@ typedef struct typedef struct { uint16_t magic; // 2byte - uint16_t cmd; // 2byte - uint32_t size; // 4byte - uint64_t handle; // 8byte + uint16_t cmd; // 2byte + uint32_t size; // 4byte + uint64_t handle; // 8byte } dnbd3_reply_t; #pragma pack(0) -- cgit v1.2.3-55-g7522