Index: head/sys/net/if_tun.c =================================================================== --- head/sys/net/if_tun.c +++ head/sys/net/if_tun.c @@ -81,16 +81,10 @@ #define TUN_RWAIT 0x0040 #define TUN_ASYNC 0x0080 #define TUN_IFHEAD 0x0100 +#define TUN_DYING 0x0200 #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 */ @@ -277,6 +271,7 @@ struct cdev *dev; mtx_lock(&tp->tun_mtx); + tp->tun_flags |= TUN_DYING; if ((tp->tun_flags & TUN_OPEN) != 0) cv_wait_unlock(&tp->tun_cv, &tp->tun_mtx); else @@ -473,19 +468,13 @@ 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 | TUN_DYING)) != 0) { mtx_unlock(&tp->tun_mtx); return (EBUSY); } - tp->tun_pid = td->td_proc->p_pid; + tp->tun_pid = td->td_proc->p_pid; tp->tun_flags |= TUN_OPEN; ifp = TUN2IFP(tp); if_link_state_change(ifp, LINK_STATE_UP); @@ -509,6 +498,16 @@ ifp = TUN2IFP(tp); mtx_lock(&tp->tun_mtx); + /* + * Simply close the device if this isn't the controlling process. This + * may happen if, for instance, the tunnel has been handed off to + * another process. The original controller should be able to close it + * without putting us into an inconsistent state. + */ + if (td->td_proc->p_pid != tp->tun_pid) { + mtx_unlock(&tp->tun_mtx); + return (0); + } /* * junk all pending output