Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 19 Dec 2025 14:13:19 +0000
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: ae96ff302f8a - main - pf: Avoid taking the pf rules write lock in a couple of ioctls
Message-ID:  <69455d7f.3ca92.3cf68097@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=ae96ff302f8ae50903a96d3a1857f9acf243f3c4

commit ae96ff302f8ae50903a96d3a1857f9acf243f3c4
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2025-12-19 14:07:26 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2025-12-19 14:07:26 +0000

    pf: Avoid taking the pf rules write lock in a couple of ioctls
    
    The DIOCGETRULES ioctl handlers has taken the write lock ever since
    fine-grained locking was merged to pf, but I believe it's unneeded.  Use
    the read lock instead.
    
    DIOCGETRULENV takes the write lock as well but I believe this is only
    required when clearing rule counters.  Acquire the read lock if that is
    not the case.
    
    Reviewed by:    kp, allanjude
    MFC after:      2 weeks
    Sponsored by:   OPNsense
    Sponsored by:   Klara, Inc.
    Differential Revision:  https://reviews.freebsd.org/D54292
---
 sys/netpfil/pf/pf_ioctl.c | 91 ++++++++++++++++++++++-------------------------
 sys/netpfil/pf/pf_nv.c    |  2 +-
 sys/netpfil/pf/pf_nv.h    |  2 +-
 3 files changed, 45 insertions(+), 50 deletions(-)

diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 9856842c72b2..ca1815984797 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -2087,19 +2087,20 @@ pf_rule_to_krule(const struct pf_rule *rule, struct pf_krule *krule)
 int
 pf_ioctl_getrules(struct pfioc_rule *pr)
 {
+	PF_RULES_RLOCK_TRACKER;
 	struct pf_kruleset	*ruleset;
 	struct pf_krule		*tail;
 	int			 rs_num;
 
-	PF_RULES_WLOCK();
+	PF_RULES_RLOCK();
 	ruleset = pf_find_kruleset(pr->anchor);
 	if (ruleset == NULL) {
-		PF_RULES_WUNLOCK();
+		PF_RULES_RUNLOCK();
 		return (EINVAL);
 	}
 	rs_num = pf_get_ruleset_number(pr->rule.action);
 	if (rs_num >= PF_RULESET_MAX) {
-		PF_RULES_WUNLOCK();
+		PF_RULES_RUNLOCK();
 		return (EINVAL);
 	}
 	tail = TAILQ_LAST(ruleset->rules[rs_num].active.ptr,
@@ -2109,7 +2110,7 @@ pf_ioctl_getrules(struct pfioc_rule *pr)
 	else
 		pr->nr = 0;
 	pr->ticket = ruleset->rules[rs_num].active.ticket;
-	PF_RULES_WUNLOCK();
+	PF_RULES_RUNLOCK();
 
 	return (0);
 }
@@ -3692,6 +3693,7 @@ DIOCADDRULENV_error:
 	}
 
 	case DIOCGETRULENV: {
+		PF_RULES_RLOCK_TRACKER;
 		struct pfioc_nv		*nv = (struct pfioc_nv *)addr;
 		nvlist_t		*nvrule = NULL;
 		nvlist_t		*nvl = NULL;
@@ -3702,6 +3704,13 @@ DIOCADDRULENV_error:
 		bool			 clear_counter = false;
 
 #define	ERROUT(x)	ERROUT_IOCTL(DIOCGETRULENV_error, x)
+#define	ERROUT_LOCKED(x) do {			\
+	if (clear_counter)			\
+		PF_RULES_WUNLOCK();		\
+	else					\
+		PF_RULES_RUNLOCK();		\
+	ERROUT(x);				\
+} while (0)
 
 		if (nv->len > pf_ioctl_maxcount)
 			ERROUT(ENOMEM);
@@ -3733,78 +3742,64 @@ DIOCADDRULENV_error:
 
 		nr = nvlist_get_number(nvl, "nr");
 
-		PF_RULES_WLOCK();
+		if (clear_counter)
+			PF_RULES_WLOCK();
+		else
+			PF_RULES_RLOCK();
 		ruleset = pf_find_kruleset(nvlist_get_string(nvl, "anchor"));
-		if (ruleset == NULL) {
-			PF_RULES_WUNLOCK();
-			ERROUT(ENOENT);
-		}
+		if (ruleset == NULL)
+			ERROUT_LOCKED(ENOENT);
 
 		rs_num = pf_get_ruleset_number(nvlist_get_number(nvl, "ruleset"));
