aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorGiridhar Malavali <giridhar.malavali@qlogic.com>2010-05-28 18:08:18 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-07-27 13:01:20 -0400
commit083a469db4ecf3b286a96b5b722c37fc1affe0be (patch)
treeaa9aef39e8933b5cc75e3af5a5d63352bb7e2776 /drivers/scsi
parent7e2b895b93db603ac3462175baa846ebf1be44da (diff)
[SCSI] qla2xxx: Correct use-after-free oops seen during EH-abort.
Hold a reference to the srb (sp) while aborting an I/O -- as the I/O can/will complete from within the interrupt-context. Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com> Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h1
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c31
2 files changed, 31 insertions, 1 deletions
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 83961090901..f8239bff092 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -202,6 +202,7 @@ struct sd_dif_tuple {
202 * SCSI Request Block 202 * SCSI Request Block
203 */ 203 */
204typedef struct srb { 204typedef struct srb {
205 atomic_t ref_count;
205 struct fc_port *fcport; 206 struct fc_port *fcport;
206 uint32_t handle; 207 uint32_t handle;
207 208
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index c345ba71672..9e656296b75 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -517,6 +517,7 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport,
517 if (!sp) 517 if (!sp)
518 return sp; 518 return sp;
519 519
520 atomic_set(&sp->ref_count, 1);
520 sp->fcport = fcport; 521 sp->fcport = fcport;
521 sp->cmd = cmd; 522 sp->cmd = cmd;
522 sp->flags = 0; 523 sp->flags = 0;
@@ -797,6 +798,12 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *vha)
797 return (return_status); 798 return (return_status);
798} 799}
799 800
801static void
802sp_get(struct srb *sp)
803{
804 atomic_inc(&sp->ref_count);
805}
806
800/************************************************************************** 807/**************************************************************************
801* qla2xxx_eh_abort 808* qla2xxx_eh_abort
802* 809*
@@ -825,6 +832,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
825 struct qla_hw_data *ha = vha->hw; 832 struct qla_hw_data *ha = vha->hw;
826 struct req_que *req = vha->req; 833 struct req_que *req = vha->req;
827 srb_t *spt; 834 srb_t *spt;
835 int got_ref = 0;
828 836
829 fc_block_scsi_eh(cmd); 837 fc_block_scsi_eh(cmd);
830 838
@@ -856,6 +864,10 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
856 DEBUG2(printk("%s(%ld): aborting sp %p from RISC." 864 DEBUG2(printk("%s(%ld): aborting sp %p from RISC."
857 " pid=%ld.\n", __func__, vha->host_no, sp, serial)); 865 " pid=%ld.\n", __func__, vha->host_no, sp, serial));
858 866
867 /* Get a reference to the sp and drop the lock.*/
868 sp_get(sp);
869 got_ref++;
870
859 spin_unlock_irqrestore(&ha->hardware_lock, flags); 871 spin_unlock_irqrestore(&ha->hardware_lock, flags);
860 if (ha->isp_ops->abort_command(sp)) { 872 if (ha->isp_ops->abort_command(sp)) {
861 DEBUG2(printk("%s(%ld): abort_command " 873 DEBUG2(printk("%s(%ld): abort_command "
@@ -881,6 +893,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
881 } 893 }
882 } 894 }
883 895
896 if (got_ref)
897 qla2x00_sp_compl(ha, sp);
898
884 qla_printk(KERN_INFO, ha, 899 qla_printk(KERN_INFO, ha,
885 "scsi(%ld:%d:%d): Abort command issued -- %d %lx %x.\n", 900 "scsi(%ld:%d:%d): Abort command issued -- %d %lx %x.\n",
886 vha->host_no, id, lun, wait, serial, ret); 901 vha->host_no, id, lun, wait, serial, ret);
@@ -3468,7 +3483,7 @@ qla2x00_sp_free_dma(srb_t *sp)
3468} 3483}
3469 3484
3470void 3485void
3471qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp) 3486qla2x00_sp_final_compl(struct qla_hw_data *ha, srb_t *sp)
3472{ 3487{
3473 struct scsi_cmnd *cmd = sp->cmd; 3488 struct scsi_cmnd *cmd = sp->cmd;
3474 3489
@@ -3489,6 +3504,20 @@ qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp)
3489 cmd->scsi_done(cmd); 3504 cmd->scsi_done(cmd);
3490} 3505}
3491 3506
3507void
3508qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp)
3509{
3510 if (atomic_read(&sp->ref_count) == 0) {
3511 DEBUG2(qla_printk(KERN_WARNING, ha,
3512 "SP reference-count to ZERO -- sp=%p\n", sp));
3513 DEBUG2(BUG());
3514 return;
3515 }
3516 if (!atomic_dec_and_test(&sp->ref_count))
3517 return;
3518 qla2x00_sp_final_compl(ha, sp);
3519}
3520
3492/************************************************************************** 3521/**************************************************************************
3493* qla2x00_timer 3522* qla2x00_timer
3494* 3523*