svn commit: r195628 - user/kmacy/head_ppacket/sys/net

Kip Macy kmacy at FreeBSD.org
Sat Jul 11 22:57:03 UTC 2009


Author: kmacy
Date: Sat Jul 11 22:57:02 2009
New Revision: 195628
URL: http://svn.freebsd.org/changeset/base/195628

Log:
  - remove tun_pid - TUN_OPEN is used to avoid multiple users
  - add tun_rwait_cv to avoid TUN_RWAIT setting sleep / wakeup dance
  - serialize access to softc structures every place they're touched
  - make teardown of the ifaddr list SMP / PREEMPTION safe
  - remove spl in all places where the tun lock now protects state

Modified:
  user/kmacy/head_ppacket/sys/net/if_tun.c

Modified: user/kmacy/head_ppacket/sys/net/if_tun.c
==============================================================================
--- user/kmacy/head_ppacket/sys/net/if_tun.c	Sat Jul 11 22:43:20 2009	(r195627)
+++ user/kmacy/head_ppacket/sys/net/if_tun.c	Sat Jul 11 22:57:02 2009	(r195628)
@@ -76,25 +76,18 @@ struct tun_softc {
 #define	TUN_IASET	0x0008
 #define	TUN_DSTADDR	0x0010
 #define	TUN_LMODE	0x0020
-#define	TUN_RWAIT	0x0040
+
 #define	TUN_ASYNC	0x0080
 #define	TUN_IFHEAD	0x0100
 
 #define TUN_READY       (TUN_OPEN | TUN_INITED)
 
-	/*
-	 * XXXRW: tun_pid is used to exclusively lock /dev/tun.  Is this
-	 * actually needed?  Can we just return EBUSY if already open?
-	 * Problem is that this involved inherent races when a tun device
-	 * is handed off from one process to another, as opposed to just
-	 * being slightly stale informationally.
-	 */
-	pid_t	tun_pid;		/* owning pid */
 	struct	ifnet *tun_ifp;		/* the interface */
 	struct  sigio *tun_sigio;	/* information for async I/O */
 	struct	selinfo	tun_rsel;	/* read select */
 	struct mtx	tun_mtx;	/* protect mutable softc fields */
 	struct cv	tun_cv;		/* protect against ref'd dev destroy */
+	struct cv	tun_rwait_cv;	/* rwait wakeup */
 };
 #define TUN2IFP(sc)	((sc)->tun_ifp)
 
@@ -347,10 +340,7 @@ tunstart(struct ifnet *ifp)
 	}
 
 	mtx_lock(&tp->tun_mtx);
