nvmet-fcloop: access fcpreq only when holding reqlock
[ Upstream commit 47a827cd7929d0550c3496d70b417fcb5649b27b ] The abort handling logic expects that the state and the fcpreq are only accessed when holding the reqlock lock. While at it, only handle the aborts in the abort handler. Signed-off-by: Daniel Wagner <wagi@kernel.org> Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
84ead78a3c
commit
efcd52ba64
@@ -613,12 +613,13 @@ fcloop_fcp_recv_work(struct work_struct *work)
|
|||||||
{
|
{
|
||||||
struct fcloop_fcpreq *tfcp_req =
|
struct fcloop_fcpreq *tfcp_req =
|
||||||
container_of(work, struct fcloop_fcpreq, fcp_rcv_work);
|
container_of(work, struct fcloop_fcpreq, fcp_rcv_work);
|
||||||
struct nvmefc_fcp_req *fcpreq = tfcp_req->fcpreq;
|
struct nvmefc_fcp_req *fcpreq;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
bool aborted = false;
|
bool aborted = false;
|
||||||
|
|
||||||
spin_lock_irqsave(&tfcp_req->reqlock, flags);
|
spin_lock_irqsave(&tfcp_req->reqlock, flags);
|
||||||
|
fcpreq = tfcp_req->fcpreq;
|
||||||
switch (tfcp_req->inistate) {
|
switch (tfcp_req->inistate) {
|
||||||
case INI_IO_START:
|
case INI_IO_START:
|
||||||
tfcp_req->inistate = INI_IO_ACTIVE;
|
tfcp_req->inistate = INI_IO_ACTIVE;
|
||||||
@@ -633,16 +634,19 @@ fcloop_fcp_recv_work(struct work_struct *work)
|
|||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&tfcp_req->reqlock, flags);
|
spin_unlock_irqrestore(&tfcp_req->reqlock, flags);
|
||||||
|
|
||||||
if (unlikely(aborted))
|
if (unlikely(aborted)) {
|
||||||
ret = -ECANCELED;
|
/* the abort handler will call fcloop_call_host_done */
|
||||||
else {
|
return;
|
||||||
if (likely(!check_for_drop(tfcp_req)))
|
|
||||||
ret = nvmet_fc_rcv_fcp_req(tfcp_req->tport->targetport,
|
|
||||||
&tfcp_req->tgt_fcp_req,
|
|
||||||
fcpreq->cmdaddr, fcpreq->cmdlen);
|
|
||||||
else
|
|
||||||
pr_info("%s: dropped command ********\n", __func__);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unlikely(check_for_drop(tfcp_req))) {
|
||||||
|
pr_info("%s: dropped command ********\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = nvmet_fc_rcv_fcp_req(tfcp_req->tport->targetport,
|
||||||
|
&tfcp_req->tgt_fcp_req,
|
||||||
|
fcpreq->cmdaddr, fcpreq->cmdlen);
|
||||||
if (ret)
|
if (ret)
|
||||||
fcloop_call_host_done(fcpreq, tfcp_req, ret);
|
fcloop_call_host_done(fcpreq, tfcp_req, ret);
|
||||||
}
|
}
|
||||||
@@ -657,9 +661,10 @@ fcloop_fcp_abort_recv_work(struct work_struct *work)
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&tfcp_req->reqlock, flags);
|
spin_lock_irqsave(&tfcp_req->reqlock, flags);
|
||||||
fcpreq = tfcp_req->fcpreq;
|
|
||||||
switch (tfcp_req->inistate) {
|
switch (tfcp_req->inistate) {
|
||||||
case INI_IO_ABORTED:
|
case INI_IO_ABORTED:
|
||||||
|
fcpreq = tfcp_req->fcpreq;
|
||||||
|
tfcp_req->fcpreq = NULL;
|
||||||
break;
|
break;
|
||||||
case INI_IO_COMPLETED:
|
case INI_IO_COMPLETED:
|
||||||
completed = true;
|
completed = true;
|
||||||
@@ -681,10 +686,6 @@ fcloop_fcp_abort_recv_work(struct work_struct *work)
|
|||||||
nvmet_fc_rcv_fcp_abort(tfcp_req->tport->targetport,
|
nvmet_fc_rcv_fcp_abort(tfcp_req->tport->targetport,
|
||||||
&tfcp_req->tgt_fcp_req);
|
&tfcp_req->tgt_fcp_req);
|
||||||
|
|
||||||
spin_lock_irqsave(&tfcp_req->reqlock, flags);
|
|
||||||
tfcp_req->fcpreq = NULL;
|
|
||||||
spin_unlock_irqrestore(&tfcp_req->reqlock, flags);
|
|
||||||
|
|
||||||
fcloop_call_host_done(fcpreq, tfcp_req, -ECANCELED);
|
fcloop_call_host_done(fcpreq, tfcp_req, -ECANCELED);
|
||||||
/* call_host_done releases reference for abort downcall */
|
/* call_host_done releases reference for abort downcall */
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user