diff options
-rw-r--r-- | drivers/block/loop.c | 79 | ||||
-rw-r--r-- | drivers/block/loop.h | 10 |
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 | ||
691 | static void loop_unprepare_queue(struct loop_device *lo) | ||
692 | { | ||
693 | flush_kthread_worker(&lo->worker); | ||
694 | kthread_stop(lo->worker_task); | ||
695 | } | ||
696 | |||
697 | static 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 | |||
691 | static int loop_set_fd(struct loop_device *lo, fmode_t mode, | 708 | static 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 | ||
1502 | static void loop_queue_write_work(struct work_struct *work) | 1499 | static 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 | |||
1527 | static 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 | ||
69 | struct loop_cmd { | 67 | struct 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 | }; |