Skip to content

Commit 8832cf9

Browse files
sagigrimbergChristoph Hellwig
authored andcommitted
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>
1 parent bc360b0 commit 8832cf9

11 files changed

Lines changed: 50 additions & 37 deletions

File tree

drivers/nvme/target/admin-cmd.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -988,7 +988,7 @@ void nvmet_execute_async_event(struct nvmet_req *req)
988988
ctrl->async_event_cmds[ctrl->nr_async_event_cmds++] = req;
989989
mutex_unlock(&ctrl->lock);
990990

991-
schedule_work(&ctrl->async_event_work);
991+
queue_work(nvmet_wq, &ctrl->async_event_work);
992992
}
993993

994994
void nvmet_execute_keep_alive(struct nvmet_req *req)

drivers/nvme/target/configfs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1593,7 +1593,7 @@ static void nvmet_port_release(struct config_item *item)
15931593
struct nvmet_port *port = to_nvmet_port(item);
15941594

15951595
/* Let inflight controllers teardown complete */
1596-
flush_scheduled_work();
1596+
flush_workqueue(nvmet_wq);
15971597
list_del(&port->global_entry);
15981598

15991599
kfree(port->ana_state);

drivers/nvme/target/core.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ struct workqueue_struct *zbd_wq;
2020
static const struct nvmet_fabrics_ops *nvmet_transports[NVMF_TRTYPE_MAX];
2121
static DEFINE_IDA(cntlid_ida);
2222

23+
struct workqueue_struct *nvmet_wq;
24+
EXPORT_SYMBOL_GPL(nvmet_wq);
25+
2326
/*
2427
* This read/write semaphore is used to synchronize access to configuration
2528
* information on a target system that will result in discovery log page
@@ -205,7 +208,7 @@ void nvmet_add_async_event(struct nvmet_ctrl *ctrl, u8 event_type,
205208
list_add_tail(&aen->entry, &ctrl->async_events);
206209
mutex_unlock(&ctrl->lock);
207210

208-
schedule_work(&ctrl->async_event_work);
211+
queue_work(nvmet_wq, &ctrl->async_event_work);
209212
}
210213

211214
static void nvmet_add_to_changed_ns_log(struct nvmet_ctrl *ctrl, __le32 nsid)
@@ -385,7 +388,7 @@ static void nvmet_keep_alive_timer(struct work_struct *work)
385388
if (reset_tbkas) {
386389
pr_debug("ctrl %d reschedule traffic based keep-alive timer\n",
387390
ctrl->cntlid);
388-
schedule_delayed_work(&ctrl->ka_work, ctrl->kato * HZ);
391+
queue_delayed_work(nvmet_wq, &ctrl->ka_work, ctrl->kato * HZ);
389392
return;
390393
}
391394

@@ -403,7 +406,7 @@ void nvmet_start_keep_alive_timer(struct nvmet_ctrl *ctrl)
403406
pr_debug("ctrl %d start keep-alive timer for %d secs\n",
404407
ctrl->cntlid, ctrl->kato);
405408

406-
schedule_delayed_work(&ctrl->ka_work, ctrl->kato * HZ);
409+
queue_delayed_work(nvmet_wq, &ctrl->ka_work, ctrl->kato * HZ);
407410
}
408411

409412
void nvmet_stop_keep_alive_timer(struct nvmet_ctrl *ctrl)
@@ -1478,7 +1481,7 @@ void nvmet_ctrl_fatal_error(struct nvmet_ctrl *ctrl)
14781481
mutex_lock(&ctrl->lock);
14791482
if (!(ctrl->csts & NVME_CSTS_CFS)) {
14801483
ctrl->csts |= NVME_CSTS_CFS;
1481-
schedule_work(&ctrl->fatal_err_work);
1484+
queue_work(nvmet_wq, &ctrl->fatal_err_work);
14821485
}
14831486
mutex_unlock(&ctrl->lock);
14841487
}
@@ -1620,9 +1623,15 @@ static int __init nvmet_init(void)
16201623
goto out_free_zbd_work_queue;
16211624
}
16221625

1626+
nvmet_wq = alloc_workqueue("nvmet-wq", WQ_MEM_RECLAIM, 0);
1627+
if (!nvmet_wq) {
1628+
error = -ENOMEM;
1629+
goto out_free_buffered_work_queue;
1630+
}
1631+
16231632
error = nvmet_init_discovery();
16241633
if (error)
1625-
goto out_free_work_queue;
1634+
goto out_free_nvmet_work_queue;
16261635

16271636
error = nvmet_init_configfs();
16281637
if (error)
@@ -1631,7 +1640,9 @@ static int __init nvmet_init(void)
16311640

16321641
out_exit_discovery:
16331642
nvmet_exit_discovery();
1634-
out_free_work_queue:
1643+
out_free_nvmet_work_queue:
1644+
destroy_workqueue(nvmet_wq);
1645+
out_free_buffered_work_queue:
16351646
destroy_workqueue(buffered_io_wq);
16361647
out_free_zbd_work_queue:
16371648
destroy_workqueue(zbd_wq);
@@ -1643,6 +1654,7 @@ static void __exit nvmet_exit(void)
16431654
nvmet_exit_configfs();
16441655
nvmet_exit_discovery();
16451656
ida_destroy(&cntlid_ida);
1657+
destroy_workqueue(nvmet_wq);
16461658
destroy_workqueue(buffered_io_wq);
16471659
destroy_workqueue(zbd_wq);
16481660

drivers/nvme/target/fc.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,7 +1491,7 @@ __nvmet_fc_free_assocs(struct nvmet_fc_tgtport *tgtport)
14911491
list_for_each_entry_rcu(assoc, &tgtport->assoc_list, a_list) {
14921492
if (!nvmet_fc_tgt_a_get(assoc))
14931493
continue;
1494-
if (!schedule_work(&assoc->del_work))
1494+
if (!queue_work(nvmet_wq, &assoc->del_work))
14951495
/* already deleting - release local reference */
14961496
nvmet_fc_tgt_a_put(assoc);
14971497
}
@@ -1546,7 +1546,7 @@ nvmet_fc_invalidate_host(struct nvmet_fc_target_port *target_port,
15461546
continue;
15471547
assoc->hostport->invalid = 1;
15481548
noassoc = false;
1549-
if (!schedule_work(&assoc->del_work))
1549+
if (!queue_work(nvmet_wq, &assoc->del_work))
15501550
/* already deleting - release local reference */
15511551
nvmet_fc_tgt_a_put(assoc);
15521552
}
@@ -1592,7 +1592,7 @@ nvmet_fc_delete_ctrl(struct nvmet_ctrl *ctrl)
15921592
nvmet_fc_tgtport_put(tgtport);
15931593

