Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dmaengine: idxd: fix missed completion on abort path

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: 6b4b87f2c31a ("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>

authored by

Dave Jiang and committed by
Vinod Koul
8affd8a4 80936d68

+17 -1
+17 -1
drivers/dma/idxd/submit.c
··· 106 106 { 107 107 struct idxd_desc *d, *t, *found = NULL; 108 108 struct llist_node *head; 109 + LIST_HEAD(flist); 109 110 110 111 desc->completion->status = IDXD_COMP_DESC_ABORT; 111 112 /* ··· 121 120 found = desc; 122 121 continue; 123 122 } 124 - list_add_tail(&desc->list, &ie->work_list); 123 + 124 + if (d->completion->status) 125 + list_add_tail(&d->list, &flist); 126 + else 127 + list_add_tail(&d->list, &ie->work_list); 125 128 } 126 129 } 127 130 ··· 135 130 136 131 if (found) 137 132 complete_desc(found, IDXD_COMPLETE_ABORT); 133 + 134 + /* 135 + * complete_desc() will return desc to allocator and the desc can be 136 + * acquired by a different process and the desc->list can be modified. 137 + * Delete desc from list so the list trasversing does not get corrupted 138 + * by the other process. 139 + */ 140 + list_for_each_entry_safe(d, t, &flist, list) { 141 + list_del_init(&d->list); 142 + complete_desc(d, IDXD_COMPLETE_NORMAL); 143 + } 138 144 } 139 145 140 146 int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc)