diff options
author | Kristof Provost <kp@FreeBSD.org> | 2020-11-25 15:07:22 +0000 |
---|---|---|
committer | Kristof Provost <kp@FreeBSD.org> | 2020-11-25 15:07:22 +0000 |
commit | a779388f8bb3608b06700268e8cfe872bb97dea8 (patch) | |
tree | 2235ade75168cd342a0fc1d613c91853107641a0 /sys/net/if.c | |
parent | 3063e1e56b509373d143a3a4c67d388bd390f268 (diff) | |
download | src-test2-a779388f8bb3608b06700268e8cfe872bb97dea8.tar.gz src-test2-a779388f8bb3608b06700268e8cfe872bb97dea8.zip |
Notes
Diffstat (limited to 'sys/net/if.c')
-rw-r--r-- | sys/net/if.c | 122 |
1 files changed, 82 insertions, 40 deletions
diff --git a/sys/net/if.c b/sys/net/if.c index 5c7b60da1778..07078448e3f6 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -275,6 +275,8 @@ static void if_delgroups(struct ifnet *); static void if_attach_internal(struct ifnet *, int, struct if_clone *); static int if_detach_internal(struct ifnet *, int, struct if_clone **); static void if_siocaddmulti(void *, int); +static void if_link_ifnet(struct ifnet *); +static bool if_unlink_ifnet(struct ifnet *, bool); #ifdef VIMAGE static int if_vmove(struct ifnet *, struct vnet *); #endif @@ -468,15 +470,81 @@ VNET_SYSUNINIT(vnet_if_uninit, SI_SUB_INIT_IF, SI_ORDER_FIRST, vnet_if_uninit, NULL); static void +if_link_ifnet(struct ifnet *ifp) +{ + + IFNET_WLOCK(); + CK_STAILQ_INSERT_TAIL(&V_ifnet, ifp, if_link); +#ifdef VIMAGE + curvnet->vnet_ifcnt++; +#endif + IFNET_WUNLOCK(); +} + +static bool +if_unlink_ifnet(struct ifnet *ifp, bool vmove) +{ + struct ifnet *iter; + int found = 0; + + IFNET_WLOCK(); + CK_STAILQ_FOREACH(iter, &V_ifnet, if_link) + if (iter == ifp) { + CK_STAILQ_REMOVE(&V_ifnet, ifp, ifnet, if_link); + if (!vmove) + ifp->if_flags |= IFF_DYING; + found = 1; + break; + } +#ifdef VIMAGE + curvnet->vnet_ifcnt--; +#endif + IFNET_WUNLOCK(); + + return (found); +} + +static void vnet_if_return(const void *unused __unused) { struct ifnet *ifp, *nifp; + struct ifnet **pending; + int found, i; + + i = 0; + + /* + * We need to protect our access to the V_ifnet tailq. Ordinarily we'd + * enter NET_EPOCH, but that's not possible, because if_vmove() calls + * if_detach_internal(), which waits for NET_EPOCH callbacks to + * complete. We can't do that from within NET_EPOCH. + * + * However, we can also use the IFNET_xLOCK, which is the V_ifnet + * read/write lock. We cannot hold the lock as we call if_vmove() + * though, as that presents LOR w.r.t ifnet_sx, in_multi_sx and iflib + * ctx lock. + */ + IFNET_WLOCK(); + + pending = malloc(sizeof(struct ifnet *) * curvnet->vnet_ifcnt, + M_IFNET, M_WAITOK | M_ZERO); /* Return all inherited interfaces to their parent vnets. */ CK_STAILQ_FOREACH_SAFE(ifp, &V_ifnet, if_link, nifp) { - if (ifp->if_home_vnet != ifp->if_vnet) - if_vmove(ifp, ifp->if_home_vnet); + if (ifp->if_home_vnet != ifp->if_vnet) { + found = if_unlink_ifnet(ifp, true); + MPASS(found); + + pending[i++] = ifp; + } } + IFNET_WUNLOCK(); + + for (int j = 0; j < i; j++) { + if_vmove(pending[j], pending[j]->if_home_vnet); + } + + free(pending, M_IFNET); } VNET_SYSUNINIT(vnet_if_return, SI_SUB_VNET_DONE, SI_ORDER_ANY, vnet_if_return, NULL); @@ -906,12 +974,7 @@ if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc) } #endif - IFNET_WLOCK(); - CK_STAILQ_INSERT_TAIL(&V_ifnet, ifp, if_link); -#ifdef VIMAGE - curvnet->vnet_ifcnt++; -#endif - IFNET_WUNLOCK(); + if_link_ifnet(ifp); if (domain_init_status >= 2) if_attachdomain1(ifp); @@ -1049,9 +1112,12 @@ if_purgemaddrs(struct ifnet *ifp) void if_detach(struct ifnet *ifp) { + bool found; CURVNET_SET_QUIET(ifp->if_vnet); - if_detach_internal(ifp, 0, NULL); + found = if_unlink_ifnet(ifp, false); + if (found) + if_detach_internal(ifp, 0, NULL); CURVNET_RESTORE(); } @@ -1071,46 +1137,16 @@ if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp) struct ifaddr *ifa; int i; struct domain *dp; - struct ifnet *iter; - int found = 0; #ifdef VIMAGE bool shutdown; shutdown = VNET_IS_SHUTTING_DOWN(ifp->if_vnet); #endif - IFNET_WLOCK(); - CK_STAILQ_FOREACH(iter, &V_ifnet, if_link) - if (iter == ifp) { - CK_STAILQ_REMOVE(&V_ifnet, ifp, ifnet, if_link); - if (!vmove) - ifp->if_flags |= IFF_DYING; - found = 1; - break; - } - IFNET_WUNLOCK(); - if (!found) { - /* - * While we would want to panic here, we cannot - * guarantee that the interface is indeed still on - * the list given we don't hold locks all the way. - */ - return (ENOENT); -#if 0 - if (vmove) - panic("%s: ifp=%p not on the ifnet tailq %p", - __func__, ifp, &V_ifnet); - else - return; /* XXX this should panic as well? */ -#endif - } /* * At this point we know the interface still was on the ifnet list * and we removed it so we are in a stable state. */ -#ifdef VIMAGE - curvnet->vnet_ifcnt--; -#endif epoch_wait_preempt(net_epoch_preempt); /* @@ -1340,6 +1376,7 @@ if_vmove_loan(struct thread *td, struct ifnet *ifp, char *ifname, int jid) struct prison *pr; struct ifnet *difp; int error; + bool found; bool shutdown; /* Try to find the prison within our visibility. */ @@ -1376,6 +1413,9 @@ if_vmove_loan(struct thread *td, struct ifnet *ifp, char *ifname, int jid) } CURVNET_RESTORE(); + found = if_unlink_ifnet(ifp, true); + MPASS(found); + /* Move the interface into the child jail/vnet. */ error = if_vmove(ifp, pr->pr_vnet); @@ -1393,7 +1433,7 @@ if_vmove_reclaim(struct thread *td, char *ifname, int jid) struct prison *pr; struct vnet *vnet_dst; struct ifnet *ifp; - int error; + int error, found; bool shutdown; /* Try to find the prison within our visibility. */ @@ -1431,6 +1471,8 @@ if_vmove_reclaim(struct thread *td, char *ifname, int jid) } /* Get interface back from child jail/vnet. */ + found = if_unlink_ifnet(ifp, true); + MPASS(found); error = if_vmove(ifp, vnet_dst); CURVNET_RESTORE(); |