Index: sys/net/if.c =================================================================== --- sys/net/if.c +++ sys/net/if.c @@ -1500,23 +1500,18 @@ } /* - * Remove a group from an interface + * Helper function to release group memory in if_delgroup and if_delgroups. + * Note this function assumes the IFNET lock is held, and will release it in + * order to call group event handlers. */ -int -if_delgroup(struct ifnet *ifp, const char *groupname) +static void +if_freegroup(struct ifnet *ifp, struct ifg_list *ifgl, const char *groupname) { - struct ifg_list *ifgl; struct ifg_member *ifgm; int freeifgl; - IFNET_WLOCK(); - CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) - if (!strcmp(ifgl->ifgl_group->ifg_group, groupname)) - break; - if (ifgl == NULL) { - IFNET_WUNLOCK(); - return (ENOENT); - } + /* Ensure we have the IFNET lock */ + IFNET_WLOCK_ASSERT(); freeifgl = 0; IF_ADDR_WLOCK(ifp); @@ -1534,6 +1529,8 @@ CK_STAILQ_REMOVE(&V_ifg_head, ifgl->ifgl_group, ifg_group, ifg_next); freeifgl = 1; } + + /* Drop the lock so that the event handler can be called */ IFNET_WUNLOCK(); epoch_wait_preempt(net_epoch_preempt); @@ -1545,6 +1542,27 @@ free(ifgl, M_TEMP); EVENTHANDLER_INVOKE(group_change_event, groupname); +} + +/* + * Remove a group from an interface + */ +int +if_delgroup(struct ifnet *ifp, const char *groupname) +{ + struct ifg_list *ifgl; + + IFNET_WLOCK(); + CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) + if (!strcmp(ifgl->ifgl_group->ifg_group, groupname)) + break; + if (ifgl == NULL) { + IFNET_WUNLOCK(); + return (ENOENT); + } + + /* if_freegroup will call IFNET_WUNLOCK() */ + if_freegroup(ifp, ifgl, groupname); return (0); } @@ -1556,9 +1574,7 @@ if_delgroups(struct ifnet *ifp) { struct ifg_list *ifgl; - struct ifg_member *ifgm; char groupname[IFNAMSIZ]; - int ifglfree; IFNET_WLOCK(); while (!CK_STAILQ_EMPTY(&ifp->if_groups)) { @@ -1566,32 +1582,8 @@ strlcpy(groupname, ifgl->ifgl_group->ifg_group, IFNAMSIZ); - IF_ADDR_WLOCK(ifp); - CK_STAILQ_REMOVE(&ifp->if_groups, ifgl, ifg_list, ifgl_next); - IF_ADDR_WUNLOCK(ifp); - - CK_STAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next) - if (ifgm->ifgm_ifp == ifp) - break; - - if (ifgm != NULL) - CK_STAILQ_REMOVE(&ifgl->ifgl_group->ifg_members, ifgm, ifg_member, - ifgm_next); - ifglfree = 0; - if (--ifgl->ifgl_group->ifg_refcnt == 0) { - CK_STAILQ_REMOVE(&V_ifg_head, ifgl->ifgl_group, ifg_group, ifg_next); - ifglfree = 1; - } - - IFNET_WUNLOCK(); - epoch_wait_preempt(net_epoch_preempt); - free(ifgm, M_TEMP); - if (ifglfree) { - EVENTHANDLER_INVOKE(group_detach_event, - ifgl->ifgl_group); - free(ifgl->ifgl_group, M_TEMP); - } - EVENTHANDLER_INVOKE(group_change_event, groupname); + /* if_freegroup calls IFNET_WUNLOCK() */ + if_freegroup(ifp, ifgl, groupname); IFNET_WLOCK(); }