15941594
if (found_ctrl) {
1595-
if (!schedule_work(&assoc->del_work))
1595+
if (!queue_work(nvmet_wq, &assoc->del_work))
15961596
/* already deleting - release local reference */
15971597
nvmet_fc_tgt_a_put(assoc);
15981598
return;
@@ -2060,7 +2060,7 @@ nvmet_fc_rcv_ls_req(struct nvmet_fc_target_port *target_port,
20602060
iod->rqstdatalen = lsreqbuf_len;
20612061
iod->hosthandle = hosthandle;
20622062

2063-
schedule_work(&iod->work);
2063+
queue_work(nvmet_wq, &iod->work);
20642064

20652065
return 0;
20662066
}

drivers/nvme/target/fcloop.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ fcloop_h2t_ls_req(struct nvme_fc_local_port *localport,
360360
spin_lock(&rport->lock);
361361
list_add_tail(&rport->ls_list, &tls_req->ls_list);
362362
spin_unlock(&rport->lock);
363-
schedule_work(&rport->ls_work);
363+
queue_work(nvmet_wq, &rport->ls_work);
364364
return ret;
365365
}
366366

@@ -393,7 +393,7 @@ fcloop_h2t_xmt_ls_rsp(struct nvmet_fc_target_port *targetport,
393393
spin_lock(&rport->lock);
394394
list_add_tail(&rport->ls_list, &tls_req->ls_list);
395395
spin_unlock(&rport->lock);
396-
schedule_work(&rport->ls_work);
396+
queue_work(nvmet_wq, &rport->ls_work);
397397
}
398398

399399
return 0;
@@ -448,7 +448,7 @@ fcloop_t2h_ls_req(struct nvmet_fc_target_port *targetport, void *hosthandle,
448448
spin_lock(&tport->lock);
449449
list_add_tail(&tport->ls_list, &tls_req->ls_list);
450450
spin_unlock(&tport->lock);
451-
schedule_work(&tport->ls_work);
451+
queue_work(nvmet_wq, &tport->ls_work);
452452
return ret;
453453
}
454454

@@ -480,7 +480,7 @@ fcloop_t2h_xmt_ls_rsp(struct nvme_fc_local_port *localport,
480480
spin_lock(&tport->lock);
481481
list_add_tail(&tport->ls_list, &tls_req->ls_list);
482482
spin_unlock(&tport->lock);
483-
schedule_work(&tport->ls_work);
483+
queue_work(nvmet_wq, &tport->ls_work);
484484
}
485485

486486
return 0;
@@ -520,7 +520,7 @@ fcloop_tgt_discovery_evt(struct nvmet_fc_target_port *tgtport)
520520
tgt_rscn->tport = tgtport->private;
521521
INIT_WORK(&tgt_rscn->work, fcloop_tgt_rscn_work);
522522

523-
schedule_work(&tgt_rscn->work);
523+
queue_work(nvmet_wq, &tgt_rscn->work);
524524
}
525525

