diff options
author | Dan Williams <dan.j.williams@intel.com> | 2012-01-20 18:23:07 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-02-29 16:38:09 -0500 |
commit | 840234745edaa82d514420dc1086e63536493a51 (patch) | |
tree | 62df0a1d381e6cbc910b82f0c727ff8ba6020f5b /drivers/scsi/libsas | |
parent | 9508a66f898d46e726a318469312b45e0b1d078b (diff) |
[SCSI] libsas: fix lifetime of SAS_HA_FROZEN
Until all sas_tasks are known to no longer be in-flight this flag gates late
completions from colliding with error handling. However, it must be cleared
prior to the submission of scsi_send_eh_cmnd() requests, otherwise those
commands will never be completed correctly.
This was spotted by slub debug:
=============================================================================
BUG sas_task: Objects remaining on kmem_cache_close()
-----------------------------------------------------------------------------
INFO: Slab 0xffffea001f0eba00 objects=34 used=1 fp=0xffff8807c3aecb00 flags=0x8000000000004080
Pid: 22919, comm: modprobe Not tainted 3.2.0-isci+ #2
Call Trace:
[<ffffffff810fcdcd>] slab_err+0xb0/0xd2
[<ffffffff810e1c50>] ? free_percpu+0x31/0x117
[<ffffffff81100122>] ? kzalloc+0x14/0x16
[<ffffffff81100122>] ? kzalloc+0x14/0x16
[<ffffffff81100486>] kmem_cache_destroy+0x11d/0x270
[<ffffffffa0112bdc>] sas_class_exit+0x10/0x12 [libsas]
[<ffffffff81078fba>] sys_delete_module+0x1c4/0x23c
[<ffffffff814797ba>] ? sysret_check+0x2e/0x69
[<ffffffff8126479e>] ? trace_hardirqs_on_thunk+0x3a/0x3f
[<ffffffff81479782>] system_call_fastpath+0x16/0x1b
INFO: Object 0xffff8807c3aed280 @offset=21120
INFO: Allocated in sas_alloc_task+0x22/0x90 [libsas] age=4615311 cpu=2 pid=12966
__slab_alloc.clone.3+0x1d1/0x234
kmem_cache_alloc+0x52/0x10d
sas_alloc_task+0x22/0x90 [libsas]
sas_queuecommand+0x20e/0x230 [libsas]
scsi_send_eh_cmnd+0xd1/0x30c
scsi_eh_try_stu+0x4f/0x6b
scsi_eh_ready_devs+0xba/0x6ef
sas_scsi_recover_host+0xa35/0xab1 [libsas]
scsi_error_handler+0x14b/0x5fa
kthread+0x9d/0xa5
kernel_thread_helper+0x4/0x10
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r-- | drivers/scsi/libsas/sas_scsi_host.c | 13 |
1 files changed, 7 insertions, 6 deletions
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 3701ff7e7267..fd3291337c1b 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c | |||
@@ -521,8 +521,7 @@ try_bus_reset: | |||
521 | return FAILED; | 521 | return FAILED; |
522 | } | 522 | } |
523 | 523 | ||
524 | static int sas_eh_handle_sas_errors(struct Scsi_Host *shost, | 524 | static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head *work_q) |
525 | struct list_head *work_q) | ||
526 | { | 525 | { |
527 | struct scsi_cmnd *cmd, *n; | 526 | struct scsi_cmnd *cmd, *n; |
528 | enum task_disposition res = TASK_IS_DONE; | 527 | enum task_disposition res = TASK_IS_DONE; |
@@ -658,7 +657,7 @@ static int sas_eh_handle_sas_errors(struct Scsi_Host *shost, | |||
658 | out: | 657 | out: |
659 | list_splice_tail(&done, work_q); | 658 | list_splice_tail(&done, work_q); |
660 | list_splice_tail_init(&ha->eh_ata_q, work_q); | 659 | list_splice_tail_init(&ha->eh_ata_q, work_q); |
661 | return list_empty(work_q); | 660 | return; |
662 | 661 | ||
663 | clear_q: | 662 | clear_q: |
664 | SAS_DPRINTK("--- Exit %s -- clear_q\n", __func__); | 663 | SAS_DPRINTK("--- Exit %s -- clear_q\n", __func__); |
@@ -682,10 +681,13 @@ void sas_scsi_recover_host(struct Scsi_Host *shost) | |||
682 | __func__, shost->host_busy, shost->host_failed); | 681 | __func__, shost->host_busy, shost->host_failed); |
683 | /* | 682 | /* |
684 | * Deal with commands that still have SAS tasks (i.e. they didn't | 683 | * Deal with commands that still have SAS tasks (i.e. they didn't |
685 | * complete via the normal sas_task completion mechanism) | 684 | * complete via the normal sas_task completion mechanism), |
685 | * SAS_HA_FROZEN gives eh dominion over all sas_task completion. | ||
686 | */ | 686 | */ |
687 | set_bit(SAS_HA_FROZEN, &ha->state); | 687 | set_bit(SAS_HA_FROZEN, &ha->state); |
688 | if (sas_eh_handle_sas_errors(shost, &eh_work_q)) | 688 | sas_eh_handle_sas_errors(shost, &eh_work_q); |
689 | clear_bit(SAS_HA_FROZEN, &ha->state); | ||
690 | if (list_empty(&eh_work_q)) | ||
689 | goto out; | 691 | goto out; |
690 | 692 | ||
691 | /* | 693 | /* |
@@ -699,7 +701,6 @@ void sas_scsi_recover_host(struct Scsi_Host *shost) | |||
699 | scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q); | 701 | scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q); |
700 | 702 | ||
701 | out: | 703 | out: |
702 | clear_bit(SAS_HA_FROZEN, &ha->state); | ||
703 | if (ha->lldd_max_execute_num > 1) | 704 | if (ha->lldd_max_execute_num > 1) |
704 | wake_up_process(ha->core.queue_thread); | 705 | wake_up_process(ha->core.queue_thread); |
705 | 706 | ||