Skip to content

Commit

Permalink
Fnic: Fnic Driver crashed with NULL pointer reference
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Sesidhar Baddela <[email protected]>
Signed-off-by: Anil Chintalapati <[email protected]>
Signed-off-by: Christoph Hellwig <[email protected]>
  • Loading branch information
Hiral Shah authored and Christoph Hellwig committed Nov 20, 2014
1 parent 0ee7b87 commit 41df7b0
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 4 deletions.
2 changes: 1 addition & 1 deletion drivers/scsi/fnic/fnic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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: "

Expand Down
21 changes: 18 additions & 3 deletions drivers/scsi/fnic/fnic_scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -559,6 +569,11 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
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);
Expand Down

0 comments on commit 41df7b0

Please sign in to comment.