526526
static void
@@ -739,7 +739,7 @@ fcloop_fcp_req(struct nvme_fc_local_port *localport,
739739
INIT_WORK(&tfcp_req->tio_done_work, fcloop_tgt_fcprqst_done_work);
740740
kref_init(&tfcp_req->ref);
741741

742-
schedule_work(&tfcp_req->fcp_rcv_work);
742+
queue_work(nvmet_wq, &tfcp_req->fcp_rcv_work);
743743

744744
return 0;
745745
}
@@ -921,7 +921,7 @@ fcloop_fcp_req_release(struct nvmet_fc_target_port *tgtport,
921921
{
922922
struct fcloop_fcpreq *tfcp_req = tgt_fcp_req_to_fcpreq(tgt_fcpreq);
923923

924-
schedule_work(&tfcp_req->tio_done_work);
924+
queue_work(nvmet_wq, &tfcp_req->tio_done_work);
925925
}
926926

927927
static void
@@ -976,7 +976,7 @@ fcloop_fcp_abort(struct nvme_fc_local_port *localport,
976976

977977
if (abortio)
978978
/* 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));
980980
else {
981981
/*
982982
* as the io has already had the done callback made,

drivers/nvme/target/io-cmd-file.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ static void nvmet_file_execute_flush(struct nvmet_req *req)
283283
if (!nvmet_check_transfer_len(req, 0))
284284
return;
285285
INIT_WORK(&req->f.work, nvmet_file_flush_work);
286-
schedule_work(&req->f.work);
286+
queue_work(nvmet_wq, &req->f.work);
287287
}
288288

289289
static void nvmet_file_execute_discard(struct nvmet_req *req)
@@ -343,7 +343,7 @@ static void nvmet_file_execute_dsm(struct nvmet_req *req)
343343
if (!nvmet_check_data_len_lte(req, nvmet_dsm_len(req)))
344344
return;
345345
INIT_WORK(&req->f.work, nvmet_file_dsm_work);
346-
schedule_work(&req->f.work);
346+
queue_work(nvmet_wq, &req->f.work);
347347
}
348348

349349
static void nvmet_file_write_zeroes_work(struct work_struct *w)
@@ -373,7 +373,7 @@ static void nvmet_file_execute_write_zeroes(struct nvmet_req *req)
373373
if (!nvmet_check_transfer_len(req, 0))
374374
return;
375375
INIT_WORK(&req->f.work, nvmet_file_write_zeroes_work);
376-
schedule_work(&req->f.work);
376+
queue_work(nvmet_wq, &req->f.work);
377377
}
378378

379379
u16 nvmet_file_parse_io_cmd(struct nvmet_req *req)

drivers/nvme/target/loop.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx,
166166
iod->req.transfer_len = blk_rq_payload_bytes(req);
167167
}
168168

169-
schedule_work(&iod->work);
169+
queue_work(nvmet_wq, &iod->work);
170170
return BLK_STS_OK;
171171
}
172172

@@ -187,7 +187,7 @@ static void nvme_loop_submit_async_event(struct nvme_ctrl *arg)
187187
return;
188188
}
189189

190-
schedule_work(&iod->work);
190+
queue_work(nvmet_wq, &iod->work);
191191
}
192192

193193
static int nvme_loop_init_iod(struct nvme_loop_ctrl *ctrl,

drivers/nvme/target/nvmet.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ struct nvmet_req {
366366

367367
extern struct workqueue_struct *buffered_io_wq;
368368
extern struct workqueue_struct *zbd_wq;
369+
extern struct workqueue_struct *nvmet_wq;
369370

370371
static inline void nvmet_set_result(struct nvmet_req *req, u32 result)
371372
{

drivers/nvme/target/passthru.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ static void nvmet_passthru_execute_cmd(struct nvmet_req *req)
283283
if (req->p.use_workqueue || effects) {
284284
INIT_WORK(&req->p.work, nvmet_passthru_execute_cmd_work);
285285
req->p.rq = rq;
286-
schedule_work(&req->p.work);
286+
queue_work(nvmet_wq, &req->p.work);
287287
} else {
288288
rq->end_io_data = req;
289289
blk_execute_rq_nowait(rq, false, nvmet_passthru_req_done);

drivers/nvme/target/rdma.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1584,7 +1584,7 @@ static int nvmet_rdma_queue_connect(struct rdma_cm_id *cm_id,
15841584

15851585
if (queue->host_qid == 0) {
15861586
/* Let inflight controller teardown complete */
1587-
flush_scheduled_work();
1587+
flush_workqueue(nvmet_wq);
15881588
}
15891589

15901590
ret = nvmet_rdma_cm_accept(cm_id, queue, &event->param.conn);
@@ -1669,7 +1669,7 @@ static void __nvmet_rdma_queue_disconnect(struct nvmet_rdma_queue *queue)
16691669

16701670
if (disconnect) {
16711671
rdma_disconnect(queue->cm_id);
1672-
schedule_work(&queue->release_work);
1672+
queue_work(nvmet_wq, &queue->release_work);
16731673
}
16741674
}
16751675

