Module Name:    src
Committed By:   skrll
Date:           Thu Jan 26 21:13:19 UTC 2017

Modified Files:
        src/sys/net: if_tun.c if_tun.h

Log Message:
Make MP-safe and use kmem(9)

Mostly from rmind-smpnet


To generate a diff of this commit:
cvs rdiff -u -r1.135 -r1.136 src/sys/net/if_tun.c
cvs rdiff -u -r1.19 -r1.20 src/sys/net/if_tun.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/net/if_tun.c
diff -u src/sys/net/if_tun.c:1.135 src/sys/net/if_tun.c:1.136
--- src/sys/net/if_tun.c:1.135	Mon Jan 23 15:32:04 2017
+++ src/sys/net/if_tun.c	Thu Jan 26 21:13:19 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_tun.c,v 1.135 2017/01/23 15:32:04 skrll Exp $	*/
+/*	$NetBSD: if_tun.c,v 1.136 2017/01/26 21:13:19 skrll Exp $	*/
 
 /*
  * Copyright (c) 1988, Julian Onions <j...@cs.nott.ac.uk>
@@ -14,33 +14,35 @@
  * operation though.
  */
 
+/*
+ * tun - tunnel software network interface.
+ */
+
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_tun.c,v 1.135 2017/01/23 15:32:04 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_tun.c,v 1.136 2017/01/26 21:13:19 skrll Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
 #endif
 
 #include <sys/param.h>
+
 #include <sys/buf.h>
 #include <sys/conf.h>
 #include <sys/cpu.h>
 #include <sys/device.h>
-#include <sys/errno.h>
 #include <sys/file.h>
 #include <sys/ioctl.h>
 #include <sys/kauth.h>
+#include <sys/kmem.h>
+#include <sys/lwp.h>
 #include <sys/mbuf.h>
 #include <sys/module.h>
 #include <sys/mutex.h>
 #include <sys/poll.h>
-#include <sys/proc.h>
 #include <sys/select.h>
 #include <sys/signalvar.h>
 #include <sys/socket.h>
-#include <sys/syslog.h>
-#include <sys/systm.h>
-#include <sys/time.h>
 
 #include <net/bpf.h>
 #include <net/if.h>
@@ -107,7 +109,7 @@ const struct cdevsw tun_cdevsw = {
 	.d_mmap = nommap,
 	.d_kqfilter = tunkqfilter,
 	.d_discard = nodiscard,
-	.d_flag = D_OTHER
+	.d_flag = D_OTHER | D_MPSAFE
 };
 
 #ifdef _MODULE
@@ -194,10 +196,8 @@ tun_find_zunit(int unit)
 	if (tp)
 		LIST_REMOVE(tp, tun_list);
 	mutex_exit(&tun_softc_lock);
-#ifdef DIAGNOSTIC
-	if (tp != NULL && (tp->tun_flags & (TUN_INITED|TUN_OPEN)) != TUN_OPEN)
-		printf("tun%d: inconsistent flags: %x\n", unit, tp->tun_flags);
-#endif
+	KASSERTMSG(!tp || (tp->tun_flags & (TUN_INITED|TUN_OPEN)) != TUN_OPEN,
+	    "tun%d: inconsistent flags: %x", unit, tp->tun_flags);
 
 	return tp;
 }
