Module Name: src
Committed By: jmcneill
Date: Tue Jun 6 21:01:07 UTC 2017
Modified Files:
src/sys/dev/sdmmc: ld_sdmmc.c
Log Message:
Fix a race between ld_sdmmc_start and ld_sdmmc_dobio that could result in
tasks getting lost from the task queue. The symptom of this is a NULL
deref in ld_sdmmc_start since the code assumes that a task will always be
available from the pool.
This changes the code to use pcq(9) instead of a TAILQ to manage the free
task list.
To generate a diff of this commit:
cvs rdiff -u -r1.26 -r1.27 src/sys/dev/sdmmc/ld_sdmmc.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/sdmmc/ld_sdmmc.c
diff -u src/sys/dev/sdmmc/ld_sdmmc.c:1.26 src/sys/dev/sdmmc/ld_sdmmc.c:1.27
--- src/sys/dev/sdmmc/ld_sdmmc.c:1.26 Sat Apr 22 14:19:36 2017
+++ src/sys/dev/sdmmc/ld_sdmmc.c Tue Jun 6 21:01:07 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ld_sdmmc.c,v 1.26 2017/04/22 14:19:36 jmcneill Exp $ */
+/* $NetBSD: ld_sdmmc.c,v 1.27 2017/06/06 21:01:07 jmcneill Exp $ */
/*
* Copyright (c) 2008 KIYOHARA Takashi
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.26 2017/04/22 14:19:36 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.27 2017/06/06 21:01:07 jmcneill Exp $");
#ifdef _KERNEL_OPT
#include "opt_sdmmc.h"
@@ -48,6 +48,7 @@ __KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v
#include <sys/kthread.h>
#include <sys/syslog.h>
#include <sys/module.h>
+#include <sys/pcq.h>
#include <dev/ldvar.h>
@@ -82,7 +83,7 @@ struct ld_sdmmc_softc {
struct sdmmc_function *sc_sf;
#define LD_SDMMC_MAXQUEUECNT 4
struct ld_sdmmc_task sc_task[LD_SDMMC_MAXQUEUECNT];
- TAILQ_HEAD(, sdmmc_task) sc_freeq;
+ pcq_t *sc_freeq;
};
static int ld_sdmmc_match(device_t, cfdata_t, void *);
@@ -129,12 +130,13 @@ ld_sdmmc_attach(device_t parent, device_
sa->sf->cid.rev, sa->sf->cid.psn, sa->sf->cid.mdt);
aprint_naive("\n");
- TAILQ_INIT(&sc->sc_freeq);
- for (i = 0; i < __arraycount(sc->sc_task); i++) {
+ const int ntask = __arraycount(sc->sc_task);
+ sc->sc_freeq = pcq_create(ntask, KM_SLEEP);
+ for (i = 0; i < ntask; i++) {
task = &sc->sc_task[i];
task->task_sc = sc;
- callout_init(&task->task_restart_ch, 0);
- TAILQ_INSERT_TAIL(&sc->sc_freeq, &task->task, next);
+ callout_init(&task->task_restart_ch, CALLOUT_MPSAFE);
+ pcq_put(sc->sc_freeq, task);
}
sc->sc_hwunit = 0; /* always 0? */
@@ -193,6 +195,8 @@ ld_sdmmc_detach(device_t dev, int flags)
for (i = 0; i < __arraycount(sc->sc_task); i++)
callout_destroy(&sc->sc_task[i].task_restart_ch);
+ pcq_destroy(sc->sc_freeq);
+
return 0;
}
@@ -200,9 +204,10 @@ static int
ld_sdmmc_start(struct ld_softc *ld, struct buf *bp)
{
struct ld_sdmmc_softc *sc = device_private(ld->sc_dv);
- struct ld_sdmmc_task *task = (void *)TAILQ_FIRST(&sc->sc_freeq);
+ struct ld_sdmmc_task *task = pcq_get(sc->sc_freeq);
- TAILQ_REMOVE(&sc->sc_freeq, &task->task, next);
+ if (task == NULL)
+ return EAGAIN;
task->task_bp = bp;
task->task_retries = 0;
@@ -278,7 +283,7 @@ ld_sdmmc_dobio(void *arg)
}
done:
- TAILQ_INSERT_TAIL(&sc->sc_freeq, &task->task, next);
+ pcq_put(sc->sc_freeq, task);
lddone(&sc->sc_ld, bp);
}