nvme-fcloop: fix "inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage"
authorMing Lei <ming.lei@redhat.com>
Wed, 12 Apr 2023 08:49:04 +0000 (16:49 +0800)
committerChristoph Hellwig <hch@lst.de>
Thu, 13 Apr 2023 07:02:55 +0000 (09:02 +0200)
fcloop_fcp_op() could be called from flush request's ->end_io(flush_end_io) in
which the spinlock of fq->mq_flush_lock is grabbed with irq saved/disabled.

So fcloop_fcp_op() can't call spin_unlock_irq(&tfcp_req->reqlock) simply
which enables irq unconditionally.

Fixes the warning by switching to spin_lock_irqsave()/spin_unlock_irqrestore()

Fixes: c38dbbfab1bc ("nvme-fcloop: fix inconsistent lock state warnings")
Reported-by: Yi Zhang <yi.zhang@redhat.com>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Reviewed-by: Ewan D. Milne <emilne@redhat.com>
Tested-by: Yi Zhang <yi.zhang@redhat.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
drivers/nvme/target/fcloop.c

index 5c16372f3b533cc646be2225517dd8d391547b2f..c780af36c1d4a5ac90ed20150d31d65e5a8f0f41 100644 (file)
@@ -614,10 +614,11 @@ 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;
+       unsigned long flags;
        int ret = 0;
        bool aborted = false;
 
-       spin_lock_irq(&tfcp_req->reqlock);
+       spin_lock_irqsave(&tfcp_req->reqlock, flags);
        switch (tfcp_req->inistate) {
        case INI_IO_START:
                tfcp_req->inistate = INI_IO_ACTIVE;
@@ -626,11 +627,11 @@ fcloop_fcp_recv_work(struct work_struct *work)
                aborted = true;
                break;
        default:
-               spin_unlock_irq(&tfcp_req->reqlock);
+               spin_unlock_irqrestore(&tfcp_req->reqlock, flags);
                WARN_ON(1);
                return;
        }
-       spin_unlock_irq(&tfcp_req->reqlock);
+       spin_unlock_irqrestore(&tfcp_req->reqlock, flags);
 
        if (unlikely(aborted))
                ret = -ECANCELED;
@@ -655,8 +656,9 @@ fcloop_fcp_abort_recv_work(struct work_struct *work)
                container_of(work, struct fcloop_fcpreq, abort_rcv_work);
        struct nvmefc_fcp_req *fcpreq;
        bool completed = false;
+       unsigned long flags;
 
-       spin_lock_irq(&tfcp_req->reqlock);
+       spin_lock_irqsave(&tfcp_req->reqlock, flags);
        fcpreq = tfcp_req->fcpreq;
        switch (tfcp_req->inistate) {
        case INI_IO_ABORTED:
@@ -665,11 +667,11 @@ fcloop_fcp_abort_recv_work(struct work_struct *work)
                completed = true;
                break;
        default:
-               spin_unlock_irq(&tfcp_req->reqlock);
+               spin_unlock_irqrestore(&tfcp_req->reqlock, flags);
                WARN_ON(1);
                return;
        }
-       spin_unlock_irq(&tfcp_req->reqlock);
+       spin_unlock_irqrestore(&tfcp_req->reqlock, flags);
 
        if (unlikely(completed)) {
                /* remove reference taken in original abort downcall */
@@ -681,9 +683,9 @@ 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_irq(&tfcp_req->reqlock);
+       spin_lock_irqsave(&tfcp_req->reqlock, flags);
        tfcp_req->fcpreq = NULL;
-       spin_unlock_irq(&tfcp_req->reqlock);
+       spin_unlock_irqrestore(&tfcp_req->reqlock, flags);
 
        fcloop_call_host_done(fcpreq, tfcp_req, -ECANCELED);
        /* call_host_done releases reference for abort downcall */
@@ -699,11 +701,12 @@ fcloop_tgt_fcprqst_done_work(struct work_struct *work)
        struct fcloop_fcpreq *tfcp_req =
                container_of(work, struct fcloop_fcpreq, tio_done_work);
        struct nvmefc_fcp_req *fcpreq;
+       unsigned long flags;
 
-       spin_lock_irq(&tfcp_req->reqlock);
+       spin_lock_irqsave(&tfcp_req->reqlock, flags);
        fcpreq = tfcp_req->fcpreq;
        tfcp_req->inistate = INI_IO_COMPLETED;
-       spin_unlock_irq(&tfcp_req->reqlock);
+       spin_unlock_irqrestore(&tfcp_req->reqlock, flags);
 
        fcloop_call_host_done(fcpreq, tfcp_req, tfcp_req->status);
 }
