Add a new interface flag, IFF_DYING, which is set when a device driver
calls if_free(), and remains set if the refcount is elevated. IF_DYING skips the bit in the if_flags bitmask previously used by IFF_NEEDSGIANT, so that an MFC can be done without changing which bit is used, as IFF_NEEDSGIANT is still present in 7.x. ifnet_byindex_ref() checks for IFF_DYING and returns NULL if it is set, preventing new references from by acquired by index, preventing monitoring sysctls from seeing it. Other lookup mechanisms currently do not check IFF_DYING, but may need to in the future. MFC after: 3 weeks
This commit is contained in:
parent
5e51cafc60
commit
242a8e72eb
82
sys/net/if.c
82
sys/net/if.c
@ -229,7 +229,7 @@ ifnet_byindex_ref(u_short idx)
|
|||||||
|
|
||||||
IFNET_RLOCK();
|
IFNET_RLOCK();
|
||||||
ifp = ifnet_byindex_locked(idx);
|
ifp = ifnet_byindex_locked(idx);
|
||||||
if (ifp == NULL) {
|
if (ifp == NULL || (ifp->if_flags & IFF_DYING)) {
|
||||||
IFNET_RUNLOCK();
|
IFNET_RUNLOCK();
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
@ -526,43 +526,21 @@ if_alloc(u_char type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the struct ifnet, the associated index, and the layer 2 common
|
* Do the actual work of freeing a struct ifnet, associated index, and layer
|
||||||
* structure if needed. All the work is done in if_free_type().
|
* 2 common structure. This call is made when the last reference to an
|
||||||
*
|
* interface is released.
|
||||||
* Do not add code to this function! Add it to if_free_type().
|
|
||||||
*/
|
*/
|
||||||
void
|
static void
|
||||||
if_free(struct ifnet *ifp)
|
if_free_internal(struct ifnet *ifp)
|
||||||
{
|
{
|
||||||
|
|
||||||
if_free_type(ifp, ifp->if_alloctype);
|
KASSERT((ifp->if_flags & IFF_DYING),
|
||||||
}
|
("if_free_internal: interface not dying"));
|
||||||
|
|
||||||
/*
|
|
||||||
* Do the actual work of freeing a struct ifnet, associated index, and
|
|
||||||
* layer 2 common structure. This version should only be called by
|
|
||||||
* intefaces that switch their type after calling if_alloc().
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
if_free_type(struct ifnet *ifp, u_char type)
|
|
||||||
{
|
|
||||||
INIT_VNET_NET(curvnet); /* ifp->if_vnet can be NULL here ! */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Some drivers modify if_type, so we can't rely on it being the
|
|
||||||
* same in free as it was in alloc. Now that we have if_alloctype,
|
|
||||||
* we should just use that, but drivers expect to pass a type.
|
|
||||||
*/
|
|
||||||
KASSERT(ifp->if_alloctype == type,
|
|
||||||
("if_free_type: type (%d) != alloctype (%d)", type,
|
|
||||||
ifp->if_alloctype));
|
|
||||||
|
|
||||||
if (!refcount_release(&ifp->if_refcount))
|
|
||||||
return;
|
|
||||||
|
|
||||||
IFNET_WLOCK();
|
IFNET_WLOCK();
|
||||||
KASSERT(ifp == ifnet_byindex_locked(ifp->if_index),
|
KASSERT(ifp == ifnet_byindex_locked(ifp->if_index),
|
||||||
("%s: freeing unallocated ifnet", ifp->if_xname));
|
("%s: freeing unallocated ifnet", ifp->if_xname));
|
||||||
|
|
||||||
ifnet_setbyindex(ifp->if_index, NULL);
|
ifnet_setbyindex(ifp->if_index, NULL);
|
||||||
while (V_if_index > 0 && ifnet_byindex_locked(V_if_index) == NULL)
|
while (V_if_index > 0 && ifnet_byindex_locked(V_if_index) == NULL)
|
||||||
V_if_index--;
|
V_if_index--;
|
||||||
@ -576,6 +554,44 @@ if_free_type(struct ifnet *ifp, u_char type)
|
|||||||
free(ifp, M_IFNET);
|
free(ifp, M_IFNET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This version should only be called by intefaces that switch their type
|
||||||
|
* after calling if_alloc(). if_free_type() will go away again now that we
|
||||||
|
* have if_alloctype to cache the original allocation type. For now, assert
|
||||||
|
* that they match, since we require that in practice.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
if_free_type(struct ifnet *ifp, u_char type)
|
||||||
|
{
|
||||||
|
INIT_VNET_NET(curvnet); /* ifp->if_vnet can be NULL here ! */
|
||||||
|
|
||||||
|
KASSERT(ifp->if_alloctype == type,
|
||||||
|
("if_free_type: type (%d) != alloctype (%d)", type,
|
||||||
|
ifp->if_alloctype));
|
||||||
|
|
||||||
|
ifp->if_flags |= IFF_DYING; /* XXX: Locking */
|
||||||
|
if (!refcount_release(&ifp->if_refcount))
|
||||||
|
return;
|
||||||
|
if_free_internal(ifp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the normal version of if_free(), used by device drivers to free a
|
||||||
|
* detached network interface. The contents of if_free_type() will move into
|
||||||
|
* here when if_free_type() goes away.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
if_free(struct ifnet *ifp)
|
||||||
|
{
|
||||||
|
|
||||||
|
if_free_type(ifp, ifp->if_alloctype);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interfaces to keep an ifnet type-stable despite the possibility of the
|
||||||
|
* driver calling if_free(). If there are additional references, we defer
|
||||||
|
* freeing the underlying data structure.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
if_ref(struct ifnet *ifp)
|
if_ref(struct ifnet *ifp)
|
||||||
{
|
{
|
||||||
@ -588,7 +604,9 @@ void
|
|||||||
if_rele(struct ifnet *ifp)
|
if_rele(struct ifnet *ifp)
|
||||||
{
|
{
|
||||||
|
|
||||||
if_free(ifp);
|
if (!refcount_release(&ifp->if_refcount))
|
||||||
|
return;
|
||||||
|
if_free_internal(ifp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -149,6 +149,7 @@ struct if_data {
|
|||||||
#define IFF_PPROMISC 0x20000 /* (n) user-requested promisc mode */
|
#define IFF_PPROMISC 0x20000 /* (n) user-requested promisc mode */
|
||||||
#define IFF_MONITOR 0x40000 /* (n) user-requested monitor mode */
|
#define IFF_MONITOR 0x40000 /* (n) user-requested monitor mode */
|
||||||
#define IFF_STATICARP 0x80000 /* (n) static ARP */
|
#define IFF_STATICARP 0x80000 /* (n) static ARP */
|
||||||
|
#define IFF_DYING 0x200000 /* (n) interface is winding down */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Old names for driver flags so that user space tools can continue to use
|
* Old names for driver flags so that user space tools can continue to use
|
||||||
@ -162,7 +163,8 @@ struct if_data {
|
|||||||
/* flags set internally only: */
|
/* flags set internally only: */
|
||||||
#define IFF_CANTCHANGE \
|
#define IFF_CANTCHANGE \
|
||||||
(IFF_BROADCAST|IFF_POINTOPOINT|IFF_DRV_RUNNING|IFF_DRV_OACTIVE|\
|
(IFF_BROADCAST|IFF_POINTOPOINT|IFF_DRV_RUNNING|IFF_DRV_OACTIVE|\
|
||||||
IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI|IFF_SMART|IFF_PROMISC)
|
IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI|IFF_SMART|IFF_PROMISC|\
|
||||||
|
IFF_DYING)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Values for if_link_state.
|
* Values for if_link_state.
|
||||||
|
Loading…
Reference in New Issue
Block a user