diff options
author | Jeff Skirvin <jeffrey.d.skirvin@intel.com> | 2011-10-27 18:05:01 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2011-10-31 05:16:04 -0400 |
commit | d6891682220c18c01bf6838f30e37342c38fde44 (patch) | |
tree | ad0c61215cbc9de6c82e95825923f95ebc2532a1 /drivers/scsi | |
parent | c2cb8a5fd7d5d8729a4fc25937c4d6564f9a7aa3 (diff) |
[SCSI] isci: Fix tag leak in tasks and terminated requests.
Make sure terminated requests and completed task tags are freed.
Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/isci/task.c | 51 |
1 files changed, 31 insertions, 20 deletions
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index e8cf17b024a4..7180b048c34b 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c | |||
@@ -552,11 +552,27 @@ static void isci_request_cleanup_completed_loiterer( | |||
552 | 552 | ||
553 | if (isci_request != NULL) { | 553 | if (isci_request != NULL) { |
554 | spin_lock_irqsave(&isci_host->scic_lock, flags); | 554 | spin_lock_irqsave(&isci_host->scic_lock, flags); |
555 | isci_free_tag(isci_host, isci_request->io_tag); | ||
556 | isci_request_change_state(isci_request, unallocated); | ||
555 | list_del_init(&isci_request->dev_node); | 557 | list_del_init(&isci_request->dev_node); |
556 | spin_unlock_irqrestore(&isci_host->scic_lock, flags); | 558 | spin_unlock_irqrestore(&isci_host->scic_lock, flags); |
557 | } | 559 | } |
558 | } | 560 | } |
559 | 561 | ||
562 | static int isci_request_is_dealloc_managed(enum isci_request_status stat) | ||
563 | { | ||
564 | switch (stat) { | ||
565 | case aborted: | ||
566 | case aborting: | ||
567 | case terminating: | ||
568 | case completed: | ||
569 | case dead: | ||
570 | return true; | ||
571 | default: | ||
572 | return false; | ||
573 | } | ||
574 | } | ||
575 | |||
560 | /** | 576 | /** |
561 | * isci_terminate_request_core() - This function will terminate the given | 577 | * isci_terminate_request_core() - This function will terminate the given |
562 | * request, and wait for it to complete. This function must only be called | 578 | * request, and wait for it to complete. This function must only be called |
@@ -574,7 +590,6 @@ static void isci_terminate_request_core(struct isci_host *ihost, | |||
574 | enum sci_status status = SCI_SUCCESS; | 590 | enum sci_status status = SCI_SUCCESS; |
575 | bool was_terminated = false; | 591 | bool was_terminated = false; |
576 | bool needs_cleanup_handling = false; | 592 | bool needs_cleanup_handling = false; |
577 | enum isci_request_status request_status; | ||
578 | unsigned long flags; | 593 | unsigned long flags; |
579 | unsigned long termination_completed = 1; | 594 | unsigned long termination_completed = 1; |
580 | struct completion *io_request_completion; | 595 | struct completion *io_request_completion; |
@@ -702,23 +717,11 @@ static void isci_terminate_request_core(struct isci_host *ihost, | |||
702 | * needs to be detached and freed here. | 717 | * needs to be detached and freed here. |
703 | */ | 718 | */ |
704 | spin_lock_irqsave(&isci_request->state_lock, flags); | 719 | spin_lock_irqsave(&isci_request->state_lock, flags); |
705 | request_status = isci_request->status; | 720 | |
706 | 721 | needs_cleanup_handling | |
707 | if ((isci_request->ttype == io_task) /* TMFs are in their own thread */ | 722 | = isci_request_is_dealloc_managed( |
708 | && ((request_status == aborted) | 723 | isci_request->status); |
709 | || (request_status == aborting) | 724 | |
710 | || (request_status == terminating) | ||
711 | || (request_status == completed) | ||
712 | || (request_status == dead) | ||
713 | ) | ||
714 | ) { | ||
715 | |||
716 | /* The completion routine won't free a request in | ||
717 | * the aborted/aborting/etc. states, so we do | ||
718 | * it here. | ||
719 | */ | ||
720 | needs_cleanup_handling = true; | ||
721 | } | ||
722 | spin_unlock_irqrestore(&isci_request->state_lock, flags); | 725 | spin_unlock_irqrestore(&isci_request->state_lock, flags); |
723 | 726 | ||
724 | } | 727 | } |
@@ -1329,8 +1332,16 @@ isci_task_request_complete(struct isci_host *ihost, | |||
1329 | */ | 1332 | */ |
1330 | set_bit(IREQ_TERMINATED, &ireq->flags); | 1333 | set_bit(IREQ_TERMINATED, &ireq->flags); |
1331 | 1334 | ||
1332 | isci_request_change_state(ireq, unallocated); | 1335 | /* As soon as something is in the terminate path, deallocation is |
1333 | list_del_init(&ireq->dev_node); | 1336 | * managed there. Note that the final non-managed state of a task |
1337 | * request is "completed". | ||
1338 | */ | ||
1339 | if ((ireq->status == completed) || | ||
1340 | !isci_request_is_dealloc_managed(ireq->status)) { | ||
1341 | isci_request_change_state(ireq, unallocated); | ||
1342 | isci_free_tag(ihost, ireq->io_tag); | ||
1343 | list_del_init(&ireq->dev_node); | ||
1344 | } | ||
1334 | 1345 | ||
1335 | /* The task management part completes last. */ | 1346 | /* The task management part completes last. */ |
1336 | complete(tmf_complete); | 1347 | complete(tmf_complete); |