From owner-svn-src-head@FreeBSD.ORG Wed Aug 26 11:13:10 2009 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id A41F2106568B; Wed, 26 Aug 2009 11:13:10 +0000 (UTC) (envelope-from rwatson@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 921468FC19; Wed, 26 Aug 2009 11:13:10 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n7QBDASR059798; Wed, 26 Aug 2009 11:13:10 GMT (envelope-from rwatson@svn.freebsd.org) Received: (from rwatson@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n7QBDA9S059796; Wed, 26 Aug 2009 11:13:10 GMT (envelope-from rwatson@svn.freebsd.org) Message-Id: <200908261113.n7QBDA9S059796@svn.freebsd.org> From: Robert Watson Date: Wed, 26 Aug 2009 11:13:10 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r196559 - head/sys/net X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 26 Aug 2009 11:13:10 -0000 Author: rwatson Date: Wed Aug 26 11:13:10 2009 New Revision: 196559 URL: http://svn.freebsd.org/changeset/base/196559 Log: Add IFNET_HOLD reserved pointer value for the ifindex ifnet array, which allows an index to be reserved for an ifnet without making the ifnet available for management operations. Use this in if_alloc() while the ifnet lock is released between initial index allocation and completion of ifnet initialization. Add ifindex_free() to centralize the implementation of releasing an ifindex value. Use in if_free() and if_vmove(), as well as when releasing a held index in if_alloc(). Reviewed by: bz MFC after: 3 days Modified: head/sys/net/if.c Modified: head/sys/net/if.c ============================================================================== --- head/sys/net/if.c Wed Aug 26 03:30:06 2009 (r196558) +++ head/sys/net/if.c Wed Aug 26 11:13:10 2009 (r196559) @@ -175,6 +175,13 @@ int ifqmaxlen = IFQ_MAXLEN; struct rwlock ifnet_rwlock; struct sx ifnet_sxlock; +/* + * The allocation of network interfaces is a rather non-atomic affair; we + * need to select an index before we are ready to expose the interface for + * use, so will use this pointer value to indicate reservation. + */ +#define IFNET_HOLD (void *)(uintptr_t)(-1) + static if_com_alloc_t *if_com_alloc[256]; static if_com_free_t *if_com_free[256]; @@ -193,6 +200,8 @@ ifnet_byindex_locked(u_short idx) if (idx > V_if_index) return (NULL); + if (V_ifindex_table[idx].ife_ifnet == IFNET_HOLD) + return (NULL); return (V_ifindex_table[idx].ife_ifnet); } @@ -228,18 +237,18 @@ ifnet_byindex_ref(u_short idx) * failure. */ static int -ifindex_alloc(u_short *idxp) +ifindex_alloc_locked(u_short *idxp) { u_short idx; IFNET_WLOCK_ASSERT(); /* - * Try to find an empty slot below if_index. If we fail, take the + * Try to find an empty slot below V_if_index. If we fail, take the * next slot. */ for (idx = 1; idx <= V_if_index; idx++) { - if (ifnet_byindex_locked(idx) == NULL) + if (V_ifindex_table[idx].ife_ifnet == NULL) break; } @@ -255,6 +264,27 @@ ifindex_alloc(u_short *idxp) } static void +ifindex_free_locked(u_short idx) +{ + + IFNET_WLOCK_ASSERT(); + + V_ifindex_table[idx].ife_ifnet = NULL; + while (V_if_index > 0 && + V_ifindex_table[V_if_index].ife_ifnet == NULL) + V_if_index--; +} + +static void +ifindex_free(u_short idx) +{ + + IFNET_WLOCK(); + ifindex_free_locked(idx); + IFNET_WUNLOCK(); +} + +static void ifnet_setbyindex_locked(u_short idx, struct ifnet *ifp) { @@ -370,11 +400,12 @@ if_alloc(u_char type) ifp = malloc(sizeof(struct ifnet), M_IFNET, M_WAITOK|M_ZERO); IFNET_WLOCK(); - if (ifindex_alloc(&idx) != 0) { + if (ifindex_alloc_locked(&idx) != 0) { IFNET_WUNLOCK(); free(ifp, M_IFNET); return (NULL); } + ifnet_setbyindex_locked(idx, IFNET_HOLD); IFNET_WUNLOCK(); ifp->if_index = idx; ifp->if_type = type; @@ -383,6 +414,7 @@ if_alloc(u_char type) ifp->if_l2com = if_com_alloc[type](type, ifp); if (ifp->if_l2com == NULL) { free(ifp, M_IFNET); + ifindex_free(idx); return (NULL); } } @@ -421,9 +453,7 @@ if_free_internal(struct ifnet *ifp) KASSERT(ifp == ifnet_byindex_locked(ifp->if_index), ("%s: freeing unallocated ifnet", ifp->if_xname)); - ifnet_setbyindex_locked(ifp->if_index, NULL); - while (V_if_index > 0 && ifnet_byindex_locked(V_if_index) == NULL) - V_if_index--; + ifindex_free_locked(ifp->if_index); IFNET_WUNLOCK(); if (if_com_free[ifp->if_alloctype] != NULL) @@ -916,18 +946,14 @@ if_vmove(struct ifnet *ifp, struct vnet * or we'd lock on one vnet and unlock on another. */ IFNET_WLOCK(); - ifnet_setbyindex_locked(ifp->if_index, NULL); - while (V_if_index > 0 && ifnet_byindex_locked(V_if_index) == NULL) - V_if_index--; - IFNET_WUNLOCK(); + ifindex_free_locked(ifp->if_index); /* * Switch to the context of the target vnet. */ CURVNET_SET_QUIET(new_vnet); - IFNET_WLOCK(); - if (ifindex_alloc(&idx) != 0) { + if (ifindex_alloc_locked(&idx) != 0) { IFNET_WUNLOCK(); panic("if_index overflow"); }