Hello, people who will be running pf(4) with bluhm's diff [1], may trip one of the asserts triggered by pf_state_key_link_reverse() here:
7366 void 7367 pf_state_key_link_reverse(struct pf_state_key *sk, struct pf_state_key *skrev) 7368 { 7369 /* Note that sk and skrev may be equal, then we refcount twice. */ 7370 KASSERT(sk->reverse == NULL); 7371 KASSERT(skrev->reverse == NULL); 7372 sk->reverse = pf_state_key_ref(skrev); 7373 skrev->reverse = pf_state_key_ref(sk); 7374 } pf(4) currently does not provide a mutual access to state instances. so it may happen pf(4) will be handling more packets, which will be updating the same state. This is the situation of one winner and more losers. At this point I'm suggesting to change those asserts to take the race into account. diff below makes pf_state_key_link_reverse() happy when pf(4) runs in parallel. would it be OK to commit it once bluhm's diff [1] will be in? thanks and regards sashan [1] https://marc.info/?l=openbsd-tech&m=161903387904923&w=2 --------8<---------------8<---------------8<------------------8<-------- diff --git a/sys/net/pf.c b/sys/net/pf.c index 28aa6157552..d4212c21d7b 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -7366,11 +7366,20 @@ pf_inp_unlink(struct inpcb *inp) void pf_state_key_link_reverse(struct pf_state_key *sk, struct pf_state_key *skrev) { - /* Note that sk and skrev may be equal, then we refcount twice. */ - KASSERT(sk->reverse == NULL); - KASSERT(skrev->reverse == NULL); - sk->reverse = pf_state_key_ref(skrev); - skrev->reverse = pf_state_key_ref(sk); + struct pf_state_key *old_reverse; + + old_reverse = atomic_cas_ptr(&sk->reverse, NULL, skrev); + if (old_reverse != NULL) + KASSERT(old_reverse == skrev); + else + pf_state_key_ref(skrev); + + + old_reverse = atomic_cas_ptr(&skrev->reverse, NULL, sk); + if (old_reverse != NULL) + KASSERT(old_reverse == sk); + else + pf_state_key_ref(sk); } #if NPFLOG > 0