@@ -208,11 +208,11 @@ tun_clone_create(struct if_clone *ifc, i
 	struct tun_softc *tp;
 
 	if ((tp = tun_find_zunit(unit)) == NULL) {
-		/* Allocate a new instance */
-		tp = malloc(sizeof(*tp), M_DEVBUF, M_WAITOK|M_ZERO);
+		tp = kmem_zalloc(sizeof(*tp), KM_SLEEP);
 
 		tp->tun_unit = unit;
 		mutex_init(&tp->tun_lock, MUTEX_DEFAULT, IPL_NET);
+		cv_init(&tp->tun_cv, "tunread");
 		selinit(&tp->tun_rsel);
 		selinit(&tp->tun_wsel);
 	} else {
@@ -267,7 +267,7 @@ static int
 tun_clone_destroy(struct ifnet *ifp)
 {
 	struct tun_softc *tp = (void *)ifp;
-	int zombie = 0;
+	bool zombie = false;
 
 	IF_PURGE(&ifp->if_snd);
 	ifp->if_flags &= ~IFF_RUNNING;
@@ -276,16 +276,16 @@ tun_clone_destroy(struct ifnet *ifp)
 	mutex_enter(&tp->tun_lock);
 	LIST_REMOVE(tp, tun_list);
 	if (tp->tun_flags & TUN_OPEN) {
-		/* Hang on to storage until last close */
-		zombie = 1;
+		/* Hang on to storage until last close. */
 		tp->tun_flags &= ~TUN_INITED;
 		LIST_INSERT_HEAD(&tunz_softc_list, tp, tun_list);
+		zombie = true;
 	}
 	mutex_exit(&tun_softc_lock);
 
 	if (tp->tun_flags & TUN_RWAIT) {
 		tp->tun_flags &= ~TUN_RWAIT;
-		wakeup((void *)tp);
+		cv_broadcast(&tp->tun_cv);
 	}
 	selnotify(&tp->tun_rsel, 0, 0);
 
@@ -303,7 +303,7 @@ tun_clone_destroy(struct ifnet *ifp)
 		softint_disestablish(tp->tun_osih);
 		softint_disestablish(tp->tun_isih);
 		mutex_destroy(&tp->tun_lock);
-		free(tp, M_DEVBUF);
+		kmem_free(tp, sizeof(*tp));
 	}
 
 	return 0;
@@ -331,22 +331,21 @@ tunopen(dev_t dev, int flag, int mode, s
 		(void)tun_clone_create(&tun_cloner, minor(dev));
 		tp = tun_find_unit(dev);
 		if (tp == NULL) {
-			error = ENXIO;
-			goto out_nolock;
+			return ENXIO;
 		}
 	}
 
 	if (tp->tun_flags & TUN_OPEN) {
-		error = EBUSY;
-		goto out;
+		mutex_exit(&tp->tun_lock);
+		return EBUSY;
 	}
 
 	ifp = &tp->tun_if;
 	tp->tun_flags |= TUN_OPEN;
 	TUNDEBUG("%s: open\n", ifp->if_xname);
-out:
+
 	mutex_exit(&tp->tun_lock);
-out_nolock:
+
 	return error;
 }
 
@@ -368,8 +367,8 @@ tunclose(dev_t dev, int flag, int mode,
 		softint_disestablish(tp->tun_osih);
 		softint_disestablish(tp->tun_isih);
 		mutex_destroy(&tp->tun_lock);
-		free(tp, M_DEVBUF);
-		goto out_nolock;
+		kmem_free(tp, sizeof(*tp));
+		return 0;
 	}
 
 	if ((tp = tun_find_unit(dev)) == NULL)
@@ -412,9 +411,6 @@ out_nolock:
 	return 0;
 }
 