-		if (rs_num >= PF_RULESET_MAX) {
-			PF_RULES_WUNLOCK();
-			ERROUT(EINVAL);
-		}
+		if (rs_num >= PF_RULESET_MAX)
+			ERROUT_LOCKED(EINVAL);
 
 		if (nvlist_get_number(nvl, "ticket") !=
-		    ruleset->rules[rs_num].active.ticket) {
-			PF_RULES_WUNLOCK();
-			ERROUT(EBUSY);
-		}
+		    ruleset->rules[rs_num].active.ticket)
+			ERROUT_LOCKED(EBUSY);
 
-		if ((error = nvlist_error(nvl))) {
-			PF_RULES_WUNLOCK();
-			ERROUT(error);
-		}
+		if ((error = nvlist_error(nvl)))
+			ERROUT_LOCKED(error);
 
 		rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
 		while ((rule != NULL) && (rule->nr != nr))
 			rule = TAILQ_NEXT(rule, entries);
-		if (rule == NULL) {
-			PF_RULES_WUNLOCK();
-			ERROUT(EBUSY);
-		}
+		if (rule == NULL)
+			ERROUT_LOCKED(EBUSY);
 
 		nvrule = pf_krule_to_nvrule(rule);
 
 		nvlist_destroy(nvl);
 		nvl = nvlist_create(0);
-		if (nvl == NULL) {
-			PF_RULES_WUNLOCK();
-			ERROUT(ENOMEM);
-		}
+		if (nvl == NULL)
+			ERROUT_LOCKED(ENOMEM);
 		nvlist_add_number(nvl, "nr", nr);
 		nvlist_add_nvlist(nvl, "rule", nvrule);
 		nvlist_destroy(nvrule);
 		nvrule = NULL;
-		if (pf_kanchor_nvcopyout(ruleset, rule, nvl)) {
-			PF_RULES_WUNLOCK();
-			ERROUT(EBUSY);
-		}
+		if (pf_kanchor_nvcopyout(ruleset, rule, nvl))
+			ERROUT_LOCKED(EBUSY);
 
 		free(nvlpacked, M_NVLIST);
 		nvlpacked = nvlist_pack(nvl, &nv->len);
-		if (nvlpacked == NULL) {
-			PF_RULES_WUNLOCK();
-			ERROUT(ENOMEM);
-		}
+		if (nvlpacked == NULL)
+			ERROUT_LOCKED(ENOMEM);
 
-		if (nv->size == 0) {
-			PF_RULES_WUNLOCK();
-			ERROUT(0);
-		}
-		else if (nv->size < nv->len) {
-			PF_RULES_WUNLOCK();
-			ERROUT(ENOSPC);
-		}
+		if (nv->size == 0)
+			ERROUT_LOCKED(0);
+		else if (nv->size < nv->len)
+			ERROUT_LOCKED(ENOSPC);
 
-		if (clear_counter)
+		if (clear_counter) {
 			pf_krule_clear_counters(rule);
-
-		PF_RULES_WUNLOCK();
+			PF_RULES_WUNLOCK();
+		} else {
+			PF_RULES_RUNLOCK();
+		}
 
 		error = copyout(nvlpacked, nv->data, nv->len);
 
+#undef ERROUT_LOCKED
 #undef ERROUT
 DIOCGETRULENV_error:
 		free(nvlpacked, M_NVLIST);
diff --git a/sys/netpfil/pf/pf_nv.c b/sys/netpfil/pf/pf_nv.c
index 2f484e2dabc6..3e741dd39974 100644
--- a/sys/netpfil/pf/pf_nv.c
+++ b/sys/netpfil/pf/pf_nv.c
@@ -684,7 +684,7 @@ error:
 }
 
 nvlist_t *
-pf_krule_to_nvrule(struct pf_krule *rule)
+pf_krule_to_nvrule(const struct pf_krule *rule)
 {
 	nvlist_t *nvl, *tmp;
 	u_int64_t src_nodes_total = 0;
diff --git a/sys/netpfil/pf/pf_nv.h b/sys/netpfil/pf/pf_nv.h
index cf9fbf8bcf5b..9e43ff1e642a 100644
--- a/sys/netpfil/pf/pf_nv.h
+++ b/sys/netpfil/pf/pf_nv.h
@@ -78,7 +78,7 @@ int	pf_nvstring(const nvlist_t *, const char *, char *, size_t);
 
 int		 pf_check_rule_addr(const struct pf_rule_addr *);
 
-nvlist_t	*pf_krule_to_nvrule(struct pf_krule *);
+nvlist_t	*pf_krule_to_nvrule(const struct pf_krule *);
 int		 pf_nvrule_to_krule(const nvlist_t *, struct pf_krule *);
 int		 pf_nvstate_kill_to_kstate_kill(const nvlist_t *,
 		    struct pf_kstate_kill *);


help

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69455d7f.3ca92.3cf68097>