mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-23 04:34:11 +08:00
[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>
This commit is contained in:
parent
c2cb8a5fd7
commit
d689168222
@ -552,11 +552,27 @@ static void isci_request_cleanup_completed_loiterer(
|
|||||||
|
|
||||||
if (isci_request != NULL) {
|
if (isci_request != NULL) {
|
||||||
spin_lock_irqsave(&isci_host->scic_lock, flags);
|
spin_lock_irqsave(&isci_host->scic_lock, flags);
|
||||||
|
isci_free_tag(isci_host, isci_request->io_tag);
|
||||||
|
isci_request_change_state(isci_request, unallocated);
|
||||||
list_del_init(&isci_request->dev_node);
|
list_del_init(&isci_request->dev_node);
|
||||||
spin_unlock_irqrestore(&isci_host->scic_lock, flags);
|
spin_unlock_irqrestore(&isci_host->scic_lock, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int isci_request_is_dealloc_managed(enum isci_request_status stat)
|
||||||
|
{
|
||||||
|
switch (stat) {
|
||||||
|
case aborted:
|
||||||
|
case aborting:
|
||||||
|
case terminating:
|
||||||
|
case completed:
|
||||||
|
case dead:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* isci_terminate_request_core() - This function will terminate the given
|
* isci_terminate_request_core() - This function will terminate the given
|
||||||
* request, and wait for it to complete. This function must only be called
|
* 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,
|
|||||||
enum sci_status status = SCI_SUCCESS;
|
enum sci_status status = SCI_SUCCESS;
|
||||||
bool was_terminated = false;
|
bool was_terminated = false;
|
||||||
bool needs_cleanup_handling = false;
|
bool needs_cleanup_handling = false;
|
||||||
enum isci_request_status request_status;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned long termination_completed = 1;
|
unsigned long termination_completed = 1;
|
||||||
struct completion *io_request_completion;
|
struct completion *io_request_completion;
|
||||||
@ -702,23 +717,11 @@ static void isci_terminate_request_core(struct isci_host *ihost,
|
|||||||
* needs to be detached and freed here.
|
* needs to be detached and freed here.
|
||||||
*/
|
*/
|
||||||
spin_lock_irqsave(&isci_request->state_lock, flags);
|
spin_lock_irqsave(&isci_request->state_lock, flags);
|
||||||
request_status = isci_request->status;
|
|
||||||
|
|
||||||
if ((isci_request->ttype == io_task) /* TMFs are in their own thread */
|
needs_cleanup_handling
|
||||||
&& ((request_status == aborted)
|
= isci_request_is_dealloc_managed(
|
||||||
|| (request_status == aborting)
|
isci_request->status);
|
||||||
|| (request_status == terminating)
|
|
||||||
|| (request_status == completed)
|
|
||||||
|| (request_status == dead)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
|
|
||||||
/* The completion routine won't free a request in
|
|
||||||
* the aborted/aborting/etc. states, so we do
|
|
||||||
* it here.
|
|
||||||
*/
|
|
||||||
needs_cleanup_handling = true;
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&isci_request->state_lock, flags);
|
spin_unlock_irqrestore(&isci_request->state_lock, flags);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1329,8 +1332,16 @@ isci_task_request_complete(struct isci_host *ihost,
|
|||||||
*/
|
*/
|
||||||
set_bit(IREQ_TERMINATED, &ireq->flags);
|
set_bit(IREQ_TERMINATED, &ireq->flags);
|
||||||
|
|
||||||
isci_request_change_state(ireq, unallocated);
|
/* As soon as something is in the terminate path, deallocation is
|
||||||
list_del_init(&ireq->dev_node);
|
* managed there. Note that the final non-managed state of a task
|
||||||
|
* request is "completed".
|
||||||
|
*/
|
||||||
|
if ((ireq->status == completed) ||
|
||||||
|
!isci_request_is_dealloc_managed(ireq->status)) {
|
||||||
|
isci_request_change_state(ireq, unallocated);
|
||||||
|
isci_free_tag(ihost, ireq->io_tag);
|
||||||
|
list_del_init(&ireq->dev_node);
|
||||||
|
}
|
||||||
|
|
||||||
/* The task management part completes last. */
|
/* The task management part completes last. */
|
||||||
complete(tmf_complete);
|
complete(tmf_complete);
|
||||||
|
Loading…
Reference in New Issue
Block a user