Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nvmet: use a private workqueue instead of the system workqueue

Any attempt to flush kernel-global WQs has possibility of deadlock
so we should simply stop using them, instead introduce nvmet_wq
which is the generic nvmet workqueue for work elements that
don't explicitly require a dedicated workqueue (by the mere fact
that they are using the system_wq).

Changes were done using the following replaces:

- s/schedule_work(/queue_work(nvmet_wq, /g
- s/schedule_delayed_work(/queue_delayed_work(nvmet_wq, /g
- s/flush_scheduled_work()/flush_workqueue(nvmet_wq)/g

Reported-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Sagi Grimberg <sagi@grimberg.me>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>

authored by

Sagi Grimberg and committed by
Christoph Hellwig
8832cf92 bc360b0b

+50 -37
+1 -1
drivers/nvme/target/admin-cmd.c
··· 988 988 ctrl->async_event_cmds[ctrl->nr_async_event_cmds++] = req; 989 989 mutex_unlock(&ctrl->lock); 990 990 991 - schedule_work(&ctrl->async_event_work); 991 + queue_work(nvmet_wq, &ctrl->async_event_work); 992 992 } 993 993 994 994 void nvmet_execute_keep_alive(struct nvmet_req *req)
+1 -1
drivers/nvme/target/configfs.c
··· 1593 1593 struct nvmet_port *port = to_nvmet_port(item); 1594 1594 1595 1595 /* Let inflight controllers teardown complete */ 1596 - flush_scheduled_work(); 1596 + flush_workqueue(nvmet_wq); 1597 1597 list_del(&port->global_entry); 1598 1598 1599 1599 kfree(port->ana_state);
+18 -6
drivers/nvme/target/core.c
··· 20 20 static const struct nvmet_fabrics_ops *nvmet_transports[NVMF_TRTYPE_MAX]; 21 21 static DEFINE_IDA(cntlid_ida); 22 22 23 + struct workqueue_struct *nvmet_wq; 24 + EXPORT_SYMBOL_GPL(nvmet_wq); 25 + 23 26 /* 24 27 * This read/write semaphore is used to synchronize access to configuration 25 28 * information on a target system that will result in discovery log page ··· 208 205 list_add_tail(&aen->entry, &ctrl->async_events); 209 206 mutex_unlock(&ctrl->lock); 210 207 211 - schedule_work(&ctrl->async_event_work); 208 + queue_work(nvmet_wq, &ctrl->async_event_work); 212 209 } 213 210 214 211 static void nvmet_add_to_changed_ns_log(struct nvmet_ctrl *ctrl, __le32 nsid) ··· 388 385 if (reset_tbkas) { 389 386 pr_debug("ctrl %d reschedule traffic based keep-alive timer\n", 390 387 ctrl->cntlid); 391 - schedule_delayed_work(&ctrl->ka_work, ctrl->kato * HZ); 388 + queue_delayed_work(nvmet_wq, &ctrl->ka_work, ctrl->kato * HZ); 392 389 return; 393 390 } 394 391 ··· 406 403 pr_debug("ctrl %d start keep-alive timer for %d secs\n", 407 404 ctrl->cntlid, ctrl->kato); 408 405 409 - schedule_delayed_work(&ctrl->ka_work, ctrl->kato * HZ); 406 + queue_delayed_work(nvmet_wq, &ctrl->ka_work, ctrl->kato * HZ); 410 407 } 411 408 412 409 void nvmet_stop_keep_alive_timer(struct nvmet_ctrl *ctrl) ··· 1481 1478 mutex_lock(&ctrl->lock); 1482 1479 if (!(ctrl->csts & NVME_CSTS_CFS)) { 1483 1480 ctrl->csts |= NVME_CSTS_CFS; 1484 - schedule_work(&ctrl->fatal_err_work); 1481 + queue_work(nvmet_wq, &ctrl->fatal_err_work); 1485 1482 } 1486 1483 mutex_unlock(&ctrl->lock); 1487 1484 } ··· 1623 1620 goto out_free_zbd_work_queue; 1624 1621 } 1625 1622 1623 + nvmet_wq = alloc_workqueue("nvmet-wq", WQ_MEM_RECLAIM, 0); 1624 + if (!nvmet_wq) { 1625 + error = -ENOMEM; 1626 + goto out_free_buffered_work_queue; 1627 + } 1628 + 1626 1629 error = nvmet_init_discovery(); 1627 1630 if (error) 1628 - goto out_free_work_queue; 1631 + goto out_free_nvmet_work_queue; 1629 1632 1630 1633 error = nvmet_init_configfs(); 1631 1634 if (error) ··· 1640 1631 1641 1632 out_exit_discovery: 1642 1633 nvmet_exit_discovery(); 1643 - out_free_work_queue: 1634 + out_free_nvmet_work_queue: 1635 + destroy_workqueue(nvmet_wq); 1636 + out_free_buffered_work_queue: 1644 1637 destroy_workqueue(buffered_io_wq); 1645 1638 out_free_zbd_work_queue: 1646 1639 destroy_workqueue(zbd_wq); ··· 1654 1643 nvmet_exit_configfs(); 1655 1644 nvmet_exit_discovery(); 1656 1645 ida_destroy(&cntlid_ida); 1646 + destroy_workqueue(nvmet_wq); 1657 1647 destroy_workqueue(buffered_io_wq); 1658 1648 destroy_workqueue(zbd_wq); 1659 1649
+4 -4
drivers/nvme/target/fc.c
··· 1491 1491 list_for_each_entry_rcu(assoc, &tgtport->assoc_list, a_list) { 1492 1492 if (!nvmet_fc_tgt_a_get(assoc)) 1493 1493 continue; 1494 - if (!schedule_work(&assoc->del_work)) 1494 + if (!queue_work(nvmet_wq, &assoc->del_work)) 1495 1495 /* already deleting - release local reference */ 1496 1496 nvmet_fc_tgt_a_put(assoc); 1497 1497 } ··· 1546 1546 continue; 1547 1547 assoc->hostport->invalid = 1; 1548 1548 noassoc = false; 1549 - if (!schedule_work(&assoc->del_work)) 1549 + if (!queue_work(nvmet_wq, &assoc->del_work)) 1550 1550 /* already deleting - release local reference */ 1551 1551 nvmet_fc_tgt_a_put(assoc); 1552 1552 } ··· 1592 1592 nvmet_fc_tgtport_put(tgtport); 1593 1593 1594 1594 if (found_ctrl) { 1595 - if (!schedule_work(&assoc->del_work)) 1595 + if (!queue_work(nvmet_wq, &assoc->del_work)) 1596 1596 /* already deleting - release local reference */ 1597 1597 nvmet_fc_tgt_a_put(assoc); 1598 1598 return; ··· 2060 2060 iod->rqstdatalen = lsreqbuf_len; 2061 2061 iod->hosthandle = hosthandle; 2062 2062 2063 - schedule_work(&iod->work); 2063 + queue_work(nvmet_wq, &iod->work); 2064 2064 2065 2065 return 0; 2066 2066 }
+8 -8
drivers/nvme/target/fcloop.c
··· 360 360 spin_lock(&rport->lock); 361 361 list_add_tail(&rport->ls_list, &tls_req->ls_list); 362 362 spin_unlock(&rport->lock); 363 - schedule_work(&rport->ls_work); 363 + queue_work(nvmet_wq, &rport->ls_work); 364 364 return ret; 365 365 } 366 366 ··· 393 393 spin_lock(&rport->lock); 394 394 list_add_tail(&rport->ls_list, &tls_req->ls_list); 395 395 spin_unlock(&rport->lock); 396 - schedule_work(&rport->ls_work); 396 + queue_work(nvmet_wq, &rport->ls_work); 397 397 } 398 398 399 399 return 0; ··· 448 448 spin_lock(&tport->lock); 449 449 list_add_tail(&tport->ls_list, &tls_req->ls_list); 450 450 spin_unlock(&tport->lock); 451 - schedule_work(&tport->ls_work); 451 + queue_work(nvmet_wq, &tport->ls_work); 452 452 return ret; 453 453 } 454 454 ··· 480 480 spin_lock(&tport->lock); 481 481 list_add_tail(&tport->ls_list, &tls_req->ls_list); 482 482 spin_unlock(&tport->lock); 483 - schedule_work(&tport->ls_work); 483 + queue_work(nvmet_wq, &tport->ls_work); 484 484 } 485 485 486 486 return 0; ··· 520 520 tgt_rscn->tport = tgtport->private; 521 521 INIT_WORK(&tgt_rscn->work, fcloop_tgt_rscn_work); 522 522 523 - schedule_work(&tgt_rscn->work); 523 + queue_work(nvmet_wq, &tgt_rscn->work); 524 524 } 525 525 526 526 static void ··· 739 739 INIT_WORK(&tfcp_req->tio_done_work, fcloop_tgt_fcprqst_done_work); 740 740 kref_init(&tfcp_req->ref); 741 741 742 - schedule_work(&tfcp_req->fcp_rcv_work); 742 + queue_work(nvmet_wq, &tfcp_req->fcp_rcv_work); 743 743 744 744 return 0; 745 745 } ··· 921 921 { 922 922 struct fcloop_fcpreq *tfcp_req = tgt_fcp_req_to_fcpreq(tgt_fcpreq); 923 923 924 - schedule_work(&tfcp_req->tio_done_work); 924 + queue_work(nvmet_wq, &tfcp_req->tio_done_work); 925 925 } 926 926 927 927 static void ··· 976 976 977 977 if (abortio) 978 978 /* leave the reference while the work item is scheduled */ 979 - WARN_ON(!schedule_work(&tfcp_req->abort_rcv_work)); 979 + WARN_ON(!queue_work(nvmet_wq, &tfcp_req->abort_rcv_work)); 980 980 else { 981 981 /* 982 982 * as the io has already had the done callback made,
+3 -3
drivers/nvme/target/io-cmd-file.c
··· 283 283 if (!nvmet_check_transfer_len(req, 0)) 284 284 return; 285 285 INIT_WORK(&req->f.work, nvmet_file_flush_work); 286 - schedule_work(&req->f.work); 286 + queue_work(nvmet_wq, &req->f.work); 287 287 } 288 288 289 289 static void nvmet_file_execute_discard(struct nvmet_req *req) ··· 343 343 if (!nvmet_check_data_len_lte(req, nvmet_dsm_len(req))) 344 344 return; 345 345 INIT_WORK(&req->f.work, nvmet_file_dsm_work); 346 - schedule_work(&req->f.work); 346 + queue_work(nvmet_wq, &req->f.work); 347 347 } 348 348 349 349 static void nvmet_file_write_zeroes_work(struct work_struct *w) ··· 373 373 if (!nvmet_check_transfer_len(req, 0)) 374 374 return; 375 375 INIT_WORK(&req->f.work, nvmet_file_write_zeroes_work); 376 - schedule_work(&req->f.work); 376 + queue_work(nvmet_wq, &req->f.work); 377 377 } 378 378 379 379 u16 nvmet_file_parse_io_cmd(struct nvmet_req *req)
+2 -2
drivers/nvme/target/loop.c
··· 166 166 iod->req.transfer_len = blk_rq_payload_bytes(req); 167 167 } 168 168 169 - schedule_work(&iod->work); 169 + queue_work(nvmet_wq, &iod->work); 170 170 return BLK_STS_OK; 171 171 } 172 172 ··· 187 187 return; 188 188 } 189 189 190 - schedule_work(&iod->work); 190 + queue_work(nvmet_wq, &iod->work); 191 191 } 192 192 193 193 static int nvme_loop_init_iod(struct nvme_loop_ctrl *ctrl,
+1
drivers/nvme/target/nvmet.h
··· 366 366 367 367 extern struct workqueue_struct *buffered_io_wq; 368 368 extern struct workqueue_struct *zbd_wq; 369 + extern struct workqueue_struct *nvmet_wq; 369 370 370 371 static inline void nvmet_set_result(struct nvmet_req *req, u32 result) 371 372 {
+1 -1
drivers/nvme/target/passthru.c
··· 283 283 if (req->p.use_workqueue || effects) { 284 284 INIT_WORK(&req->p.work, nvmet_passthru_execute_cmd_work); 285 285 req->p.rq = rq; 286 - schedule_work(&req->p.work); 286 + queue_work(nvmet_wq, &req->p.work); 287 287 } else { 288 288 rq->end_io_data = req; 289 289 blk_execute_rq_nowait(rq, false, nvmet_passthru_req_done);
+6 -6
drivers/nvme/target/rdma.c
··· 1584 1584 1585 1585 if (queue->host_qid == 0) { 1586 1586 /* Let inflight controller teardown complete */ 1587 - flush_scheduled_work(); 1587 + flush_workqueue(nvmet_wq); 1588 1588 } 1589 1589 1590 1590 ret = nvmet_rdma_cm_accept(cm_id, queue, &event->param.conn); ··· 1669 1669 1670 1670 if (disconnect) { 1671 1671 rdma_disconnect(queue->cm_id); 1672 - schedule_work(&queue->release_work); 1672 + queue_work(nvmet_wq, &queue->release_work); 1673 1673 } 1674 1674 } 1675 1675 ··· 1699 1699 mutex_unlock(&nvmet_rdma_queue_mutex); 1700 1700 1701 1701 pr_err("failed to connect queue %d\n", queue->idx); 1702 - schedule_work(&queue->release_work); 1702 + queue_work(nvmet_wq, &queue->release_work); 1703 1703 } 1704 1704 1705 1705 /** ··· 1773 1773 if (!queue) { 1774 1774 struct nvmet_rdma_port *port = cm_id->context; 1775 1775 1776 - schedule_delayed_work(&port->repair_work, 0); 1776 + queue_delayed_work(nvmet_wq, &port->repair_work, 0); 1777 1777 break; 1778 1778 } 1779 1779 fallthrough; ··· 1903 1903 nvmet_rdma_disable_port(port); 1904 1904 ret = nvmet_rdma_enable_port(port); 1905 1905 if (ret) 1906 - schedule_delayed_work(&port->repair_work, 5 * HZ); 1906 + queue_delayed_work(nvmet_wq, &port->repair_work, 5 * HZ); 1907 1907 } 1908 1908 1909 1909 static int nvmet_rdma_add_port(struct nvmet_port *nport) ··· 2053 2053 } 2054 2054 mutex_unlock(&nvmet_rdma_queue_mutex); 2055 2055 2056 - flush_scheduled_work(); 2056 + flush_workqueue(nvmet_wq); 2057 2057 } 2058 2058 2059 2059 static struct ib_client nvmet_rdma_ib_client = {
+5 -5
drivers/nvme/target/tcp.c
··· 1269 1269 spin_lock(&queue->state_lock); 1270 1270 if (queue->state != NVMET_TCP_Q_DISCONNECTING) { 1271 1271 queue->state = NVMET_TCP_Q_DISCONNECTING; 1272 - schedule_work(&queue->release_work); 1272 + queue_work(nvmet_wq, &queue->release_work); 1273 1273 } 1274 1274 spin_unlock(&queue->state_lock); 1275 1275 } ··· 1684 1684 goto out; 1685 1685 1686 1686 if (sk->sk_state == TCP_LISTEN) 1687 - schedule_work(&port->accept_work); 1687 + queue_work(nvmet_wq, &port->accept_work); 1688 1688 out: 1689 1689 read_unlock_bh(&sk->sk_callback_lock); 1690 1690 } ··· 1815 1815 1816 1816 if (sq->qid == 0) { 1817 1817 /* Let inflight controller teardown complete */ 1818 - flush_scheduled_work(); 1818 + flush_workqueue(nvmet_wq); 1819 1819 } 1820 1820 1821 1821 queue->nr_cmds = sq->size * 2; ··· 1876 1876 1877 1877 nvmet_unregister_transport(&nvmet_tcp_ops); 1878 1878 1879 - flush_scheduled_work(); 1879 + flush_workqueue(nvmet_wq); 1880 1880 mutex_lock(&nvmet_tcp_queue_mutex); 1881 1881 list_for_each_entry(queue, &nvmet_tcp_queue_list, queue_list) 1882 1882 kernel_sock_shutdown(queue->sock, SHUT_RDWR); 1883 1883 mutex_unlock(&nvmet_tcp_queue_mutex); 1884 - flush_scheduled_work(); 1884 + flush_workqueue(nvmet_wq); 1885 1885 1886 1886 destroy_workqueue(nvmet_tcp_wq); 1887 1887 }