-/*
- * Call at splnet().
- */
 static void
 tun_enable(struct tun_softc *tp, const struct ifaddr *ifa)
 {
@@ -473,12 +469,10 @@ tun_enable(struct tun_softc *tp, const s
 static int
 tun_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 {
-	int		error = 0, s;
 	struct tun_softc *tp = (struct tun_softc *)(ifp->if_softc);
 	struct ifreq *ifr = (struct ifreq *)data;
 	struct ifaddr *ifa = (struct ifaddr *)data;
-
-	s = splnet();
+	int error = 0;
 
 	switch (cmd) {
 	case SIOCINITIFADDR:
@@ -522,7 +516,6 @@ tun_ioctl(struct ifnet *ifp, u_long cmd,
 		error = ifioctl_common(ifp, cmd, data);
 	}
 
-	splx(s);
 	return error;
 }
 
@@ -534,14 +527,12 @@ tun_output(struct ifnet *ifp, struct mbu
     const struct rtentry *rt)
 {
 	struct tun_softc *tp = ifp->if_softc;
-	int		s;
 	int		error;
 #if defined(INET) || defined(INET6)
 	int		mlen;
 	uint32_t	*af;
 #endif
 
-	s = splnet();
 	mutex_enter(&tp->tun_lock);
 	TUNDEBUG ("%s: tun_output\n", ifp->if_xname);
 
@@ -551,6 +542,8 @@ tun_output(struct ifnet *ifp, struct mbu
 		error = EHOSTDOWN;
 		goto out;
 	}
+	// XXXrmind
+	mutex_exit(&tp->tun_lock);
 
 	/*
 	 * if the queueing discipline needs packet classification,
@@ -576,7 +569,7 @@ tun_output(struct ifnet *ifp, struct mbu
 				error = ENOBUFS;
 				goto out;
 			}
-			bcopy(dst, mtod(m0, char *), dst->sa_len);
+			memcpy(mtod(m0, char *), dst, dst->sa_len);
 		}
 
 		if (tp->tun_flags & TUN_IFHEAD) {
@@ -617,9 +610,10 @@ tun_output(struct ifnet *ifp, struct mbu
 		goto out;
 	}
 
+	mutex_enter(&tp->tun_lock);
 	if (tp->tun_flags & TUN_RWAIT) {
 		tp->tun_flags &= ~TUN_RWAIT;
-		wakeup((void *)tp);
+		cv_broadcast(&tp->tun_cv);
 	}
 	if (tp->tun_flags & TUN_ASYNC && tp->tun_pgid)
 		softint_schedule(tp->tun_isih);
@@ -627,7 +621,6 @@ tun_output(struct ifnet *ifp, struct mbu
 	selnotify(&tp->tun_rsel, 0, 0);
 out:
 	mutex_exit(&tp->tun_lock);
-	splx(s);
 
 	if (error && m0) {
 		m_freem(m0);
@@ -662,15 +655,13 @@ int
 tunioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
 {
 	struct tun_softc *tp;
-	int s, error = 0;
+	int error = 0;
 
-	s = splnet();
 	tp = tun_find_unit(dev);
 
 	/* interface was "destroyed" already */
 	if (tp == NULL) {
-		error = ENXIO;
-		goto out_nolock;
+		return ENXIO;
 	}
 
 	switch (cmd) {
@@ -757,8 +748,7 @@ tunioctl(dev_t dev, u_long cmd, void *da
 
 out:
 	mutex_exit(&tp->tun_lock);
-out_nolock:
-	splx(s);
+
 	return error;
 }
 
@@ -772,18 +762,15 @@ tunread(dev_t dev, struct uio *uio, int 
 	struct tun_softc *tp;
 	struct ifnet	*ifp;
 	struct mbuf	*m, *m0;
-	int		error = 0, len, s, index;
+	int		error = 0, len;
 
-	s = splnet();
 	tp = tun_find_unit(dev);
 
 	/* interface was "destroyed" already */
 	if (tp == NULL) {
-		error = ENXIO;
-		goto out_nolock;
+		return ENXIO;
 	}
 
-	index = tp->tun_if.if_index;
 	ifp = &tp->tun_if;
 
 	TUNDEBUG ("%s: read\n", ifp->if_xname);
@@ -803,32 +790,14 @@ tunread(dev_t dev, struct uio *uio, int 
 				goto out;
 			}
 			tp->tun_flags |= TUN_RWAIT;
-			if (mtsleep((void *)tp, PZERO|PCATCH|PNORELOCK,
-					"tunread", 0, &tp->tun_lock) != 0) {
+			if (cv_wait_sig(&tp->tun_cv, &tp->tun_lock)) {
 				error = EINTR;
-				goto out_nolock;
-			} else {
-				/*
-				 * Maybe the interface was destroyed while
-				 * we were sleeping, so let's ensure that
-				 * we're looking at the same (valid) tun
-				 * interface before looping.
-				 */
-				tp = tun_find_unit(dev);
-				if (tp == NULL) {
-					error = ENXIO;
-					goto out_nolock;
-				}
-				if (tp->tun_if.if_index != index) {
-					error = ENXIO;
-					goto out;
-				}
+				goto out;
 			}
 		}
 	} while (m0 == 0);
 
 	mutex_exit(&tp->tun_lock);
-	splx(s);
 
 	/* Copy the mbuf chain */
 	while (m0 && uio->uio_resid > 0 && error == 0) {
@@ -849,8 +818,7 @@ tunread(dev_t dev, struct uio *uio, int 
 
 out:
 	mutex_exit(&tp->tun_lock);
-out_nolock:
-	splx(s);
+
 	return error;
 }
 
@@ -865,21 +833,17 @@ tunwrite(dev_t dev, struct uio *uio, int
 	struct mbuf	*top, **mp, *m;
 	pktqueue_t	*pktq;
 	struct sockaddr	dst;
-	int		error = 0, s, tlen, mlen;
+	int		error = 0, tlen, mlen;
 	uint32_t	family;
 
-	s = splnet();
 	tp = tun_find_unit(dev);
-
-	/* interface was "destroyed" already */
 	if (tp == NULL) {
-		error = ENXIO;
-		goto out_nolock;
+		/* Interface was "destroyed" already. */
+		return ENXIO;
 	}
 
 	/* Unlock until we've got the data */
 	mutex_exit(&tp->tun_lock);
-	splx(s);
 
 	ifp = &tp->tun_if;
 
@@ -893,12 +857,14 @@ tunwrite(dev_t dev, struct uio *uio, int
 		error = uiomove((void *)&dst, sizeof(dst), uio);
 		if (dst.sa_len > sizeof(dst)) {
 			/* Duh.. */
-			char discard;
 			int n = dst.sa_len - sizeof(dst);
-			while (n--)
-				if ((error = uiomove(&discard, 1, uio)) != 0) {
+			while (n--) {
+				char discard;
+				error = uiomove(&discard, 1, uio);
+				if (error) {
 					goto out0;
 				}
+			}
 		}
 	} else if (tp->tun_flags & TUN_IFHEAD) {
 		if (uio->uio_resid < sizeof(family)){
@@ -941,8 +907,7 @@ tunwrite(dev_t dev, struct uio *uio, int
 	/* get a header mbuf */
 	MGETHDR(m, M_DONTWAIT, MT_DATA);
 	if (m == NULL) {
-		error = ENOBUFS;
-		goto out0;
+		return ENOBUFS;
 	}
 	mlen = MHLEN;
 
@@ -964,7 +929,7 @@ tunwrite(dev_t dev, struct uio *uio, int
 	}
 	if (error) {
 		if (top != NULL)
-			m_freem (top);
+			m_freem(top);
 		ifp->if_ierrors++;
 		goto out0;
 	}
@@ -974,7 +939,6 @@ tunwrite(dev_t dev, struct uio *uio, int
 
 	bpf_mtap_af(ifp, dst.sa_family, top);
 
-	s = splnet();
 	mutex_enter(&tp->tun_lock);
 	if ((tp->tun_flags & TUN_INITED) == 0) {
 		/* Interface was destroyed */
@@ -986,14 +950,12 @@ tunwrite(dev_t dev, struct uio *uio, int
 		mutex_exit(&tp->tun_lock);
 		error = ENOBUFS;
 		m_freem(top);
-		goto out_nolock;
+		goto out0;
 	}
 	ifp->if_ipackets++;
 	ifp->if_ibytes += tlen;
 out:
 	mutex_exit(&tp->tun_lock);
-out_nolock:
-	splx(s);
 out0:
 	return error;
 }
@@ -1004,8 +966,6 @@ out0:
  * when the interface queue is rate-limited by ALTQ or TBR,
  * if_start is needed to drain packets from the queue in order
  * to notify readers when outgoing packets become ready.
- *
- * Should be called at splnet.
  */
 static void
 tunstart(struct ifnet *ifp)
@@ -1019,7 +979,7 @@ tunstart(struct ifnet *ifp)
 	if (!IF_IS_EMPTY(&ifp->if_snd)) {
 		if (tp->tun_flags & TUN_RWAIT) {
 			tp->tun_flags &= ~TUN_RWAIT;
-			wakeup((void *)tp);
+			cv_broadcast(&tp->tun_cv);
 		}
 		if (tp->tun_flags & TUN_ASYNC && tp->tun_pgid)
 			softint_schedule(tp->tun_osih);
@@ -1039,15 +999,13 @@ tunpoll(dev_t dev, int events, struct lw
 {
 	struct tun_softc *tp;
 	struct ifnet	*ifp;
-	int		s, revents = 0;
+	int revents = 0;
 
-	s = splnet();
 	tp = tun_find_unit(dev);
-
-	/* interface was "destroyed" already */
-	if (tp == NULL)
-		goto out_nolock;
-
+	if (tp == NULL) {
+		/* Interface was "destroyed" already. */
+		return 0;
+	}
 	ifp = &tp->tun_if;
 
 	TUNDEBUG("%s: tunpoll\n", ifp->if_xname);
@@ -1067,8 +1025,7 @@ tunpoll(dev_t dev, int events, struct lw
 		revents |= events & (POLLOUT | POLLWRNORM);
 
 	mutex_exit(&tp->tun_lock);
-out_nolock:
-	splx(s);
+
 	return revents;
 }
 
@@ -1076,11 +1033,10 @@ static void
 filt_tunrdetach(struct knote *kn)
 {
 	struct tun_softc *tp = kn->kn_hook;
-	int s;
 
-	s = splnet();
+	mutex_enter(&tp->tun_lock);
 	SLIST_REMOVE(&tp->tun_rsel.sel_klist, kn, knote, kn_selnext);
-	splx(s);
+	mutex_exit(&tp->tun_lock);
 }
 
 static int
@@ -1089,19 +1045,19 @@ filt_tunread(struct knote *kn, long hint
 	struct tun_softc *tp = kn->kn_hook;
 	struct ifnet *ifp = &tp->tun_if;
 	struct mbuf *m;
-	int s;
 
-	s = splnet();
+	mutex_enter(&tp->tun_lock);
 	IF_POLL(&ifp->if_snd, m);
 	if (m == NULL) {
-		splx(s);
+		mutex_exit(&tp->tun_lock);
 		return 0;
 	}
 
 	for (kn->kn_data = 0; m != NULL; m = m->m_next)
 		kn->kn_data += m->m_len;
 
-	splx(s);
+	mutex_exit(&tp->tun_lock);
+
 	return 1;
 }
 
@@ -1116,9 +1072,8 @@ tunkqfilter(dev_t dev, struct knote *kn)
 {
 	struct tun_softc *tp;
 	struct klist *klist;
-	int rv = 0, s;
+	int rv = 0;
 
-	s = splnet();
 	tp = tun_find_unit(dev);
 	if (tp == NULL)
 		goto out_nolock;
@@ -1146,7 +1101,6 @@ tunkqfilter(dev_t dev, struct knote *kn)
 out:
 	mutex_exit(&tp->tun_lock);
 out_nolock:
-	splx(s);
 	return rv;
 }
 

Index: src/sys/net/if_tun.h
diff -u src/sys/net/if_tun.h:1.19 src/sys/net/if_tun.h:1.20
--- src/sys/net/if_tun.h:1.19	Sun Sep  6 06:01:01 2015
+++ src/sys/net/if_tun.h	Thu Jan 26 21:13:19 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_tun.h,v 1.19 2015/09/06 06:01:01 dholland Exp $	*/
+/*	$NetBSD: if_tun.h,v 1.20 2017/01/26 21:13:19 skrll Exp $	*/
 
 /*
  * Copyright (c) 1988, Julian Onions <j...@cs.nott.ac.uk>
@@ -44,6 +44,7 @@ struct tun_softc {
 	struct	selinfo	tun_wsel;	/* write select (not used) */
 	int	tun_unit;		/* the tunnel unit number */
 	kmutex_t tun_lock;		/* lock for this tunnel */
+	kcondvar_t tun_cv;		/* condition variable for tunnel */
 	LIST_ENTRY(tun_softc) tun_list;	/* list of all tuns */
 	void	*tun_osih;		/* soft interrupt handle */
 	void	*tun_isih;		/* soft interrupt handle */

Reply via email to