diff options
author | Jacob Meuser <jakemsr@cvs.openbsd.org> | 2010-12-30 05:22:52 +0000 |
---|---|---|
committer | Jacob Meuser <jakemsr@cvs.openbsd.org> | 2010-12-30 05:22:52 +0000 |
commit | 1def543700ac1ab92b7f65e3178f9c25b08795ef (patch) | |
tree | 490f6e0ee6af9f43e1af18fc0b9c320f9349ac40 /sys/dev/usb/if_rum.c | |
parent | f6a5099b44f1218b8b9e6a7c28b5646e4f277942 (diff) |
* do not add timeouts if the driver is dying
* use usbd_ref_{incr,decr,wait} to not detach while another process/thread
is using the driver
* s/usb_rem_task/usb_rem_wait_task/ in detach functions because detach
doesn't always happen in the task thread; otherwise a task could be
running while the driver detaches
* in detach functions, first delete pending timeouts, then wait for
processes to be done with the driver before freeing resources
ok martynas@
Diffstat (limited to 'sys/dev/usb/if_rum.c')
-rw-r--r-- | sys/dev/usb/if_rum.c | 37 |
1 files changed, 27 insertions, 10 deletions
diff --git a/sys/dev/usb/if_rum.c b/sys/dev/usb/if_rum.c index 035b073778a..53560d33c8f 100644 --- a/sys/dev/usb/if_rum.c +++ b/sys/dev/usb/if_rum.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_rum.c,v 1.95 2010/12/17 22:38:54 jasper Exp $ */ +/* $OpenBSD: if_rum.c,v 1.96 2010/12/30 05:22:51 jakemsr Exp $ */ /*- * Copyright (c) 2005-2007 Damien Bergamini <damien.bergamini@free.fr> @@ -460,17 +460,20 @@ rum_detach(struct device *self, int flags) s = splusb(); - if (ifp->if_softc != NULL) { - ieee80211_ifdetach(ifp); /* free all nodes */ - if_detach(ifp); - } - - usb_rem_task(sc->sc_udev, &sc->sc_task); if (timeout_initialized(&sc->scan_to)) timeout_del(&sc->scan_to); if (timeout_initialized(&sc->amrr_to)) timeout_del(&sc->amrr_to); + usb_rem_wait_task(sc->sc_udev, &sc->sc_task); + + usbd_ref_wait(sc->sc_udev); + + if (ifp->if_softc != NULL) { + ieee80211_ifdetach(ifp); /* free all nodes */ + if_detach(ifp); + } + if (sc->amrr_xfer != NULL) { usbd_free_xfer(sc->amrr_xfer); sc->amrr_xfer = NULL; @@ -647,8 +650,12 @@ rum_next_scan(void *arg) if (usbd_is_dying(sc->sc_udev)) return; + usbd_ref_incr(sc->sc_udev); + if (ic->ic_state == IEEE80211_S_SCAN) ieee80211_next_scan(ifp); + + usbd_ref_decr(sc->sc_udev); } void @@ -676,7 +683,8 @@ rum_task(void *arg) case IEEE80211_S_SCAN: rum_set_chan(sc, ic->ic_bss->ni_chan); - timeout_add_msec(&sc->scan_to, 200); + if (!usbd_is_dying(sc->sc_udev)) + timeout_add_msec(&sc->scan_to, 200); break; case IEEE80211_S_AUTH: @@ -1350,6 +1358,11 @@ rum_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) struct ifreq *ifr; int s, error = 0; + if (usbd_is_dying(sc->sc_udev)) + return ENXIO; + + usbd_ref_incr(sc->sc_udev); + s = splnet(); switch (cmd) { @@ -1413,6 +1426,8 @@ rum_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) splx(s); + usbd_ref_decr(sc->sc_udev); + return error; } @@ -2232,7 +2247,8 @@ rum_amrr_start(struct rum_softc *sc, struct ieee80211_node *ni) i--); ni->ni_txrate = i; - timeout_add_sec(&sc->amrr_to, 1); + if (!usbd_is_dying(sc->sc_udev)) + timeout_add_sec(&sc->amrr_to, 1); } void @@ -2286,7 +2302,8 @@ rum_amrr_update(usbd_xfer_handle xfer, usbd_private_handle priv, ieee80211_amrr_choose(&sc->amrr, sc->sc_ic.ic_bss, &sc->amn); - timeout_add_sec(&sc->amrr_to, 1); + if (!usbd_is_dying(sc->sc_udev)) + timeout_add_sec(&sc->amrr_to, 1); } int |