@@ -807,13 +810,14 @@ fcloop_fcp_op(struct nvmet_fc_target_port *tgtport,
        u32 rsplen = 0, xfrlen = 0;
        int fcp_err = 0, active, aborted;
        u8 op = tgt_fcpreq->op;
+       unsigned long flags;
 
-       spin_lock_irq(&tfcp_req->reqlock);
+       spin_lock_irqsave(&tfcp_req->reqlock, flags);
        fcpreq = tfcp_req->fcpreq;
        active = tfcp_req->active;
        aborted = tfcp_req->aborted;
        tfcp_req->active = true;
-       spin_unlock_irq(&tfcp_req->reqlock);
+       spin_unlock_irqrestore(&tfcp_req->reqlock, flags);
 
        if (unlikely(active))
                /* illegal - call while i/o active */
@@ -821,9 +825,9 @@ fcloop_fcp_op(struct nvmet_fc_target_port *tgtport,
 
        if (unlikely(aborted)) {
                /* target transport has aborted i/o prior */
-               spin_lock_irq(&tfcp_req->reqlock);
+               spin_lock_irqsave(&tfcp_req->reqlock, flags);
                tfcp_req->active = false;
-               spin_unlock_irq(&tfcp_req->reqlock);
+               spin_unlock_irqrestore(&tfcp_req->reqlock, flags);
                tgt_fcpreq->transferred_length = 0;
                tgt_fcpreq->fcp_error = -ECANCELED;
                tgt_fcpreq->done(tgt_fcpreq);
@@ -880,9 +884,9 @@ fcloop_fcp_op(struct nvmet_fc_target_port *tgtport,
                break;
        }
 
-       spin_lock_irq(&tfcp_req->reqlock);
+       spin_lock_irqsave(&tfcp_req->reqlock, flags);
        tfcp_req->active = false;
-       spin_unlock_irq(&tfcp_req->reqlock);
+       spin_unlock_irqrestore(&tfcp_req->reqlock, flags);
 
        tgt_fcpreq->transferred_length = xfrlen;
        tgt_fcpreq->fcp_error = fcp_err;
@@ -896,15 +900,16 @@ fcloop_tgt_fcp_abort(struct nvmet_fc_target_port *tgtport,
                        struct nvmefc_tgt_fcp_req *tgt_fcpreq)
 {
        struct fcloop_fcpreq *tfcp_req = tgt_fcp_req_to_fcpreq(tgt_fcpreq);
+       unsigned long flags;
 
        /*
         * mark aborted only in case there were 2 threads in transport
         * (one doing io, other doing abort) and only kills ops posted
         * after the abort request
         */
-       spin_lock_irq(&tfcp_req->reqlock);
+       spin_lock_irqsave(&tfcp_req->reqlock, flags);
        tfcp_req->aborted = true;
-       spin_unlock_irq(&tfcp_req->reqlock);
+       spin_unlock_irqrestore(&tfcp_req->reqlock, flags);
 
        tfcp_req->status = NVME_SC_INTERNAL;
 
@@ -946,6 +951,7 @@ fcloop_fcp_abort(struct nvme_fc_local_port *localport,
        struct fcloop_ini_fcpreq *inireq = fcpreq->private;
        struct fcloop_fcpreq *tfcp_req;
        bool abortio = true;
+       unsigned long flags;
 
        spin_lock(&inireq->inilock);
        tfcp_req = inireq->tfcp_req;
@@ -958,7 +964,7 @@ fcloop_fcp_abort(struct nvme_fc_local_port *localport,
                return;
 
        /* break initiator/target relationship for io */
-       spin_lock_irq(&tfcp_req->reqlock);
+       spin_lock_irqsave(&tfcp_req->reqlock, flags);
        switch (tfcp_req->inistate) {
        case INI_IO_START:
        case INI_IO_ACTIVE:
@@ -968,11 +974,11 @@ fcloop_fcp_abort(struct nvme_fc_local_port *localport,
                abortio = false;
                break;
        default:
-               spin_unlock_irq(&tfcp_req->reqlock);
+               spin_unlock_irqrestore(&tfcp_req->reqlock, flags);
                WARN_ON(1);
                return;
        }
-       spin_unlock_irq(&tfcp_req->reqlock);
+       spin_unlock_irqrestore(&tfcp_req->reqlock, flags);
 
        if (abortio)
                /* leave the reference while the work item is scheduled */