Re: [PATCH] scsi: core: do not block on tag allocation in scsi_eh_lock_door()
Zizhi Wo <[email protected]> Thu, 30 Jul 2026 15:28:30 +0800
| Newsgroups | org.kernel.vger.linux-scsi,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
friendly ping 在 2026/7/23 12:12, Zizhi Wo 写道: > From: Zizhi Wo <[email protected]> > > scsi_eh_lock_door() is called from scsi_restart_operations() while the host > is still in the SHOST_RECOVERY state, i.e. before the host is switched back > to SHOST_RUNNING and scsi_run_host_queues() restarts the queues. It > allocates a request via scsi_alloc_request() with no flags, so > blk_mq_get_tag() may block waiting for a free sched tag when all tags are > already in use. > > Those tags can be held by commands that were just requeued by > scsi_eh_flush_done_q() during error handling. Such commands cannot be > dispatched until the host leaves SHOST_RECOVERY and scsi_run_host_queues() > is called - which only happens *after* scsi_eh_lock_door() returns. > > This forms a circular dependency: > > - scsi_eh_lock_door(), running in the SCSI error handler thread, waits > for a sched tag held by a requeued command; > - the requeued command cannot complete and release its sched tag until > the error handler thread leaves scsi_restart_operations() and restart > the queues. > > For devices with a single driver tag (e.g. USB storage) it is a guaranteed > deadlock and I/O that can never be submitted. This problem has also been > reproduced in our environment. > > Locking the door is a best-effort operation, and scsi_eh_lock_door() > already returns silently when the request allocation fails. Pass > BLK_MQ_REQ_NOWAIT to scsi_alloc_request() so the allocation fails instead > of blocking when no tag is available. This breaks the circular dependency > and allows the error handler to finish restarting the queues, after which > the pending commands are dispatched normally. > > Signed-off-by: Zizhi Wo <[email protected]> > --- > drivers/scsi/scsi_error.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c > index 147127fb4db9..3d42fe7701b7 100644 > --- a/drivers/scsi/scsi_error.c > +++ b/drivers/scsi/scsi_error.c > @@ -2139,11 +2139,11 @@ static enum rq_end_io_ret eh_lock_door_done(struct request *req, > static void scsi_eh_lock_door(struct scsi_device *sdev) > { > struct scsi_cmnd *scmd; > struct request *req; > > - req = scsi_alloc_request(sdev->request_queue, REQ_OP_DRV_IN, 0); > + req = scsi_alloc_request(sdev->request_queue, REQ_OP_DRV_IN, BLK_MQ_REQ_NOWAIT); > if (IS_ERR(req)) > return; > scmd = blk_mq_rq_to_pdu(req); > > scmd->cmnd[0] = ALLOW_MEDIUM_REMOVAL;