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, *s4p, *s4n; #ifdef INET6 - struct dyn_ipv6_state *s6, *s6n; + struct dyn_ipv6_state *s6, *s6p, *s6n; #endif int cached_count, i; @@ -2057,10 +2057,9 @@ * 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 { \ +#define DYN_FREE_STATES(s, prev, next, name) do { \ + prev = NULL; \ s = SLIST_FIRST(&V_dyn_expired_ ## name); \ while (s != NULL) { \ next = SLIST_NEXT(s, expired); \ @@ -2070,17 +2069,23 @@ if (i == cached_count) { \ if (s->type == O_LIMIT_PARENT && \ s->limit->count != 0) { \ + prev = s; \ s = next; \ continue; \ } \ - SLIST_REMOVE(&V_dyn_expired_ ## name, \ - s, dyn_ ## name ## _state, expired); \ + if (prev) \ + SLIST_REMOVE_AFTER(prev, expired); \ + else { \ + SLIST_REMOVE_HEAD( \ + &V_dyn_expired_ ## name, 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); \ } \ + prev = s; \ s = next; \ } \ } while (0) @@ -2095,9 +2100,9 @@ * IPFW_UH_WLOCK to protect access to these lists. */ DYN_EXPIRED_LOCK(); - DYN_FREE_STATES(s4, s4n, ipv4); + DYN_FREE_STATES(s4, s4p, s4n, ipv4); #ifdef INET6 - DYN_FREE_STATES(s6, s6n, ipv6); + DYN_FREE_STATES(s6, s6p, s6n, ipv6); #endif DYN_EXPIRED_UNLOCK(); #undef DYN_FREE_STATES