@@ -1699,7 +1699,7 @@ static void nvmet_rdma_queue_connect_fail(struct rdma_cm_id *cm_id,
16991699
mutex_unlock(&nvmet_rdma_queue_mutex);
17001700

17011701
pr_err("failed to connect queue %d\n", queue->idx);
1702-
schedule_work(&queue->release_work);
1702+
queue_work(nvmet_wq, &queue->release_work);
17031703
}
17041704

17051705
/**
@@ -1773,7 +1773,7 @@ static int nvmet_rdma_cm_handler(struct rdma_cm_id *cm_id,
17731773
if (!queue) {
17741774
struct nvmet_rdma_port *port = cm_id->context;
17751775

1776-
schedule_delayed_work(&port->repair_work, 0);
1776+
queue_delayed_work(nvmet_wq, &port->repair_work, 0);
17771777
break;
17781778
}
17791779
fallthrough;
@@ -1903,7 +1903,7 @@ static void nvmet_rdma_repair_port_work(struct work_struct *w)
19031903
nvmet_rdma_disable_port(port);
19041904
ret = nvmet_rdma_enable_port(port);
19051905
if (ret)
1906-
schedule_delayed_work(&port->repair_work, 5 * HZ);
1906+
queue_delayed_work(nvmet_wq, &port->repair_work, 5 * HZ);
19071907
}
19081908

19091909
static int nvmet_rdma_add_port(struct nvmet_port *nport)
@@ -2053,7 +2053,7 @@ static void nvmet_rdma_remove_one(struct ib_device *ib_device, void *client_data
20532053
}
20542054
mutex_unlock(&nvmet_rdma_queue_mutex);
20552055

2056-
flush_scheduled_work();
2056+
flush_workqueue(nvmet_wq);
20572057
}
20582058

20592059
static struct ib_client nvmet_rdma_ib_client = {

0 commit comments

Comments
 (0)