-	if (tp->tun_flags & TUN_RWAIT) {
-		tp->tun_flags &= ~TUN_RWAIT;
-		wakeup(tp);
-	}
+	cv_broadcast(&tp->tun_rwait_cv);
 	if (tp->tun_flags & TUN_ASYNC && tp->tun_sigio) {
 		mtx_unlock(&tp->tun_mtx);
 		pgsigio(&tp->tun_sigio, SIGIO, 0);
@@ -371,7 +361,8 @@ tuncreate(const char *name, struct cdev 
 
 	sc = malloc(sizeof(*sc), M_TUN, M_WAITOK | M_ZERO);
 	mtx_init(&sc->tun_mtx, "tun_mtx", NULL, MTX_DEF);
-	cv_init(&sc->tun_cv, "tun_condvar");
+	cv_init(&sc->tun_cv, "tun_ref_cv");
+	cv_init(&sc->tun_rwait_cv, "tun_rwait_cv");
 	sc->tun_flags = TUN_INITED;
 	sc->tun_dev = dev;
 	mtx_lock(&tunmtx);
@@ -417,18 +408,11 @@ tunopen(struct cdev *dev, int flag, int 
 		tp = dev->si_drv1;
 	}
 
-	/*
-	 * XXXRW: This use of tun_pid is subject to error due to the
-	 * fact that a reference to the tunnel can live beyond the
-	 * death of the process that created it.  Can we replace this
-	 * with a simple busy flag?
-	 */
 	mtx_lock(&tp->tun_mtx);
-	if (tp->tun_pid != 0 && tp->tun_pid != td->td_proc->p_pid) {
+	if (tp->tun_flags & TUN_OPEN) {
 		mtx_unlock(&tp->tun_mtx);
 		return (EBUSY);
 	}
-	tp->tun_pid = td->td_proc->p_pid;
 
 	tp->tun_flags |= TUN_OPEN;
 	mtx_unlock(&tp->tun_mtx);
@@ -448,36 +432,37 @@ tunclose(struct cdev *dev, int foo, int 
 {
 	struct tun_softc *tp;
 	struct ifnet *ifp;
-	int s;
-
+	struct ifaddrhead head;
+	
 	tp = dev->si_drv1;
 	ifp = TUN2IFP(tp);
-
+	
+	TAILQ_INIT(&head);
 	mtx_lock(&tp->tun_mtx);
 	tp->tun_flags &= ~TUN_OPEN;
-	tp->tun_pid = 0;
 	mtx_unlock(&tp->tun_mtx);
 
 	/*
 	 * junk all pending output
 	 */
 	CURVNET_SET(ifp->if_vnet);
-	s = splimp();
 	IFQ_PURGE(&ifp->if_snd);
-	splx(s);
 
 	if (ifp->if_flags & IFF_UP) {
-		s = splimp();
+		mtx_lock(&tp->tun_mtx);
 		if_down(ifp);
-		splx(s);
+		mtx_unlock(&tp->tun_mtx);
 	}
 
 	/* Delete all addresses and routes which reference this interface. */
 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
 		struct ifaddr *ifa;
 
-		s = splimp();
-		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+		while (!TAILQ_EMPTY(&ifp->if_addrhead)) {
+			IF_ADDR_LOCK(ifp);
+			ifa = TAILQ_FIRST(&ifp->if_addrhead);
+			TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
+			IF_ADDR_UNLOCK(ifp);
 			/* deal w/IPv4 PtP destination; unlocked read */
 			if (ifa->ifa_addr->sa_family == AF_INET) {
 				rtinit(ifa, (int)RTM_DELETE,
@@ -486,9 +471,13 @@ tunclose(struct cdev *dev, int foo, int 
 				rtinit(ifa, (int)RTM_DELETE, 0);
 			}
 		}
+		IF_ADDR_LOCK(ifp);
+		TAILQ_CONCAT(&ifp->if_addrhead, &head, ifa_link);
 		if_purgeaddrs(ifp);
+		IF_ADDR_UNLOCK(ifp);
+		mtx_lock(&tp->tun_mtx);
 		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
-		splx(s);
+		mtx_unlock(&tp->tun_mtx);
 	}
 	if_link_state_change(ifp, LINK_STATE_DOWN);
 	CURVNET_RESTORE();
@@ -507,12 +496,13 @@ tunclose(struct cdev *dev, int foo, int 
 static int
 tuninit(struct ifnet *ifp)
 {
+	int error = 0;
 #ifdef INET
 	struct tun_softc *tp = ifp->if_softc;
 	struct ifaddr *ifa;
+	
+	mtx_assert(&tp->tun_mtx, MA_OWNED);
 #endif
-	int error = 0;
-
 	TUNDEBUG(ifp, "tuninit\n");
 
 	ifp->if_flags |= IFF_UP;
@@ -526,14 +516,12 @@ tuninit(struct ifnet *ifp)
 			struct sockaddr_in *si;
 
 			si = (struct sockaddr_in *)ifa->ifa_addr;
-			mtx_lock(&tp->tun_mtx);
 			if (si->sin_addr.s_addr)
 				tp->tun_flags |= TUN_IASET;
 
 			si = (struct sockaddr_in *)ifa->ifa_dstaddr;
 			if (si && si->sin_addr.s_addr)
 				tp->tun_flags |= TUN_DSTADDR;
-			mtx_unlock(&tp->tun_mtx);
 		}
 	}
 	if_addr_runlock(ifp);
@@ -550,17 +538,12 @@ tunifioctl(struct ifnet *ifp, u_long cmd
 	struct ifreq *ifr = (struct ifreq *)data;
 	struct tun_softc *tp = ifp->if_softc;
 	struct ifstat *ifs;
-	int		error = 0, s;
+	int error = 0;
 
-	s = splimp();
+	mtx_lock(&tp->tun_mtx);
 	switch(cmd) {
 	case SIOCGIFSTATUS:
 		ifs = (struct ifstat *)data;
-		mtx_lock(&tp->tun_mtx);
-		if (tp->tun_pid)
-			sprintf(ifs->ascii + strlen(ifs->ascii),
-			    "\tOpened by PID %d\n", tp->tun_pid);
-		mtx_unlock(&tp->tun_mtx);
 		break;
 	case SIOCSIFADDR:
 		error = tuninit(ifp);
@@ -581,7 +564,7 @@ tunifioctl(struct ifnet *ifp, u_long cmd
 	default:
 		error = EINVAL;
 	}
-	splx(s);
+	mtx_unlock(&tp->tun_mtx);
 	return (error);
 }
 
@@ -687,7 +670,6 @@ tunoutput(
 static	int
 tunioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
 {
-	int		s;
 	int		error;
 	struct tun_softc *tp = dev->si_drv1;
 	struct tuninfo *tunp;
@@ -758,11 +740,6 @@ tunioctl(struct cdev *dev, u_long cmd, c
 			return(EINVAL);
 		}
 		break;
-	case TUNSIFPID:
-		mtx_lock(&tp->tun_mtx);
-		tp->tun_pid = curthread->td_proc->p_pid;
-		mtx_unlock(&tp->tun_mtx);
-		break;
 	case FIONBIO:
 		break;
 	case FIOASYNC:
@@ -774,7 +751,6 @@ tunioctl(struct cdev *dev, u_long cmd, c
 		mtx_unlock(&tp->tun_mtx);
 		break;
 	case FIONREAD:
-		s = splimp();
 		if (!IFQ_IS_EMPTY(&TUN2IFP(tp)->if_snd)) {
 			struct mbuf *mb;
 			IFQ_LOCK(&TUN2IFP(tp)->if_snd);
@@ -784,7 +760,6 @@ tunioctl(struct cdev *dev, u_long cmd, c
 			IFQ_UNLOCK(&TUN2IFP(tp)->if_snd);
 		} else
 			*(int *)data = 0;
-		splx(s);
 		break;
 	case FIOSETOWN:
 		return (fsetown(*(int *)data, &tp->tun_sigio));
@@ -818,7 +793,7 @@ tunread(struct cdev *dev, struct uio *ui
 	struct tun_softc *tp = dev->si_drv1;
 	struct ifnet	*ifp = TUN2IFP(tp);
 	struct mbuf	*m;
-	int		error=0, len, s;
+	int		error=0, len;
 
 	TUNDEBUG (ifp, "read\n");
 	mtx_lock(&tp->tun_mtx);
@@ -827,29 +802,21 @@ tunread(struct cdev *dev, struct uio *ui
 		TUNDEBUG (ifp, "not ready 0%o\n", tp->tun_flags);
 		return (EHOSTDOWN);
 	}
-
-	tp->tun_flags &= ~TUN_RWAIT;
 	mtx_unlock(&tp->tun_mtx);
 
-	s = splimp();
 	do {
 		IFQ_DEQUEUE(&ifp->if_snd, m);
 		if (m == NULL) {
 			if (flag & O_NONBLOCK) {
-				splx(s);
 				return (EWOULDBLOCK);
 			}
 			mtx_lock(&tp->tun_mtx);
-			tp->tun_flags |= TUN_RWAIT;
+			error = cv_wait_sig(&tp->tun_rwait_cv, &tp->tun_mtx);
 			mtx_unlock(&tp->tun_mtx);
-			if ((error = tsleep(tp, PCATCH | (PZERO + 1),
-					"tunread", 0)) != 0) {
-				splx(s);
+			if (error)
 				return (error);
-			}
 		}
 	} while (m == NULL);
-	splx(s);
 
 	while (m && uio->uio_resid > 0 && error == 0) {
 		len = min(uio->uio_resid, m->m_len);
@@ -962,13 +929,11 @@ tunwrite(struct cdev *dev, struct uio *u
 static	int
 tunpoll(struct cdev *dev, int events, struct thread *td)
 {
-	int		s;
 	struct tun_softc *tp = dev->si_drv1;
 	struct ifnet	*ifp = TUN2IFP(tp);
 	int		revents = 0;
 	struct mbuf	*m;
 
-	s = splimp();
 	TUNDEBUG(ifp, "tunpoll\n");
 
 	if (events & (POLLIN | POLLRDNORM)) {
@@ -986,7 +951,6 @@ tunpoll(struct cdev *dev, int events, st
 	if (events & (POLLOUT | POLLWRNORM))
 		revents |= events & (POLLOUT | POLLWRNORM);
 
-	splx(s);
 	return (revents);
 }
 
@@ -1034,12 +998,11 @@ tunkqfilter(struct cdev *dev, struct kno
 static int
 tunkqread(struct knote *kn, long hint)
 {
-	int			ret, s;
+	int			ret;
 	struct cdev		*dev = (struct cdev *)(kn->kn_hook);
 	struct tun_softc	*tp = dev->si_drv1;
 	struct ifnet	*ifp = TUN2IFP(tp);
 
-	s = splimp();
 	if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) {
 		TUNDEBUG(ifp,
 		    "%s have data in the queue.  Len = %d, minor = %#x\n",
@@ -1051,7 +1014,6 @@ tunkqread(struct knote *kn, long hint)
 		    dev2unit(dev));
 		ret = 0;
 	}
-	splx(s);
 
 	return (ret);
 }
@@ -1062,13 +1024,12 @@ tunkqread(struct knote *kn, long hint)
 static int
 tunkqwrite(struct knote *kn, long hint)
 {
-	int			s;
 	struct tun_softc	*tp = ((struct cdev *)kn->kn_hook)->si_drv1;
 	struct ifnet	*ifp = TUN2IFP(tp);
 
-	s = splimp();
+	mtx_lock(&tp->tun_mtx);
 	kn->kn_data = ifp->if_mtu;
-	splx(s);
+	mtx_unlock(&tp->tun_mtx);
 
 	return (1);
 }


More information about the svn-src-user mailing list