From owner-svn-src-all@freebsd.org Thu Oct 3 17:46:28 2019 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 9DAC413C165; Thu, 3 Oct 2019 17:46:28 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 46kgRS3fcFz4RWC; Thu, 3 Oct 2019 17:46:28 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 609AAFB28; Thu, 3 Oct 2019 17:46:28 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x93HkSAJ059219; Thu, 3 Oct 2019 17:46:28 GMT (envelope-from kevans@FreeBSD.org) Received: (from kevans@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x93HkSRO059218; Thu, 3 Oct 2019 17:46:28 GMT (envelope-from kevans@FreeBSD.org) Message-Id: <201910031746.x93HkSRO059218@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kevans set sender to kevans@FreeBSD.org using -f From: Kyle Evans Date: Thu, 3 Oct 2019 17:46:28 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r353056 - head/sys/net X-SVN-Group: head X-SVN-Commit-Author: kevans X-SVN-Commit-Paths: head/sys/net X-SVN-Commit-Revision: 353056 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 03 Oct 2019 17:46:28 -0000 Author: kevans Date: Thu Oct 3 17:46:27 2019 New Revision: 353056 URL: https://svnweb.freebsd.org/changeset/base/353056 Log: if_tuntap: add a busy/unbusy mechanism, replace destroy OPEN check A future commit will create device aliases when a tuntap device is renamed so that it's still easily found in /dev after the rename. Said mechanism will want to keep the tun alive long enough to either realize that it's about to go away or complete the alias creation, even if the alias is about to get destroyed. While we're introducing it, using it to prevent open devices from going away makes plenty of sense and keeps the logic on waking up tun_destroy clean, so we don't have multiple places trying to cv_broadcast unless it's still in use elsewhere. Modified: head/sys/net/if_tuntap.c Modified: head/sys/net/if_tuntap.c ============================================================================== --- head/sys/net/if_tuntap.c Thu Oct 3 17:41:20 2019 (r353055) +++ head/sys/net/if_tuntap.c Thu Oct 3 17:46:27 2019 (r353056) @@ -131,13 +131,15 @@ struct tuntap_softc { struct mtx tun_mtx; /* softc field mutex */ struct cv tun_cv; /* for ref'd dev destroy */ struct ether_addr tun_ether; /* remote address */ + int tun_busy; /* busy count */ }; #define TUN2IFP(sc) ((sc)->tun_ifp) #define TUNDEBUG if (tundebug) if_printf -#define TUN_LOCK(tp) mtx_lock(&(tp)->tun_mtx) -#define TUN_UNLOCK(tp) mtx_unlock(&(tp)->tun_mtx) +#define TUN_LOCK(tp) mtx_lock(&(tp)->tun_mtx) +#define TUN_UNLOCK(tp) mtx_unlock(&(tp)->tun_mtx) +#define TUN_LOCK_ASSERT(tp) mtx_assert(&(tp)->tun_mtx, MA_OWNED); #define TUN_VMIO_FLAG_MASK 0x0fff @@ -182,6 +184,11 @@ SYSCTL_INT(_net_link_tap, OID_AUTO, devfs_cloning, CTL "Enable legacy devfs interface creation"); SYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tundebug, 0, ""); +static int tun_busy_locked(struct tuntap_softc *tp); +static void tun_unbusy_locked(struct tuntap_softc *tp); +static int tun_busy(struct tuntap_softc *tp); +static void tun_unbusy(struct tuntap_softc *tp); + static int tuntap_name2info(const char *name, int *unit, int *flags); static void tunclone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev); @@ -304,6 +311,65 @@ VNET_DEFINE_STATIC(SLIST_HEAD(, tuntap_driver_cloner), #define V_tuntap_driver_cloners VNET(tuntap_driver_cloners) /* + * Mechanism for marking a tunnel device as busy so that we can safely do some + * orthogonal operations (such as operations on devices) without racing against + * tun_destroy. tun_destroy will wait on the condvar if we're at all busy or + * open, to be woken up when the condition is alleviated. + */ +static int +tun_busy_locked(struct tuntap_softc *tp) +{ + + TUN_LOCK_ASSERT(tp); + if ((tp->tun_flags & TUN_DYING) != 0) { + /* + * Perhaps unintuitive, but the device is busy going away. + * Other interpretations of EBUSY from tun_busy make little + * sense, since making a busy device even more busy doesn't + * sound like a problem. + */ + return (EBUSY); + } + + ++tp->tun_busy; + return (0); +} + +static void +tun_unbusy_locked(struct tuntap_softc *tp) +{ + + TUN_LOCK_ASSERT(tp); + KASSERT(tp->tun_busy != 0, ("tun_unbusy: called for non-busy tunnel")); + + --tp->tun_busy; + /* Wake up anything that may be waiting on our busy tunnel. */ + if (tp->tun_busy == 0) + cv_broadcast(&tp->tun_cv); +} + +static int +tun_busy(struct tuntap_softc *tp) +{ + int ret; + + TUN_LOCK(tp); + ret = tun_busy_locked(tp); + TUN_UNLOCK(tp); + return (ret); +} + + +static void +tun_unbusy(struct tuntap_softc *tp) +{ + + TUN_LOCK(tp); + tun_unbusy_locked(tp); + TUN_UNLOCK(tp); +} + +/* * Sets unit and/or flags given the device name. Must be called with correct * vnet context. */ @@ -531,7 +597,7 @@ tun_destroy(struct tuntap_softc *tp) TUN_LOCK(tp); tp->tun_flags |= TUN_DYING; - if ((tp->tun_flags & TUN_OPEN) != 0) + if (tp->tun_busy != 0) cv_wait_unlock(&tp->tun_cv, &tp->tun_mtx); else TUN_UNLOCK(tp); @@ -885,6 +951,8 @@ tunopen(struct cdev *dev, int flag, int mode, struct t return (EBUSY); } + error = tun_busy_locked(tp); + KASSERT(error == 0, ("Must be able to busy an unopen tunnel")); ifp = TUN2IFP(tp); if ((tp->tun_flags & TUN_L2) != 0) { @@ -988,7 +1056,7 @@ out: tp->tun_flags &= ~TUN_OPEN; tp->tun_pid = 0; - cv_broadcast(&tp->tun_cv); + tun_unbusy_locked(tp); TUN_UNLOCK(tp); return (0); }