Skip to content
/ linux Public

Commit 85dbbf7

Browse files
richard-bootlingregkh
authored andcommitted
soc: fsl: qbman: fix race condition in qman_destroy_fq
[ Upstream commit 0140770 ] When QMAN_FQ_FLAG_DYNAMIC_FQID is set, there's a race condition between fq_table[fq->idx] state and freeing/allocating from the pool and WARN_ON(fq_table[fq->idx]) in qman_create_fq() gets triggered. Indeed, we can have: Thread A Thread B qman_destroy_fq() qman_create_fq() qman_release_fqid() qman_shutdown_fq() gen_pool_free() -- At this point, the fqid is available again -- qman_alloc_fqid() -- so, we can get the just-freed fqid in thread B -- fq->fqid = fqid; fq->idx = fqid * 2; WARN_ON(fq_table[fq->idx]); fq_table[fq->idx] = fq; fq_table[fq->idx] = NULL; And adding some logs between qman_release_fqid() and fq_table[fq->idx] = NULL makes the WARN_ON() trigger a lot more. To prevent that, ensure that fq_table[fq->idx] is set to NULL before gen_pool_free() is called by using smp_wmb(). Fixes: c535e92 ("soc/fsl: Introduce DPAA 1.x QMan device driver") Signed-off-by: Richard Genoud <richard.genoud@bootlin.com> Tested-by: CHAMPSEIX Thomas <thomas.champseix@alstomgroup.com> Link: https://lore.kernel.org/r/20251223072549.397625-1-richard.genoud@bootlin.com Signed-off-by: Christophe Leroy (CS GROUP) <chleroy@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 2315d32 commit 85dbbf7

File tree

1 file changed

+22
-2
lines changed

1 file changed

+22
-2
lines changed

drivers/soc/fsl/qbman/qman.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1827,18 +1827,38 @@ EXPORT_SYMBOL(qman_create_fq);
18271827

18281828
void qman_destroy_fq(struct qman_fq *fq)
18291829
{
1830+
int leaked;
1831+
18301832
/*
18311833
* We don't need to lock the FQ as it is a pre-condition that the FQ be
18321834
* quiesced. Instead, run some checks.
18331835
*/
18341836
switch (fq->state) {
18351837
case qman_fq_state_parked:
18361838
case qman_fq_state_oos:
1837-
if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID))
1838-
qman_release_fqid(fq->fqid);
1839+
/*
1840+
* There's a race condition here on releasing the fqid,
1841+
* setting the fq_table to NULL, and freeing the fqid.
1842+
* To prevent it, this order should be respected:
1843+
*/
1844+
if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID)) {
1845+
leaked = qman_shutdown_fq(fq->fqid);
1846+
if (leaked)
1847+
pr_debug("FQID %d leaked\n", fq->fqid);
1848+
}
18391849

18401850
DPAA_ASSERT(fq_table[fq->idx]);
18411851
fq_table[fq->idx] = NULL;
1852+
1853+
if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID) && !leaked) {
1854+
/*
1855+
* fq_table[fq->idx] should be set to null before
1856+
* freeing fq->fqid otherwise it could by allocated by
1857+
* qman_alloc_fqid() while still being !NULL
1858+
*/
1859+
smp_wmb();
1860+
gen_pool_free(qm_fqalloc, fq->fqid | DPAA_GENALLOC_OFF, 1);
1861+
}
18421862
return;
18431863
default:
18441864
break;

0 commit comments

Comments
 (0)