diff options
Diffstat (limited to 'src/kernel/blk.c')
-rw-r--r-- | src/kernel/blk.c | 276 |
1 files changed, 156 insertions, 120 deletions
diff --git a/src/kernel/blk.c b/src/kernel/blk.c index 889b988..dde8dea 100644 --- a/src/kernel/blk.c +++ b/src/kernel/blk.c @@ -41,92 +41,7 @@ req->cmd_type == REQ_TYPE_SPECIAL #endif -int dnbd3_blk_add_device(dnbd3_device_t *dev, int minor) -{ - 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); - - 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->disconnecting = 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; - } - - 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; - } - - 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; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) - blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue); - blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, disk->queue); -#else - queue_flag_set_unlocked(QUEUE_FLAG_NONROT, disk->queue); -#endif -#define ONE_MEG (1048576) - blk_queue_max_segment_size(disk->queue, ONE_MEG); - blk_queue_max_segments(disk->queue, 0xffff); - blk_queue_max_hw_sectors(disk->queue, ONE_MEG / DNBD3_BLOCK_SIZE); - disk->queue->limits.max_sectors = 256; - dev->disk = disk; -#undef ONE_MEG - - 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; -} - -struct block_device_operations dnbd3_blk_ops = - { .owner = THIS_MODULE, .ioctl = dnbd3_blk_ioctl, }; - -int dnbd3_blk_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) +static int dnbd3_blk_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { int result = -100; dnbd3_device_t *dev = bdev->bd_disk->private_data; @@ -225,7 +140,9 @@ int dnbd3_blk_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, u dnbd3_blk_fail_all_requests(dev); result = dnbd3_net_disconnect(dev); dnbd3_blk_fail_all_requests(dev); + blk_mq_freeze_queue(dev->queue); set_capacity(dev->disk, 0); + blk_mq_unfreeze_queue(dev->queue); if (dev->imgname) { kfree(dev->imgname); @@ -275,48 +192,167 @@ cleanup_return: return result; } -/** - * dev->blk_lock and q->queue_lock are being held - * when this is called! - */ -void dnbd3_blk_request(struct request_queue *q) +static const struct block_device_operations dnbd3_blk_ops = { + .owner = THIS_MODULE, + .ioctl = dnbd3_blk_ioctl, +}; + +static blk_status_t dnbd3_queue_rq(struct blk_mq_hw_ctx *hctx, const struct blk_mq_queue_data *bd) { - struct request *req; - dnbd3_device_t *dev; + struct request *rq = bd->rq; + dnbd3_device_t *dev = rq->q->queuedata; + unsigned long irqflags; + + blk_mq_start_request(rq); - while ((req = blk_fetch_request(q)) != NULL) + if (dev->imgname == NULL) { - dev = req->rq_disk->private_data; + blk_mq_end_request(rq, BLK_STS_IOERR); + goto out; + } - if (dev->imgname == NULL) - { - __blk_end_request_all(req, -EIO); - continue; - } + if (!(dnbd3_req_fs(rq))) + { + blk_mq_end_request(rq, BLK_STS_IOERR); + goto out; + } - if (!(dnbd3_req_fs(req))) - { - __blk_end_request_all(req, 0); - continue; - } + if (PROBE_COUNT_TIMEOUT > 0 && dev->panic_count >= PROBE_COUNT_TIMEOUT) + { + blk_mq_end_request(rq, BLK_STS_TIMEOUT); + goto out; + } - if (PROBE_COUNT_TIMEOUT > 0 && dev->panic_count >= PROBE_COUNT_TIMEOUT) - { - __blk_end_request_all(req, -EIO); - continue; - } + if (!(dnbd3_req_read(rq))) + { + blk_mq_end_request(rq, BLK_STS_NOTSUPP); + goto out; + } - if (!(dnbd3_req_read(req))) - { - __blk_end_request_all(req, -EACCES); - continue; - } + spin_lock_irqsave(&dev->blk_lock, irqflags); + list_add_tail(&rq->queuelist, &dev->request_queue_send); + spin_unlock_irqrestore(&dev->blk_lock, irqflags); + wake_up(&dev->process_queue_send); + +out: + return BLK_STS_OK; +} + +static const struct blk_mq_ops dnbd3_mq_ops = { + .queue_rq = dnbd3_queue_rq, +}; + +int dnbd3_blk_add_device(dnbd3_device_t *dev, int minor) +{ + int ret; + + 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; + + 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->disconnecting = 0; + dev->panic = 0; + dev->panic_count = 0; + dev->reported_size = 0; + + // set up spin lock for request queues for send and receive + spin_lock_init(&dev->blk_lock); + + // set up tag_set for blk-mq + dev->tag_set.ops = &dnbd3_mq_ops; + dev->tag_set.nr_hw_queues = 1; + dev->tag_set.queue_depth = 128; + dev->tag_set.numa_node = NUMA_NO_NODE; + dev->tag_set.cmd_size = 0; + dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; + dev->tag_set.driver_data = dev; + + ret = blk_mq_alloc_tag_set(&dev->tag_set); + if (ret) + { + printk(KERN_ERR "ERROR: dnbd3 blk_mq_alloc_tag_set failed.\n"); + goto out; + } - 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); + // set up blk-mq + dev->queue = blk_mq_init_queue(&dev->tag_set); + if (IS_ERR(dev->queue)) { + ret = PTR_ERR(dev->queue); + goto out_cleanup_tags; } + dev->queue->queuedata = dev; + + blk_queue_logical_block_size(dev->queue, DNBD3_BLOCK_SIZE); + blk_queue_physical_block_size(dev->queue, DNBD3_BLOCK_SIZE); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) + blk_queue_flag_set(QUEUE_FLAG_NONROT, dev->queue); + blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, dev->queue); +#else + queue_flag_set_unlocked(QUEUE_FLAG_NONROT, dev->queue); +#endif +#define ONE_MEG (1048576) + blk_queue_max_segment_size(dev->queue, ONE_MEG); + blk_queue_max_segments(dev->queue, 0xffff); + blk_queue_max_hw_sectors(dev->queue, ONE_MEG / DNBD3_BLOCK_SIZE); + dev->queue->limits.max_sectors = 256; +#undef ONE_MEG + + // set up disk + if (!(dev->disk = alloc_disk(1))) + { + printk(KERN_ERR "ERROR: dnbd3 alloc_disk failed.\n"); + ret = -ENOMEM; + goto out_cleanup_queue; + } + + dev->disk->flags |= GENHD_FL_NO_PART_SCAN; + dev->disk->major = major; + dev->disk->first_minor = minor; + dev->disk->fops = &dnbd3_blk_ops; + dev->disk->private_data = dev; + dev->disk->queue = dev->queue; + sprintf(dev->disk->disk_name, "dnbd%d", minor); + set_capacity(dev->disk, 0); + set_disk_ro(dev->disk, 1); + add_disk(dev->disk); + + // set up sysfs + dnbd3_sysfs_init(dev); + + return 0; + +out_cleanup_queue: + blk_cleanup_queue(dev->queue); +out_cleanup_tags: + blk_mq_free_tag_set(&dev->tag_set); +out: + return ret; +} + +int dnbd3_blk_del_device(dnbd3_device_t *dev) +{ + dnbd3_sysfs_exit(dev); + dnbd3_net_disconnect(dev); + del_gendisk(dev->disk); + blk_cleanup_queue(dev->queue); + blk_mq_free_tag_set(&dev->tag_set); + put_disk(dev->disk); + return 0; } void dnbd3_blk_fail_all_requests(dnbd3_device_t *dev) @@ -371,7 +407,7 @@ void dnbd3_blk_fail_all_requests(dnbd3_device_t *dev) if (dnbd3_req_fs(blk_request)) { spin_lock_irqsave(&dev->blk_lock, flags); - __blk_end_request_all(blk_request, -EIO); + blk_mq_end_request(blk_request, BLK_STS_IOERR); spin_unlock_irqrestore(&dev->blk_lock, flags); } else if (dnbd3_req_special(blk_request)) |