diff options
author | Giridhar Malavali <giridhar.malavali@qlogic.com> | 2010-05-28 18:08:18 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-07-27 13:01:20 -0400 |
commit | 083a469db4ecf3b286a96b5b722c37fc1affe0be (patch) | |
tree | aa9aef39e8933b5cc75e3af5a5d63352bb7e2776 /drivers | |
parent | 7e2b895b93db603ac3462175baa846ebf1be44da (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')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 1 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 31 |
2 files changed, 31 insertions, 1 deletions
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 839610909018..f8239bff0924 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 | */ |
204 | typedef struct srb { | 204 | typedef 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 c345ba716728..9e656296b757 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 | ||
801 | static void | ||
802 | sp_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 | ||
3470 | void | 3485 | void |
3471 | qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp) | 3486 | qla2x00_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 | ||
3507 | void | ||
3508 | qla2x00_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 | * |