dmaengine: idxd: fix missed completion on abort path
[ Upstream commit8affd8a4b5
] Ming reported that with the abort path of the descriptor submission, there can be a window where a completed descriptor can be missed to be completed by the irq completion thread: CPU A CPU B Submit (successful) Submit (fail) irq_process_work_list() // empty llist_abort_desc() // remove all descs from pending list irq_process_pending_llist() // empty exit idxd_wq_thread() with no processing Add opportunistic descriptor completion in the abort path in order to remove the missed completion. Fixes:6b4b87f2c3
("dmaengine: idxd: fix submission race window") Reported-by: Ming Li <ming4.li@intel.com> Signed-off-by: Dave Jiang <dave.jiang@intel.com> Link: https://lore.kernel.org/r/163898288714.443911.16084982766671976640.stgit@djiang5-desk3.ch.intel.com Signed-off-by: Vinod Koul <vkoul@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Родитель
088e4d7dba
Коммит
ee3701c4d9
|
@ -106,6 +106,7 @@ static void llist_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie,
|
||||||
{
|
{
|
||||||
struct idxd_desc *d, *t, *found = NULL;
|
struct idxd_desc *d, *t, *found = NULL;
|
||||||
struct llist_node *head;
|
struct llist_node *head;
|
||||||
|
LIST_HEAD(flist);
|
||||||
|
|
||||||
desc->completion->status = IDXD_COMP_DESC_ABORT;
|
desc->completion->status = IDXD_COMP_DESC_ABORT;
|
||||||
/*
|
/*
|
||||||
|
@ -120,7 +121,11 @@ static void llist_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie,
|
||||||
found = desc;
|
found = desc;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
list_add_tail(&desc->list, &ie->work_list);
|
|
||||||
|
if (d->completion->status)
|
||||||
|
list_add_tail(&d->list, &flist);
|
||||||
|
else
|
||||||
|
list_add_tail(&d->list, &ie->work_list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +135,17 @@ static void llist_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie,
|
||||||
|
|
||||||
if (found)
|
if (found)
|
||||||
complete_desc(found, IDXD_COMPLETE_ABORT);
|
complete_desc(found, IDXD_COMPLETE_ABORT);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* complete_desc() will return desc to allocator and the desc can be
|
||||||
|
* acquired by a different process and the desc->list can be modified.
|
||||||
|
* Delete desc from list so the list trasversing does not get corrupted
|
||||||
|
* by the other process.
|
||||||
|
*/
|
||||||
|
list_for_each_entry_safe(d, t, &flist, list) {
|
||||||
|
list_del_init(&d->list);
|
||||||
|
complete_desc(d, IDXD_COMPLETE_NORMAL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc)
|
int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче