Skip to content

Commit

Permalink
[SCSI] libfc: possible race could panic system due to NULL fsp->cmd
Browse files Browse the repository at this point in the history
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 c1ecb90
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: Vasu Dev <vasu.dev@intel.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
  • Loading branch information
Vasu Dev authored and James Bottomley committed Oct 25, 2010
1 parent 3067817 commit 8b7ac2b
Showing 1 changed file with 6 additions and 12 deletions.
18 changes: 6 additions & 12 deletions drivers/scsi/libfc/fc_fcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ struct kmem_cache *scsi_pkt_cachep;
#define FC_SRB_WRITE (1 << 0)

/*
* The SCp.ptr should be tested and set under the host lock. NULL indicates
* that the command has been retruned to the scsi layer.
* The SCp.ptr should be tested and set under the scsi_pkt_queue lock
*/
#define CMD_SP(Cmnd) ((struct fc_fcp_pkt *)(Cmnd)->SCp.ptr)
#define CMD_ENTRY_STATUS(Cmnd) ((Cmnd)->SCp.have_data_in)
Expand Down Expand Up @@ -1880,8 +1879,6 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)

lport = fsp->lp;
si = fc_get_scsi_internal(lport);
if (!fsp->cmd)
return;

/*
* if can_queue ramp down is done then try can_queue ramp up
Expand All @@ -1891,11 +1888,6 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
fc_fcp_can_queue_ramp_up(lport);

sc_cmd = fsp->cmd;
fsp->cmd = NULL;

if (!sc_cmd->SCp.ptr)
return;

CMD_SCSI_STATUS(sc_cmd) = fsp->cdb_status;
switch (fsp->status_code) {
case FC_COMPLETE:
Expand Down Expand Up @@ -1976,8 +1968,8 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)

spin_lock_irqsave(&si->scsi_queue_lock, flags);
list_del(&fsp->list);
spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
sc_cmd->SCp.ptr = NULL;
spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
sc_cmd->scsi_done(sc_cmd);

/* release ref from initial allocation in queue command */
Expand All @@ -1995,6 +1987,7 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd)
{
struct fc_fcp_pkt *fsp;
struct fc_lport *lport;
struct fc_fcp_internal *si;
int rc = FAILED;
unsigned long flags;

Expand All @@ -2004,7 +1997,8 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd)
else if (!lport->link_up)
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);
if (!fsp) {
/* command completed while scsi eh was setting up */
Expand All @@ -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 */
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)) {
/* completed while we were waiting for timer to be deleted */
Expand Down

0 comments on commit 8b7ac2b

Please sign in to comment.