Commit 8b7ac2bb authored by Vasu Dev's avatar Vasu Dev Committed by James Bottomley

[SCSI] libfc: possible race could panic system due to NULL fsp->cmd

It is unlikely but in case if it hits then it would cause panic
due to null cmd ptr, so far only one instance seen recently with
ESX though this was introduced long ago with this commit:-

commit c1ecb90a
Author: Chris Leech <christopher.leech@intel.com>
Date:   Thu Dec 10 09:59:26 2009 -0800
[SCSI] libfc: reduce hold time on SCSI host lock

Currently fsp->cmd is set to NULL w/o scsi_queue_lock before
dequeuing from scsi_pkt_queue and that could cause NULL
fsp->cmd in fc_fcp_cleanup_each_cmd for cmd completing
with fsp->cmd = NULL after fc_fcp_cleanup_each_cmd taken
reference. No need to set fsp->cmd to NULL as this is also
protected by fc_fcp_lock_pkt(), for above race the
fc_fcp_lock_pkt() in fc_fcp_cleanup_each_cmd() will fail
as that cmd is  already done.

Mike mentioned same issue at
http://www.open-fcoe.org/pipermail/devel/2010-September/010533.html

Similarly moved sc_cmd->SCp.ptr = NULL under scsi_queue_lock so
that scsi abort error handler won't abort on completed cmds.
Signed-off-by: default avatarVasu Dev <vasu.dev@intel.com>
Signed-off-by: default avatarRobert Love <robert.w.love@intel.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 3067817a
...@@ -58,8 +58,7 @@ struct kmem_cache *scsi_pkt_cachep; ...@@ -58,8 +58,7 @@ struct kmem_cache *scsi_pkt_cachep;
#define FC_SRB_WRITE (1 << 0) #define FC_SRB_WRITE (1 << 0)
/* /*
* The SCp.ptr should be tested and set under the host lock. NULL indicates * The SCp.ptr should be tested and set under the scsi_pkt_queue lock
* that the command has been retruned to the scsi layer.
*/ */
#define CMD_SP(Cmnd) ((struct fc_fcp_pkt *)(Cmnd)->SCp.ptr) #define CMD_SP(Cmnd) ((struct fc_fcp_pkt *)(Cmnd)->SCp.ptr)
#define CMD_ENTRY_STATUS(Cmnd) ((Cmnd)->SCp.have_data_in) #define CMD_ENTRY_STATUS(Cmnd) ((Cmnd)->SCp.have_data_in)
...@@ -1880,8 +1879,6 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp) ...@@ -1880,8 +1879,6 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
lport = fsp->lp; lport = fsp->lp;
si = fc_get_scsi_internal(lport); si = fc_get_scsi_internal(lport);
if (!fsp->cmd)
return;
/* /*
* if can_queue ramp down is done then try can_queue ramp up * if can_queue ramp down is done then try can_queue ramp up
...@@ -1891,11 +1888,6 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp) ...@@ -1891,11 +1888,6 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
fc_fcp_can_queue_ramp_up(lport); fc_fcp_can_queue_ramp_up(lport);
sc_cmd = fsp->cmd; sc_cmd = fsp->cmd;
fsp->cmd = NULL;
if (!sc_cmd->SCp.ptr)
return;
CMD_SCSI_STATUS(sc_cmd) = fsp->cdb_status; CMD_SCSI_STATUS(sc_cmd) = fsp->cdb_status;
switch (fsp->status_code) { switch (fsp->status_code) {
case FC_COMPLETE: case FC_COMPLETE:
...@@ -1976,8 +1968,8 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp) ...@@ -1976,8 +1968,8 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
spin_lock_irqsave(&si->scsi_queue_lock, flags); spin_lock_irqsave(&si->scsi_queue_lock, flags);
list_del(&fsp->list); list_del(&fsp->list);
spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
sc_cmd->SCp.ptr = NULL; sc_cmd->SCp.ptr = NULL;
spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
sc_cmd->scsi_done(sc_cmd); sc_cmd->scsi_done(sc_cmd);
/* release ref from initial allocation in queue command */ /* release ref from initial allocation in queue command */
...@@ -1995,6 +1987,7 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd) ...@@ -1995,6 +1987,7 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd)
{ {
struct fc_fcp_pkt *fsp; struct fc_fcp_pkt *fsp;
struct fc_lport *lport; struct fc_lport *lport;
struct fc_fcp_internal *si;
int rc = FAILED; int rc = FAILED;
unsigned long flags; unsigned long flags;
...@@ -2004,7 +1997,8 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd) ...@@ -2004,7 +1997,8 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd)
else if (!lport->link_up) else if (!lport->link_up)
return rc; return rc;
spin_lock_irqsave(lport->host->host_lock, flags); si = fc_get_scsi_internal(lport);
spin_lock_irqsave(&si->scsi_queue_lock, flags);
fsp = CMD_SP(sc_cmd); fsp = CMD_SP(sc_cmd);
if (!fsp) { if (!fsp) {
/* command completed while scsi eh was setting up */ /* command completed while scsi eh was setting up */
...@@ -2013,7 +2007,7 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd) ...@@ -2013,7 +2007,7 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd)
} }
/* grab a ref so the fsp and sc_cmd cannot be relased from under us */ /* grab a ref so the fsp and sc_cmd cannot be relased from under us */
fc_fcp_pkt_hold(fsp); fc_fcp_pkt_hold(fsp);
spin_unlock_irqrestore(lport->host->host_lock, flags); spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
if (fc_fcp_lock_pkt(fsp)) { if (fc_fcp_lock_pkt(fsp)) {
/* completed while we were waiting for timer to be deleted */ /* completed while we were waiting for timer to be deleted */
......
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