--- a/sys/net/pf/pf.c +++ b/sys/net/pf/pf.c @@ -911,10 +911,12 @@ pf_state_key_attach(struct pfi_kif *kif, struct pf_state_key *sk, if ((si = kmalloc(sizeof(struct pf_state_item), M_PFSTATEITEMPL, M_NOWAIT)) == NULL) { - pf_state_key_detach(s, idx); + /* + * We hold pf_global_statetbl_lock exclusively for + * PFSTATE_STACK_GLOBAL states; pf_state_key_detach() + * would re-acquire it -> lockmgr "locking against + * myself" panic. Use the non-locking variant here. + */ + pf_state_key_detach_unlocked(s, idx); error = -1; goto failed; /* collision! */ } --- a/sys/net/pf/pf.c (helper) +++ b/sys/net/pf/pf.c @@ new helper before pf_state_key_detach +/* + * Like pf_state_key_detach() but MUST be called with the appropriate + * statetbl lock (global or per-cpu) already held exclusively. + */ +static void +pf_state_key_detach_unlocked(struct pf_state *s, int idx) +{ + struct pf_state_item *si; + int cpu; + + if (s->state_flags & PFSTATE_STACK_GLOBAL) { + cpu = ncpus; + } else { + cpu = mycpu->gd_cpuid; + } + si = TAILQ_FIRST(&s->key[idx]->states); + while (si && si->s != s) + si = TAILQ_NEXT(si, entry); + if (si) { + TAILQ_REMOVE(&s->key[idx]->states, si, entry); + kfree(si, M_PFSTATEITEMPL); + } + if (TAILQ_EMPTY(&s->key[idx]->states)) { + RB_REMOVE(pf_state_tree, &pf_statetbl[cpu], s->key[idx]); + pf_state_key_detach_release(s, idx); + } +}