Commit 41df7b02 authored by Hiral Shah's avatar Hiral Shah Committed by Christoph Hellwig

Fnic: Fnic Driver crashed with NULL pointer reference

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: default avatarHiral Shah <hishah@cisco.com>
Signed-off-by: default avatarSesidhar Baddela <sebaddel@cisco.com>
Signed-off-by: default avatarAnil Chintalapati <achintal@cisco.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent 0ee7b871
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
#define DRV_NAME "fnic" #define DRV_NAME "fnic"
#define DRV_DESCRIPTION "Cisco FCoE HBA Driver" #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 PFX DRV_NAME ": "
#define DFX DRV_NAME "%d: " #define DFX DRV_NAME "%d: "
......
...@@ -421,9 +421,10 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_ ...@@ -421,9 +421,10 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
int ret; int ret;
u64 cmd_trace; u64 cmd_trace;
int sg_count = 0; int sg_count = 0;
unsigned long flags; unsigned long flags = 0;
unsigned long ptr; unsigned long ptr;
struct fc_rport_priv *rdata; struct fc_rport_priv *rdata;
spinlock_t *io_lock = NULL;
if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_IO_BLOCKED))) if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_IO_BLOCKED)))
return SCSI_MLQUEUE_HOST_BUSY; return SCSI_MLQUEUE_HOST_BUSY;
...@@ -509,6 +510,13 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_ ...@@ -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 */ /* initialize rest of io_req */
io_req->port_id = rport->port_id; io_req->port_id = rport->port_id;
io_req->start_time = jiffies; io_req->start_time = jiffies;
...@@ -525,11 +533,9 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_ ...@@ -525,11 +533,9 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
* In case another thread cancelled the request, * In case another thread cancelled the request,
* refetch the pointer under the lock. * 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, FNIC_TRACE(fnic_queuecommand, sc->device->host->host_no,
sc->request->tag, sc, 0, 0, 0, sc->request->tag, sc, 0, 0, 0,
(((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc)));
spin_lock_irqsave(io_lock, flags);
io_req = (struct fnic_io_req *)CMD_SP(sc); io_req = (struct fnic_io_req *)CMD_SP(sc);
CMD_SP(sc) = NULL; CMD_SP(sc) = NULL;
CMD_STATE(sc) = FNIC_IOREQ_CMD_COMPLETE; CMD_STATE(sc) = FNIC_IOREQ_CMD_COMPLETE;
...@@ -538,6 +544,10 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_ ...@@ -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); fnic_release_ioreq_buf(fnic, io_req, sc);
mempool_free(io_req, fnic->io_req_pool); 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 { } else {
atomic64_inc(&fnic_stats->io_stats.active_ios); atomic64_inc(&fnic_stats->io_stats.active_ios);
atomic64_inc(&fnic_stats->io_stats.num_ios); atomic64_inc(&fnic_stats->io_stats.num_ios);
...@@ -559,6 +569,11 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_ ...@@ -559,6 +569,11 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
sc->request->tag, sc, io_req, sc->request->tag, sc, io_req,
sg_count, cmd_trace, sg_count, cmd_trace,
(((u64)CMD_FLAGS(sc) >> 32) | CMD_STATE(sc))); (((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); atomic_dec(&fnic->in_flight);
/* acquire host lock before returning to SCSI */ /* acquire host lock before returning to SCSI */
spin_lock(lp->host->host_lock); spin_lock(lp->host->host_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment