get rid of NET_LOCK in the pf purge work
authordlg <dlg@openbsd.org>
Fri, 25 Nov 2022 03:45:39 +0000 (03:45 +0000)
committerdlg <dlg@openbsd.org>
Fri, 25 Nov 2022 03:45:39 +0000 (03:45 +0000)
pf purge was moved to systqmp (to get it away from KERNEL_LOCK)
which is also used as the backend for things like intr_barrier and
sched_barrier. it is common for network cards to call intr_barrier
while holding NET_LOCK, and if pf is trying to get the NET_LOCK in
the purge tasks that are now running in systqmp, it's a deadlock.
bluhm@ hit this exact issue.

sashan@ has been working to get rid of the need for NET_LOCK in pf,
so now we can remove the NET_LOCKs here rather than create a pf
specific taskq to run these tasks in.

ok sashan@ bluhm@

sys/net/pf.c

index 4203911..2552da3 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pf.c,v 1.1153 2022/11/12 02:48:14 kn Exp $ */
+/*     $OpenBSD: pf.c,v 1.1154 2022/11/25 03:45:39 dlg Exp $ */
 
 /*
  * Copyright (c) 2001 Daniel Hartmeier
@@ -1603,9 +1603,6 @@ pf_purge(void *null)
 {
        unsigned int interval = max(1, pf_default_rule.timeout[PFTM_INTERVAL]);
 
-       /* XXX is NET_LOCK necessary? */
-       NET_LOCK();
-
        PF_LOCK();
 
        pf_purge_expired_src_nodes();
@@ -1616,7 +1613,6 @@ pf_purge(void *null)
         * Fragments don't require PF_LOCK(), they use their own lock.
         */
        pf_purge_expired_fragments();
-       NET_UNLOCK();
 
        /* interpret the interval as idle time between runs */
        timeout_add_sec(&pf_purge_to, interval);
@@ -1891,7 +1887,6 @@ pf_purge_expired_states(const unsigned int limit, const unsigned int collect)
        if (SLIST_EMPTY(&gcl))
                return (scanned);
 
-       NET_LOCK();
        rw_enter_write(&pf_state_list.pfs_rwl);
        PF_LOCK();
        PF_STATE_ENTER_WRITE();
@@ -1904,7 +1899,6 @@ pf_purge_expired_states(const unsigned int limit, const unsigned int collect)
        PF_STATE_EXIT_WRITE();
        PF_UNLOCK();
        rw_exit_write(&pf_state_list.pfs_rwl);
-       NET_UNLOCK();
 
        while ((st = SLIST_FIRST(&gcl)) != NULL) {
                SLIST_REMOVE_HEAD(&gcl, gc_list);