Index: sys/netpfil/ipfw/ip_fw_dynamic.c =================================================================== --- sys/netpfil/ipfw/ip_fw_dynamic.c +++ sys/netpfil/ipfw/ip_fw_dynamic.c @@ -2016,9 +2016,9 @@ static void dyn_free_states(struct ip_fw_chain *chain) { - struct dyn_ipv4_state *s4, *s4n; + struct dyn_ipv4_state *s4, *s4d, *s4t; #ifdef INET6 - struct dyn_ipv6_state *s6, *s6n; + struct dyn_ipv6_state *s6, *s6d, *s6t; #endif int cached_count, i; @@ -2057,31 +2057,31 @@ * list, if pointer to the object is in the dyn_hp_cache array, * keep it until next pass. Otherwise it is safe to free the * object. - * - * XXXAE: optimize this to use SLIST_REMOVE_AFTER. */ -#define DYN_FREE_STATES(s, next, name) do { \ - s = SLIST_FIRST(&V_dyn_expired_ ## name); \ - while (s != NULL) { \ - next = SLIST_NEXT(s, expired); \ +#define DYN_FREE_STATES(s, del, tmp, name) do { \ + del = NULL; \ + SLIST_FOREACH_SAFE(s, &V_dyn_expired_ ## name, expired, tmp) { \ for (i = 0; i < cached_count; i++) \ if (dyn_hp_cache[i] == s) \ break; \ - if (i == cached_count) { \ - if (s->type == O_LIMIT_PARENT && \ - s->limit->count != 0) { \ - s = next; \ - continue; \ + if (i != cached_count) \ + del = s; \ + else if (s->type == O_LIMIT_PARENT && \ + s->limit->count != 0) \ + del = s; \ + else { \ + if (del) \ + SLIST_REMOVE_AFTER(del, expired); \ + else { \ + SLIST_REMOVE_HEAD( \ + &V_dyn_expired_ ## name, expired); \ } \ - SLIST_REMOVE(&V_dyn_expired_ ## name, \ - s, dyn_ ## name ## _state, expired); \ if (s->type == O_LIMIT_PARENT) \ uma_zfree(V_dyn_parent_zone, s->limit); \ else \ uma_zfree(V_dyn_data_zone, s->data); \ uma_zfree(V_dyn_ ## name ## _zone, s); \ } \ - s = next; \ } \ } while (0) @@ -2095,9 +2095,9 @@ * IPFW_UH_WLOCK to protect access to these lists. */ DYN_EXPIRED_LOCK(); - DYN_FREE_STATES(s4, s4n, ipv4); + DYN_FREE_STATES(s4, s4d, s4t, ipv4); #ifdef INET6 - DYN_FREE_STATES(s6, s6n, ipv6); + DYN_FREE_STATES(s6, s6d, s6t, ipv6); #endif DYN_EXPIRED_UNLOCK(); #undef DYN_FREE_STATES