Fnic: Fnic Driver crashed with NULL pointer reference
authorHiral Shah <hishah@cisco.com>
Mon, 10 Nov 2014 20:54:36 +0000 (12:54 -0800)
committerChristoph Hellwig <hch@lst.de>
Thu, 20 Nov 2014 08:11:00 +0000 (09:11 +0100)
When issuing I/O request, if the I/O completes before returning from
fnic_queuecommand(), we may be referencing scsi_cmnd structure that may
be freed by interrupt handler. Acquring IO lock would synchronize
fnic_queuecommand and interrupt handler.

- Increment fnic version from 1.6.0.15 to 1.6.0.16

Signed-off-by: Hiral Shah <hishah@cisco.com>
Signed-off-by: Sesidhar Baddela <sebaddel@cisco.com>
Signed-off-by: Anil Chintalapati <achintal@cisco.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
drivers/scsi/fnic/fnic.h
drivers/scsi/fnic/fnic_scsi.c

index 977960b03c9fb03e70b77f6c446c31ccc7b4c8c8..3b73b96619e2deeb82e203927f57904913a51dff 100644 (file)
@@ -39,7 +39,7 @@
 
 #define DRV_NAME               "fnic"
 #define DRV_DESCRIPTION                "Cisco FCoE HBA Driver"
-#define DRV_VERSION            "1.6.0.15"
+#define DRV_VERSION            "1.6.0.16"
 #define PFX                    DRV_NAME ": "
 #define DFX                     DRV_NAME "%d: "
 
index 29d23a3c068679aaf7a61188c9e4e3a818f7da00..2097de42a14775c1b164485482e834198a77f474 100644 (file)
@@ -421,9 +421,10 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
        int ret;
        u64 cmd_trace;
        int sg_count = 0;
-       unsigned long flags;
+       unsigned long flags = 0;
        unsigned long ptr;
        struct fc_rport_priv *rdata;
+       spinlock_t *io_lock = NULL;
 
        if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_IO_BLOCKED)))
                return SCSI_MLQUEUE_HOST_BUSY;
@@ -509,6 +510,13 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
                }
        }
 
+       /*
+       * Will acquire lock defore setting to IO initialized.
+       */
+
+       io_lock = fnic_io_lock_hash(fnic, sc);
+       spin_lock_irqsave(io_lock, flags);
+
        /* initialize rest of io_req */
        io_req->port_id = rport->port_id;
        io_req->start_time = jiffies;
@@ -525,11 +533,9 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
                 * In case another thread cancelled the request,
                 * refetch the pointer under the lock.
                 */
-               spinlock_t *io_lock = fnic_io_lock_hash(fnic, sc);
                FNIC_TRACE(fnic_queuecommand, sc->device->host->host_no,
                          sc->request->tag, sc, 0, 0, 0,
                          (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc)));
-               spin_lock_irqsave(io_lock, flags);
                io_req = (struct fnic_io_req *)CMD_SP(sc);
                CMD_SP(sc) = NULL;
                CMD_STATE(sc) = FNIC_IOREQ_CMD_COMPLETE;
@@ -538,6 +544,10 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
                        fnic_release_ioreq_buf(fnic, io_req, sc);
                        mempool_free(io_req, fnic->io_req_pool);
                }
+               atomic_dec(&fnic->in_flight);
+               /* acquire host lock before returning to SCSI */
+               spin_lock(lp->host->host_lock);
+               return ret;
        } else {
                atomic64_inc(&fnic_stats->io_stats.active_ios);
                atomic64_inc(&fnic_stats->io_stats.num_ios);
@@ -559,6 +569,11 @@ out:
                  sc->request->tag, sc, io_req,
                  sg_count, cmd_trace,
                  (((u64)CMD_FLAGS(sc) >> 32) | CMD_STATE(sc)));
+
+       /* if only we issued IO, will we have the io lock */
+       if (CMD_FLAGS(sc) & FNIC_IO_INITIALIZED)
+               spin_unlock_irqrestore(io_lock, flags);
+
        atomic_dec(&fnic->in_flight);
        /* acquire host lock before returning to SCSI */
        spin_lock(lp->host->host_lock);