]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
nvmet-fcloop: access fcpreq only when holding reqlock
authorDaniel Wagner <wagi@kernel.org>
Wed, 7 May 2025 12:23:03 +0000 (14:23 +0200)
committerChristoph Hellwig <hch@lst.de>
Tue, 20 May 2025 03:34:26 +0000 (05:34 +0200)
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>
drivers/nvme/target/fcloop.c

index 8af809ce963ad6ea8b042e6e24d45e74f57b1d4d..f0c0d95b8dde82d36a50a9189edd2b700861fcfe 100644 (file)
@@ -619,12 +619,13 @@ fcloop_fcp_recv_work(struct work_struct *work)
 {
        struct fcloop_fcpreq *tfcp_req =
                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;
        int ret = 0;
        bool aborted = false;
 
        spin_lock_irqsave(&tfcp_req->reqlock, flags);
+       fcpreq = tfcp_req->fcpreq;
        switch (tfcp_req->inistate) {
        case INI_IO_START:
                tfcp_req->inistate = INI_IO_ACTIVE;
@@ -639,16 +640,19 @@ fcloop_fcp_recv_work(struct work_struct *work)
        }
        spin_unlock_irqrestore(&tfcp_req->reqlock, flags);
 
-       if (unlikely(aborted))
-               ret = -ECANCELED;
-       else {
-               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(aborted)) {
+               /* the abort handler will call fcloop_call_host_done */
+               return;
+       }
+
+       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)
                fcloop_call_host_done(fcpreq, tfcp_req, ret);
 }
@@ -663,9 +667,10 @@ fcloop_fcp_abort_recv_work(struct work_struct *work)
        unsigned long flags;
 
        spin_lock_irqsave(&tfcp_req->reqlock, flags);
-       fcpreq = tfcp_req->fcpreq;
        switch (tfcp_req->inistate) {
        case INI_IO_ABORTED:
+               fcpreq = tfcp_req->fcpreq;
+               tfcp_req->fcpreq = NULL;
                break;
        case INI_IO_COMPLETED:
                completed = true;
@@ -688,10 +693,6 @@ fcloop_fcp_abort_recv_work(struct work_struct *work)
                nvmet_fc_rcv_fcp_abort(tfcp_req->tport->targetport,
                                        &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);
        /* call_host_done releases reference for abort downcall */
 }