fix a another driver bug related with tsleep() during detaching that

this also can be happened if we pull the USN stick out forcibly.

Currently the ZyDAS driver uses tsleep() when it try to query a read
command to the device and it'd make a timeout if the device doesn't
response within about 1 sec.

In a case of that the USB stick is gone by hand and the driver's
scanning with changing the channel numbers, the thread which is sleeping
until a command requested is responded can be waked up after all
detaching routines finished that means the zyd softc already freed.
Tring to touch the softc freed by the wakeup thread makes a panic.

So make sure that all sleeping threads should be waken up before the
detach is completed and any other new requests to the device should be
prevented.
This commit is contained in:
weongyo 2008-09-19 07:40:30 +00:00
parent 8e8ffe74e6
commit c9d141b060

View File

@ -234,6 +234,7 @@ static void zyd_scantask(void *);
static void zyd_scan_start(struct ieee80211com *);
static void zyd_scan_end(struct ieee80211com *);
static void zyd_set_channel(struct ieee80211com *);
static void zyd_wakeup(struct zyd_softc *);
static int
zyd_match(device_t dev)
@ -451,9 +452,6 @@ zyd_detach(device_t dev)
if (!device_is_attached(dev))
return 0;
/* set a flag to indicate we're detaching. */
sc->sc_flags |= ZYD_FLAG_DETACHING;
/* protect a race when we have listeners related with the driver. */
ifp->if_flags &= ~IFF_UP;
@ -461,10 +459,14 @@ zyd_detach(device_t dev)
bpfdetach(ifp);
ieee80211_ifdetach(ic);
/* set a flag to indicate we're detaching. */
sc->sc_flags |= ZYD_FLAG_DETACHING;
usb_rem_task(sc->sc_udev, &sc->sc_scantask);
usb_rem_task(sc->sc_udev, &sc->sc_task);
callout_stop(&sc->sc_watchdog_ch);
zyd_wakeup(sc);
zyd_close_pipes(sc);
if_free(ifp);
@ -790,6 +792,9 @@ zyd_cmd(struct zyd_softc *sc, uint16_t code, const void *idata, int ilen,
uint16_t xferflags;
usbd_status error;
if (sc->sc_flags & ZYD_FLAG_DETACHING)
return ENXIO;
if ((xfer = usbd_alloc_xfer(sc->sc_udev)) == NULL)
return ENOMEM;
@ -2748,9 +2753,6 @@ zyd_scantask(void *arg)
struct ifnet *ifp = sc->sc_ifp;
struct ieee80211com *ic = ifp->if_l2com;
if (sc->sc_flags & ZYD_FLAG_DETACHING)
return;
ZYD_LOCK(sc);
switch (sc->sc_scan_action) {
@ -2779,6 +2781,16 @@ zyd_scantask(void *arg)
ZYD_UNLOCK(sc);
}
static void
zyd_wakeup(struct zyd_softc *sc)
{
struct rq *rqp;
STAILQ_FOREACH(rqp, &sc->sc_rqh, rq) {
wakeup(rqp->odata); /* wakeup sleeping caller */
}
}
static device_method_t zyd_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, zyd_match),