aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorMing Lei <ming.lei@canonical.com>2015-08-16 22:31:48 -0400
committerJens Axboe <axboe@fb.com>2015-09-23 13:01:16 -0400
commite03a3d7a94e2485b6e2fa3fb630b9b3a30b65718 (patch)
treece0d022f49faefa5845da085c0dcd66ff72252f9 /drivers/block
parent5b5e20f421c0b6d437b3dec13e53674161998d56 (diff)
block: loop: use kthread_work
The following patch will use dio/aio to submit IO to backing file, then it needn't to schedule IO concurrently from work, so use kthread_work for decreasing context switch cost a lot. For non-AIO case, single thread has been used for long long time, and it was just converted to work in v4.0, which has caused performance regression for fedora live booting already. In discussion[1], even though submitting I/O via work concurrently can improve random read IO throughput, meantime it might hurt sequential read IO performance, so better to restore to single thread behaviour. For the following AIO support, it is better to use multi hw-queue with per-hwq kthread than current work approach suppose there is so high performance requirement for loop. [1] http://marc.info/?t=143082678400002&r=1&w=2 Signed-off-by: Ming Lei <ming.lei@canonical.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/loop.c79
-rw-r--r--drivers/block/loop.h10
2 files changed, 28 insertions, 61 deletions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index eee751032cad..1875aadb31b0 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -688,6 +688,23 @@ static void loop_config_discard(struct loop_device *lo)
688 queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); 688 queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
689} 689}
690 690
691static void loop_unprepare_queue(struct loop_device *lo)
692{
693 flush_kthread_worker(&lo->worker);
694 kthread_stop(lo->worker_task);
695}
696
697static int loop_prepare_queue(struct loop_device *lo)
698{
699 init_kthread_worker(&lo->worker);
700 lo->worker_task = kthread_run(kthread_worker_fn,
701 &lo->worker, "loop%d", lo->lo_number);
702 if (IS_ERR(lo->worker_task))
703 return -ENOMEM;
704 set_user_nice(lo->worker_task, MIN_NICE);
705 return 0;
706}
707
691static int loop_set_fd(struct loop_device *lo, fmode_t mode, 708static int loop_set_fd(struct loop_device *lo, fmode_t mode,
692 struct block_device *bdev, unsigned int arg) 709 struct block_device *bdev, unsigned int arg)
693{ 710{
@@ -745,11 +762,8 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
745 size = get_loop_size(lo, file); 762 size = get_loop_size(lo, file);
746 if ((loff_t)(sector_t)size != size) 763 if ((loff_t)(sector_t)size != size)
747 goto out_putf; 764 goto out_putf;
748 error = -ENOMEM; 765 error = loop_prepare_queue(lo);
749 lo->wq = alloc_workqueue("kloopd%d", 766 if (error)
750 WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 16,
751 lo->lo_number);
752 if (!lo->wq)
753 goto out_putf; 767 goto out_putf;
754 768
755 error = 0; 769 error = 0;
@@ -903,8 +917,7 @@ static int loop_clr_fd(struct loop_device *lo)
903 lo->lo_flags = 0; 917 lo->lo_flags = 0;
904 if (!part_shift) 918 if (!part_shift)
905 lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN; 919 lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN;
906 destroy_workqueue(lo->wq); 920 loop_unprepare_queue(lo);
907 lo->wq = NULL;
908 mutex_unlock(&lo->lo_ctl_mutex); 921 mutex_unlock(&lo->lo_ctl_mutex);
909 /* 922 /*
910 * Need not hold lo_ctl_mutex to fput backing file. 923 * Need not hold lo_ctl_mutex to fput backing file.
@@ -1461,23 +1474,7 @@ static int loop_queue_rq(struct blk_mq_hw_ctx *hctx,
1461 if (lo->lo_state != Lo_bound) 1474 if (lo->lo_state != Lo_bound)
1462 return -EIO; 1475 return -EIO;
1463 1476
1464 if (cmd->rq->cmd_flags & REQ_WRITE) { 1477 queue_kthread_work(&lo->worker, &cmd->work);
1465 struct loop_device *lo = cmd->rq->q->queuedata;
1466 bool need_sched = true;
1467
1468 spin_lock_irq(&lo->lo_lock);
1469 if (lo->write_started)
1470 need_sched = false;
1471 else
1472 lo->write_started = true;
1473 list_add_tail(&cmd->list, &lo->write_cmd_head);
1474 spin_unlock_irq(&lo->lo_lock);
1475
1476 if (need_sched)
1477 queue_work(lo->wq, &lo->write_work);
1478 } else {
1479 queue_work(lo->wq, &cmd->read_work);
1480 }
1481 1478
1482 return BLK_MQ_RQ_QUEUE_OK; 1479 return BLK_MQ_RQ_QUEUE_OK;
1483} 1480}
@@ -1499,35 +1496,10 @@ static void loop_handle_cmd(struct loop_cmd *cmd)
1499 blk_mq_complete_request(cmd->rq); 1496 blk_mq_complete_request(cmd->rq);
1500} 1497}
1501 1498
1502static void loop_queue_write_work(struct work_struct *work) 1499static void loop_queue_work(struct kthread_work *work)
1503{
1504 struct loop_device *lo =
1505 container_of(work, struct loop_device, write_work);
1506 LIST_HEAD(cmd_list);
1507
1508 spin_lock_irq(&lo->lo_lock);
1509 repeat:
1510 list_splice_init(&lo->write_cmd_head, &cmd_list);
1511 spin_unlock_irq(&lo->lo_lock);
1512
1513 while (!list_empty(&cmd_list)) {
1514 struct loop_cmd *cmd = list_first_entry(&cmd_list,
1515 struct loop_cmd, list);
1516 list_del_init(&cmd->list);
1517 loop_handle_cmd(cmd);
1518 }
1519
1520 spin_lock_irq(&lo->lo_lock);
1521 if (!list_empty(&lo->write_cmd_head))
1522 goto repeat;
1523 lo->write_started = false;
1524 spin_unlock_irq(&lo->lo_lock);
1525}
1526
1527static void loop_queue_read_work(struct work_struct *work)
1528{ 1500{
1529 struct loop_cmd *cmd = 1501 struct loop_cmd *cmd =
1530 container_of(work, struct loop_cmd, read_work); 1502 container_of(work, struct loop_cmd, work);
1531 1503
1532 loop_handle_cmd(cmd); 1504 loop_handle_cmd(cmd);
1533} 1505}
@@ -1539,7 +1511,7 @@ static int loop_init_request(void *data, struct request *rq,
1539 struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq); 1511 struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq);
1540 1512
1541 cmd->rq = rq; 1513 cmd->rq = rq;
1542 INIT_WORK(&cmd->read_work, loop_queue_read_work); 1514 init_kthread_work(&cmd->work, loop_queue_work);
1543 1515
1544 return 0; 1516 return 0;
1545} 1517}
@@ -1601,9 +1573,6 @@ static int loop_add(struct loop_device **l, int i)
1601 */ 1573 */
1602 queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, lo->lo_queue); 1574 queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, lo->lo_queue);
1603 1575
1604 INIT_LIST_HEAD(&lo->write_cmd_head);
1605 INIT_WORK(&lo->write_work, loop_queue_write_work);
1606
1607 disk = lo->lo_disk = alloc_disk(1 << part_shift); 1576 disk = lo->lo_disk = alloc_disk(1 << part_shift);
1608 if (!disk) 1577 if (!disk)
1609 goto out_free_queue; 1578 goto out_free_queue;
diff --git a/drivers/block/loop.h b/drivers/block/loop.h
index 25e8997ed246..b6c7d21a453a 100644
--- a/drivers/block/loop.h
+++ b/drivers/block/loop.h
@@ -14,7 +14,7 @@
14#include <linux/blk-mq.h> 14#include <linux/blk-mq.h>
15#include <linux/spinlock.h> 15#include <linux/spinlock.h>
16#include <linux/mutex.h> 16#include <linux/mutex.h>
17#include <linux/workqueue.h> 17#include <linux/kthread.h>
18#include <uapi/linux/loop.h> 18#include <uapi/linux/loop.h>
19 19
20/* Possible states of device */ 20/* Possible states of device */
@@ -54,12 +54,10 @@ struct loop_device {
54 gfp_t old_gfp_mask; 54 gfp_t old_gfp_mask;
55 55
56 spinlock_t lo_lock; 56 spinlock_t lo_lock;
57 struct workqueue_struct *wq;
58 struct list_head write_cmd_head;
59 struct work_struct write_work;
60 bool write_started;
61 int lo_state; 57 int lo_state;
62 struct mutex lo_ctl_mutex; 58 struct mutex lo_ctl_mutex;
59 struct kthread_worker worker;
60 struct task_struct *worker_task;
63 61
64 struct request_queue *lo_queue; 62 struct request_queue *lo_queue;
65 struct blk_mq_tag_set tag_set; 63 struct blk_mq_tag_set tag_set;
@@ -67,7 +65,7 @@ struct loop_device {
67}; 65};
68 66
69struct loop_cmd { 67struct loop_cmd {
70 struct work_struct read_work; 68 struct kthread_work work;
71 struct request *rq; 69 struct request *rq;
72 struct list_head list; 70 struct list_head list;
73}; 71};