Module Name: src Committed By: jmcneill Date: Fri Aug 11 18:41:42 UTC 2017
Modified Files: src/sys/dev/sdmmc: ld_sdmmc.c Log Message: Defer sdmmc discard operations to the sdmmc task queue. Fixes a panic introduced by ld.c r1.102. To generate a diff of this commit: cvs rdiff -u -r1.32 -r1.33 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.32 src/sys/dev/sdmmc/ld_sdmmc.c:1.33 --- src/sys/dev/sdmmc/ld_sdmmc.c:1.32 Wed Aug 9 16:44:40 2017 +++ src/sys/dev/sdmmc/ld_sdmmc.c Fri Aug 11 18:41:42 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: ld_sdmmc.c,v 1.32 2017/08/09 16:44:40 mlelstv Exp $ */ +/* $NetBSD: ld_sdmmc.c,v 1.33 2017/08/11 18:41:42 jmcneill Exp $ */ /* * Copyright (c) 2008 KIYOHARA Takashi @@ -28,7 +28,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.32 2017/08/09 16:44:40 mlelstv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.33 2017/08/11 18:41:42 jmcneill Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -65,15 +65,24 @@ __KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v #define LD_SDMMC_IORETRIES 5 /* number of retries before giving up */ #define RECOVERYTIME hz/2 /* time to wait before retrying a cmd */ +#define LD_SDMMC_MAXQUEUECNT 4 /* number of queued bio requests */ +#define LD_SDMMC_MAXTASKCNT 8 /* number of tasks in task pool */ + struct ld_sdmmc_softc; struct ld_sdmmc_task { struct sdmmc_task task; struct ld_sdmmc_softc *task_sc; + + /* bio tasks */ struct buf *task_bp; int task_retries; /* number of xfer retry */ struct callout task_restart_ch; + + /* discard tasks */ + off_t task_pos; + off_t task_len; }; struct ld_sdmmc_softc { @@ -81,9 +90,12 @@ struct ld_sdmmc_softc { int sc_hwunit; struct sdmmc_function *sc_sf; -#define LD_SDMMC_MAXQUEUECNT 4 - struct ld_sdmmc_task sc_task[LD_SDMMC_MAXQUEUECNT]; + struct ld_sdmmc_task sc_task[LD_SDMMC_MAXTASKCNT]; pcq_t *sc_freeq; + + struct evcnt sc_ev_discard; /* discard counter */ + struct evcnt sc_ev_discarderr; /* discard error counter */ + struct evcnt sc_ev_discardbusy; /* discard busy counter */ }; static int ld_sdmmc_match(device_t, cfdata_t, void *); @@ -98,6 +110,7 @@ static int ld_sdmmc_ioctl(struct ld_soft static void ld_sdmmc_doattach(void *); static void ld_sdmmc_dobio(void *); +static void ld_sdmmc_dodiscard(void *); CFATTACH_DECL_NEW(ld_sdmmc, sizeof(struct ld_sdmmc_softc), ld_sdmmc_match, ld_sdmmc_attach, ld_sdmmc_detach, NULL); @@ -132,6 +145,13 @@ ld_sdmmc_attach(device_t parent, device_ sa->sf->cid.rev, sa->sf->cid.psn, sa->sf->cid.mdt); aprint_naive("\n"); + evcnt_attach_dynamic(&sc->sc_ev_discard, EVCNT_TYPE_MISC, + NULL, device_xname(self), "sdmmc discard count"); + evcnt_attach_dynamic(&sc->sc_ev_discarderr, EVCNT_TYPE_MISC, + NULL, device_xname(self), "sdmmc discard errors"); + evcnt_attach_dynamic(&sc->sc_ev_discardbusy, EVCNT_TYPE_MISC, + NULL, device_xname(self), "sdmmc discard busy"); + const int ntask = __arraycount(sc->sc_task); sc->sc_freeq = pcq_create(ntask, KM_SLEEP); for (i = 0; i < ntask; i++) { @@ -213,6 +233,9 @@ ld_sdmmc_detach(device_t dev, int flags) callout_destroy(&sc->sc_task[i].task_restart_ch); pcq_destroy(sc->sc_freeq); + evcnt_detach(&sc->sc_ev_discard); + evcnt_detach(&sc->sc_ev_discarderr); + evcnt_detach(&sc->sc_ev_discardbusy); return 0; } @@ -314,12 +337,44 @@ ld_sdmmc_dump(struct ld_softc *ld, void blkcnt * ld->sc_secsize); } +static void +ld_sdmmc_dodiscard(void *arg) +{ + struct ld_sdmmc_task *task = arg; + struct ld_sdmmc_softc *sc = task->task_sc; + const off_t pos = task->task_pos; + const off_t len = task->task_len; + int error; + + /* An error from discard is non-fatal */ + error = sdmmc_mem_discard(sc->sc_sf, pos, len); + if (error != 0) + sc->sc_ev_discarderr.ev_count++; + else + sc->sc_ev_discard.ev_count++; + + pcq_put(sc->sc_freeq, task); +} + static int ld_sdmmc_discard(struct ld_softc *ld, off_t pos, off_t len) { struct ld_sdmmc_softc *sc = device_private(ld->sc_dv); + struct ld_sdmmc_task *task = pcq_get(sc->sc_freeq); + + if (task == NULL) { + sc->sc_ev_discardbusy.ev_count++; + return 0; + } - return sdmmc_mem_discard(sc->sc_sf, pos, len); + task->task_pos = pos; + task->task_len = len; + + sdmmc_init_task(&task->task, ld_sdmmc_dodiscard, task); + + sdmmc_add_task(sc->sc_sf->sc, &task->task); + + return 0; } static int