Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/ic Use a recursive lock to ensure that only on threa...



details:   https://anonhg.NetBSD.org/src/rev/b8c5f60182fe
branches:  trunk
changeset: 768371:b8c5f60182fe
user:      dyoung <dyoung%NetBSD.org@localhost>
date:      Mon Aug 15 18:24:34 2011 +0000

description:
Use a recursive lock to ensure that only on thread is in wi_ioctl() at
one time.  It's a recursive lock because sometimes wi_ioctl() recurses
through the network stack (ick).

diffstat:

 sys/dev/ic/wi.c    |  77 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 sys/dev/ic/wivar.h |  12 +++++++-
 2 files changed, 86 insertions(+), 3 deletions(-)

diffs (166 lines):

diff -r 6bb28ef4101e -r b8c5f60182fe sys/dev/ic/wi.c
--- a/sys/dev/ic/wi.c   Mon Aug 15 18:04:59 2011 +0000
+++ b/sys/dev/ic/wi.c   Mon Aug 15 18:24:34 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: wi.c,v 1.234 2010/11/23 04:33:09 christos Exp $        */
+/*     $NetBSD: wi.c,v 1.235 2011/08/15 18:24:34 dyoung Exp $  */
 
 /*-
  * Copyright (c) 2004 The NetBSD Foundation, Inc.
@@ -99,7 +99,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: wi.c,v 1.234 2010/11/23 04:33:09 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wi.c,v 1.235 2011/08/15 18:24:34 dyoung Exp $");
 
 #define WI_HERMES_AUTOINC_WAR  /* Work around data write autoinc bug. */
 #define WI_HERMES_STATS_WAR    /* Work around stats counter bug. */
@@ -151,6 +151,11 @@
 STATIC int  wi_media_change(struct ifnet *);
 STATIC void wi_media_status(struct ifnet *, struct ifmediareq *);
 
+static void wi_ioctl_init(struct wi_softc *);
+static int wi_ioctl_enter(struct wi_softc *);
+static void wi_ioctl_exit(struct wi_softc *);
+static void wi_ioctl_drain(struct wi_softc *);
+
 STATIC struct ieee80211_node *wi_node_alloc(struct ieee80211_node_table *);
 STATIC void wi_node_free(struct ieee80211_node *);
 
@@ -373,6 +378,8 @@
        };
        int s;
 
+       wi_ioctl_init(sc);
+
        s = splnet();
 
        /* Make sure interrupts are disabled. */
@@ -595,6 +602,7 @@
        ieee80211_ifdetach(&sc->sc_ic);
        if_detach(ifp);
        splx(s);
+       wi_ioctl_drain(sc);
        return 0;
 }
 
@@ -1289,6 +1297,67 @@
        ieee80211_watchdog(&sc->sc_ic);
 }
 
+static int
+wi_ioctl_enter(struct wi_softc *sc)
+{
+       int rc = 0;
+
+       mutex_enter(&sc->sc_ioctl_mtx);
+       sc->sc_ioctl_nwait++;
+       while (sc->sc_ioctl_lwp != NULL && sc->sc_ioctl_lwp != curlwp) {
+               rc = sc->sc_ioctl_gone
+                   ? ENXIO
+                   : cv_wait_sig(&sc->sc_ioctl_cv, &sc->sc_ioctl_mtx);
+               if (rc != 0)
+                       break;
+       }
+       if (rc == 0) {
+               sc->sc_ioctl_lwp = curlwp;
+               sc->sc_ioctl_depth++;
+       }
+       if (--sc->sc_ioctl_nwait == 0)
+               cv_signal(&sc->sc_ioctl_cv);
+       mutex_exit(&sc->sc_ioctl_mtx);
+       return rc;
+}
+
+static void
+wi_ioctl_exit(struct wi_softc *sc)
+{
+       KASSERT(sc->sc_ioctl_lwp == curlwp);
+       mutex_enter(&sc->sc_ioctl_mtx);
+       if (--sc->sc_ioctl_depth == 0) {
+               sc->sc_ioctl_lwp = NULL;
+               cv_signal(&sc->sc_ioctl_cv);
+       }
+       mutex_exit(&sc->sc_ioctl_mtx);
+}
+
+static void
+wi_ioctl_init(struct wi_softc *sc)
+{
+       mutex_init(&sc->sc_ioctl_mtx, MUTEX_DEFAULT, IPL_NONE);
+       cv_init(&sc->sc_ioctl_cv, device_xname(sc->sc_dev));
+}
+
+static void
+wi_ioctl_drain(struct wi_softc *sc)
+{
+       wi_ioctl_enter(sc);
+
+       mutex_enter(&sc->sc_ioctl_mtx);
+       sc->sc_ioctl_gone = true;
+       cv_broadcast(&sc->sc_ioctl_cv);
+       while (sc->sc_ioctl_nwait != 0)
+               cv_wait(&sc->sc_ioctl_cv, &sc->sc_ioctl_mtx);
+       mutex_exit(&sc->sc_ioctl_mtx);
+
+       wi_ioctl_exit(sc);
+
+       mutex_destroy(&sc->sc_ioctl_mtx);
+       cv_destroy(&sc->sc_ioctl_cv);
+}
+
 STATIC int
 wi_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 {
@@ -1302,6 +1371,9 @@
 
        s = splnet();
 
+       if ((error = wi_ioctl_enter(sc)) != 0)
+               return error;
+
        switch (cmd) {
        case SIOCSIFFLAGS:
                if ((error = ifioctl_common(ifp, cmd, data)) != 0)
@@ -1374,6 +1446,7 @@
                break;
        }
        wi_mend_flags(sc, ic->ic_state);
+       wi_ioctl_exit(sc);
        splx(s);
        return error;
 }
diff -r 6bb28ef4101e -r b8c5f60182fe sys/dev/ic/wivar.h
--- a/sys/dev/ic/wivar.h        Mon Aug 15 18:04:59 2011 +0000
+++ b/sys/dev/ic/wivar.h        Mon Aug 15 18:24:34 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: wivar.h,v 1.64 2010/11/23 04:33:09 christos Exp $      */
+/*     $NetBSD: wivar.h,v 1.65 2011/08/15 18:24:34 dyoung Exp $        */
 
 /*
  * Copyright (c) 1997, 1998, 1999
@@ -32,6 +32,10 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/lwp.h>
+
 /* Radio capture format for Prism. */
 
 #define WI_RX_RADIOTAP_PRESENT ((1 << IEEE80211_RADIOTAP_FLAGS) | \
@@ -166,6 +170,12 @@
        /* number of transmissions pending at each data rate */
        u_int8_t                sc_txpending[IEEE80211_RATE_MAXSIZE];
        struct callout          sc_rssadapt_ch;
+       kmutex_t                sc_ioctl_mtx;
+       kcondvar_t              sc_ioctl_cv;
+       bool                    sc_ioctl_gone;
+       unsigned int            sc_ioctl_nwait;
+       unsigned int            sc_ioctl_depth;
+       lwp_t                   *sc_ioctl_lwp;
 };
 
 #define        sc_if           sc_ec.ec_if



Home | Main Index | Thread Index | Old Index