Module Name:    src
Committed By:   dyoung
Date:           Mon Aug 15 18:24:34 UTC 2011

Modified Files:
        src/sys/dev/ic: wi.c wivar.h

Log Message:
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).


To generate a diff of this commit:
cvs rdiff -u -r1.234 -r1.235 src/sys/dev/ic/wi.c
cvs rdiff -u -r1.64 -r1.65 src/sys/dev/ic/wivar.h

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/ic/wi.c
diff -u src/sys/dev/ic/wi.c:1.234 src/sys/dev/ic/wi.c:1.235
--- src/sys/dev/ic/wi.c:1.234	Tue Nov 23 04:33:09 2010
+++ src/sys/dev/ic/wi.c	Mon Aug 15 18:24:34 2011
@@ -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;
 }

Index: src/sys/dev/ic/wivar.h
diff -u src/sys/dev/ic/wivar.h:1.64 src/sys/dev/ic/wivar.h:1.65
--- src/sys/dev/ic/wivar.h:1.64	Tue Nov 23 04:33:09 2010
+++ src/sys/dev/ic/wivar.h	Mon Aug 15 18:24:34 2011
@@ -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

Reply via email to