summaryrefslogtreecommitdiffstats
path: root/sys/net/if_tun.c
diff options
context:
space:
mode:
authorqingli <qingli@FreeBSD.org>2008-12-22 01:56:56 +0000
committerqingli <qingli@FreeBSD.org>2008-12-22 01:56:56 +0000
commite3cd29b301e6fca9d070995095d27115813dd149 (patch)
tree6b071d7ed047aa31e002b84298f0d581c5e67086 /sys/net/if_tun.c
parent4fea5c77549e61d0dbb1c1cf9acbcadedb11d7cf (diff)
downloadFreeBSD-src-e3cd29b301e6fca9d070995095d27115813dd149.zip
FreeBSD-src-e3cd29b301e6fca9d070995095d27115813dd149.tar.gz
Provide a condition variable to delay the cloned interface
destroy operation until the referenced clone device has been closed by the process properly. The behavior is now consistently with the previous release. Reviewed by: Kip Macy
Diffstat (limited to 'sys/net/if_tun.c')
-rw-r--r--sys/net/if_tun.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c
index 67fb74e..8187b74 100644
--- a/sys/net/if_tun.c
+++ b/sys/net/if_tun.c
@@ -57,6 +57,7 @@
#include <net/if_tun.h>
#include <sys/queue.h>
+#include <sys/condvar.h>
#include <security/mac/mac_framework.h>
@@ -93,6 +94,7 @@ struct tun_softc {
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 */
};
#define TUN2IFP(sc) ((sc)->tun_ifp)
@@ -253,8 +255,9 @@ tun_destroy(struct tun_softc *tp)
struct cdev *dev;
/* Unlocked read. */
- KASSERT((tp->tun_flags & TUN_OPEN) == 0,
- ("tununits is out of sync - unit %d", TUN2IFP(tp)->if_dunit));
+ mtx_lock(&tp->tun_mtx);
+ if ((tp->tun_flags & TUN_OPEN) != 0)
+ cv_wait_unlock(&tp->tun_cv, &tp->tun_mtx);
CURVNET_SET(TUN2IFP(tp)->if_vnet);
dev = tp->tun_dev;
@@ -264,6 +267,7 @@ tun_destroy(struct tun_softc *tp)
destroy_dev(dev);
knlist_destroy(&tp->tun_rsel.si_note);
mtx_destroy(&tp->tun_mtx);
+ cv_destroy(&tp->tun_cv);
free(tp, M_TUN);
CURVNET_RESTORE();
}
@@ -365,6 +369,7 @@ tuncreate(const char *name, struct cdev *dev)
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");
sc->tun_flags = TUN_INITED;
sc->tun_dev = dev;
mtx_lock(&tunmtx);
@@ -449,6 +454,7 @@ tunclose(struct cdev *dev, int foo, int bar, struct thread *td)
mtx_lock(&tp->tun_mtx);
tp->tun_flags &= ~TUN_OPEN;
tp->tun_pid = 0;
+ mtx_unlock(&tp->tun_mtx);
/*
* junk all pending output
@@ -457,7 +463,6 @@ tunclose(struct cdev *dev, int foo, int bar, struct thread *td)
s = splimp();
IFQ_PURGE(&ifp->if_snd);
splx(s);
- mtx_unlock(&tp->tun_mtx);
if (ifp->if_flags & IFF_UP) {
s = splimp();
@@ -486,10 +491,14 @@ tunclose(struct cdev *dev, int foo, int bar, struct thread *td)
if_link_state_change(ifp, LINK_STATE_DOWN);
CURVNET_RESTORE();
+ mtx_lock(&tp->tun_mtx);
funsetown(&tp->tun_sigio);
selwakeuppri(&tp->tun_rsel, PZERO + 1);
KNOTE_UNLOCKED(&tp->tun_rsel.si_note, 0);
TUNDEBUG (ifp, "closed\n");
+
+ cv_broadcast(&tp->tun_cv);
+ mtx_unlock(&tp->tun_mtx);
return (0);
}
OpenPOWER on IntegriCloud