svn commit: r234651 - projects/pf/head/sys/contrib/pf/net

Gleb Smirnoff glebius at FreeBSD.org
Tue Apr 24 13:13:42 UTC 2012


Author: glebius
Date: Tue Apr 24 13:13:42 2012
New Revision: 234651
URL: http://svn.freebsd.org/changeset/base/234651

Log:
  States and source nodes reference rules, so when state or source node is
  expired a rule may potentially be deleted. In the new locking scheme this
  is a problem, since we don't have writer lock on rules in packet processing,
  and we don't like any additional atomic operations in forwarding path.
  
  To cope with that, pf_rm_rule() was split into two pieces - pf_unlink_rule(),
  that removes a rule from the ruleset, and pf_free_rule() that does actual
  freeing.
  
  Freeing of once used rules is performed solely by the pf expiry thread. It
  now performs naive mark-and-sweep algorithm, based on states and source
  nodes expiry run.
  
  We still account number of states per rule and number of source nodes,
  since they are important to drive adaptive expiry and 'max-src-conn'
  rules. When we get rid of pf giant lock, these increments/decrements
  should be reconsidered and probably made atomic.
  
  Also:
  - Migrate from PF_LOCK() to PF_RULES_WLOCK() in all rule manipulating ioctls.

Modified:
  projects/pf/head/sys/contrib/pf/net/pf.c
  projects/pf/head/sys/contrib/pf/net/pf_ioctl.c
  projects/pf/head/sys/contrib/pf/net/pfvar.h

Modified: projects/pf/head/sys/contrib/pf/net/pf.c
==============================================================================
--- projects/pf/head/sys/contrib/pf/net/pf.c	Tue Apr 24 12:54:04 2012	(r234650)
+++ projects/pf/head/sys/contrib/pf/net/pf.c	Tue Apr 24 13:13:42 2012	(r234651)
@@ -187,6 +187,9 @@ static struct mtx pf_sendqueue_mtx;
 #define	PF_QUEUE_LOCK()		mtx_lock(&pf_sendqueue_mtx)
 #define	PF_QUEUE_UNLOCK()	mtx_unlock(&pf_sendqueue_mtx)
 
+VNET_DEFINE(struct pf_rulequeue, pf_unlinked_rules);
+struct mtx pf_unlnkdrules_mtx;
+
 VNET_DEFINE(uma_zone_t,	 pf_sources_z);
 VNET_DEFINE(uma_zone_t,	 pf_rule_z);
 VNET_DEFINE(uma_zone_t,	 pf_pooladdr_z);
@@ -291,7 +294,8 @@ static struct pf_state	*pf_find_state(st
 static int		 pf_src_connlimit(struct pf_state **);
 static int		 pf_insert_src_node(struct pf_src_node **,
 			    struct pf_rule *, struct pf_addr *, sa_family_t);
-static void		 pf_purge_expired_states(int);
+static int		 pf_purge_expired_states(int);
+static void		 pf_purge_unlinked_rules(void);
 
 int in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len);
 
@@ -709,6 +713,10 @@ pf_initialize()
 	STAILQ_INIT(&V_pf_sendqueue);
 	mtx_init(&pf_sendqueue_mtx, "pf send queue", NULL, MTX_DEF);
 
+	/* Unlinked, but may be referenced rules. */
+	TAILQ_INIT(&V_pf_unlinked_rules);
+	mtx_init(&pf_unlnkdrules_mtx, "pf unlinked rules", NULL, MTX_DEF);
+
 	/* XXXGL: sort this out */
 	V_pf_rule_z = uma_zcreate("pf rules", sizeof(struct pf_rule),
 	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
@@ -761,6 +769,8 @@ pf_cleanup()
 	}
 	mtx_destroy(&pf_sendqueue_mtx);
 
+	mtx_destroy(&pf_unlnkdrules_mtx);
+
 	uma_zdestroy(V_pf_sources_z);
 	uma_zdestroy(V_pf_rule_z);
 	uma_zdestroy(V_pf_state_z);
@@ -1278,7 +1288,7 @@ pf_intr(void *v)
 void
 pf_purge_thread(void *v)
 {
-	int nloops = 0;
+	int fullrun;
 
 	CURVNET_SET((struct vnet *)v);
 
@@ -1298,14 +1308,15 @@ pf_purge_thread(void *v)
 		}
 
 		/* Process a fraction of the state table every second. */
-		pf_purge_expired_states(V_pf_hashmask /
+		fullrun = pf_purge_expired_states(V_pf_hashmask /
 			    V_pf_default_rule.timeout[PFTM_INTERVAL]);
 
 		/* Purge other expired types every PFTM_INTERVAL seconds. */
-		if (++nloops >= V_pf_default_rule.timeout[PFTM_INTERVAL]) {
+		if (fullrun) {
+			/* Order important: rules should be the last. */
 			pf_purge_expired_fragments();
 			pf_purge_expired_src_nodes();
-			nloops = 0;
+			pf_purge_unlinked_rules();
 		}
 
 		PF_UNLOCK();
@@ -1364,17 +1375,14 @@ pf_purge_expired_src_nodes()
 	    PF_HASHROW_LOCK(sh);
 	    LIST_FOREACH_SAFE(cur, &sh->nodes, entry, next) 
 		if (cur->states <= 0 && cur->expire <= time_uptime) {
-			if (cur->rule.ptr != NULL) {
+			if (cur->rule.ptr != NULL)
 				cur->rule.ptr->src_nodes--;
-				if (cur->rule.ptr->states_cur <= 0 &&
-				    cur->rule.ptr->max_src_nodes <= 0)
-					pf_rm_rule(NULL, cur->rule.ptr);
-			}
 			LIST_REMOVE(cur, entry);
 			V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
 			V_pf_status.src_nodes--;
 			uma_zfree(V_pf_sources_z, cur);
-		}
+		} else if (cur->rule.ptr != NULL)
+			cur->rule.ptr->rule_flag |= PFRULE_REFS;
 	    PF_HASHROW_UNLOCK(sh);
 	}
 }
@@ -1458,16 +1466,11 @@ pf_free_state(struct pf_state *cur)
 	KASSERT(cur->refs == 0, ("%s: %p has refs", __func__, cur));
 	KASSERT(cur->timeout == PFTM_UNLINKED, ("%s: timeout %u", __func__,
 	    cur->timeout));
-	if (--cur->rule.ptr->states_cur <= 0 &&
-	    cur->rule.ptr->src_nodes <= 0)
-		pf_rm_rule(NULL, cur->rule.ptr);
+	--cur->rule.ptr->states_cur;
 	if (cur->nat_rule.ptr != NULL)
-		if (--cur->nat_rule.ptr->states_cur <= 0 &&
-			cur->nat_rule.ptr->src_nodes <= 0)
-			pf_rm_rule(NULL, cur->nat_rule.ptr);
+		--cur->nat_rule.ptr->states_cur;
 	if (cur->anchor.ptr != NULL)
-		if (--cur->anchor.ptr->states_cur <= 0)
-			pf_rm_rule(NULL, cur->anchor.ptr);
+		--cur->anchor.ptr->states_cur;
 	pf_normalize_tcp_cleanup(cur);
 	pfi_kif_unref(cur->kif, PFI_KIF_REF_STATE);
 	if (cur->tag)
@@ -1480,13 +1483,14 @@ pf_free_state(struct pf_state *cur)
 /*
  * Called only from pf_purge_thread(), thus serialized.
  */
-static void
+static int
 pf_purge_expired_states(int maxcheck)
 {
 	static u_int i = 0;
 
 	struct pf_idhash *ih;
 	struct pf_state *s;
+	int rv = 0;
 
 	/*
 	 * Go through hash and unlink states that expire now.
@@ -1494,8 +1498,10 @@ pf_purge_expired_states(int maxcheck)
 	while (maxcheck > 0) {
 
 		/* Wrap to start of hash when we hit the end. */
-		if (i > V_pf_hashmask)
+		if (i > V_pf_hashmask) {
 			i = 0;
+			rv = 1;
+		}
 
 		ih = &V_pf_idhash[i];
 relock:
@@ -1505,11 +1511,40 @@ relock:
 				pf_unlink_state(s, PF_ENTER_LOCKED);
 				goto relock;
 			}
+			s->rule.ptr->rule_flag |= PFRULE_REFS;
+			if (s->nat_rule.ptr != NULL)
+				s->nat_rule.ptr->rule_flag |= PFRULE_REFS;
+			if (s->anchor.ptr != NULL)
+				s->anchor.ptr->rule_flag |= PFRULE_REFS;
+
 		}
 		PF_HASHROW_UNLOCK(ih);
 		i++;
 		maxcheck--;
 	}
+
+	return (rv);
+}
+
+static void
+pf_purge_unlinked_rules()
+{
+	struct pf_rule *r, *r1;
+
+	/*
+	 * Do naive mark-and-sweep garbage collecting of old rules.
+	 * Reference flag is raised by pf_purge_expired_states()
+	 * and pf_purge_expired_src_nodes().
+	 */
+	PF_UNLNKDRULES_LOCK();
+	TAILQ_FOREACH_SAFE(r, &V_pf_unlinked_rules, entries, r1) {
+		if (!(r->rule_flag & PFRULE_REFS)) {
+			TAILQ_REMOVE(&V_pf_unlinked_rules, r, entries);
+			pf_free_rule(r);
+		} else
+			r->rule_flag &= ~PFRULE_REFS;
+	}
+	PF_UNLNKDRULES_UNLOCK();
 }
 
 void

Modified: projects/pf/head/sys/contrib/pf/net/pf_ioctl.c
==============================================================================
--- projects/pf/head/sys/contrib/pf/net/pf_ioctl.c	Tue Apr 24 12:54:04 2012	(r234650)
+++ projects/pf/head/sys/contrib/pf/net/pf_ioctl.c	Tue Apr 24 13:13:42 2012	(r234651)
@@ -385,29 +385,24 @@ pf_empty_pool(struct pf_palist *poola)
 	}
 }
 
+static void
+pf_unlink_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
+{
+
+	PF_RULES_WASSERT();
+
+	TAILQ_REMOVE(rulequeue, rule, entries);
+
+	PF_UNLNKDRULES_LOCK();
+	rule->rule_flag |= PFRULE_REFS;
+	TAILQ_INSERT_TAIL(&V_pf_unlinked_rules, rule, entries);
+	PF_UNLNKDRULES_UNLOCK();
+}
+
 void
-pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule)
+pf_free_rule(struct pf_rule *rule)
 {
-	if (rulequeue != NULL) {
-		if (rule->states_cur <= 0) {
-			/*
-			 * XXX - we need to remove the table *before* detaching
-			 * the rule to make sure the table code does not delete
-			 * the anchor under our feet.
-			 */
-			pf_tbladdr_remove(&rule->src.addr);
-			pf_tbladdr_remove(&rule->dst.addr);
-			if (rule->overload_tbl)
-				pfr_detach_table(rule->overload_tbl);
-		}
-		TAILQ_REMOVE(rulequeue, rule, entries);
-		rule->entries.tqe_prev = NULL;
-		rule->nr = -1;
-	}
 
-	if (rule->states_cur > 0 || rule->src_nodes > 0 ||
-	    rule->entries.tqe_prev != NULL)
-		return;
 	pf_tag_unref(rule->tag);
 	pf_tag_unref(rule->match_tag);
 #ifdef ALTQ
@@ -419,12 +414,10 @@ pf_rm_rule(struct pf_rulequeue *rulequeu
 	pf_rtlabel_remove(&rule->dst.addr);
 	pfi_dynaddr_remove(&rule->src.addr);
 	pfi_dynaddr_remove(&rule->dst.addr);
-	if (rulequeue == NULL) {
-		pf_tbladdr_remove(&rule->src.addr);
-		pf_tbladdr_remove(&rule->dst.addr);
-		if (rule->overload_tbl)
-			pfr_detach_table(rule->overload_tbl);
-	}
+	pf_tbladdr_remove(&rule->src.addr);
+	pf_tbladdr_remove(&rule->dst.addr);
+	if (rule->overload_tbl)
+		pfr_detach_table(rule->overload_tbl);
 	pfi_kif_unref(rule->kif, PFI_KIF_REF_RULE);
 	pf_anchor_remove(rule);
 	pf_empty_pool(&rule->rpool.list);
@@ -781,13 +774,15 @@ pf_begin_rules(u_int32_t *ticket, int rs
 	struct pf_ruleset	*rs;
 	struct pf_rule		*rule;
 
+	PF_RULES_WASSERT();
+
 	if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
 		return (EINVAL);
 	rs = pf_find_or_create_ruleset(anchor);
 	if (rs == NULL)
 		return (EINVAL);
 	while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
-		pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
+		pf_unlink_rule(rs->rules[rs_num].inactive.ptr, rule);
 		rs->rules[rs_num].inactive.rcount--;
 	}
 	*ticket = ++rs->rules[rs_num].inactive.ticket;
@@ -801,6 +796,8 @@ pf_rollback_rules(u_int32_t ticket, int 
 	struct pf_ruleset	*rs;
 	struct pf_rule		*rule;
 
+	PF_RULES_WASSERT();
+
 	if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
 		return (EINVAL);
 	rs = pf_find_ruleset(anchor);
@@ -808,7 +805,7 @@ pf_rollback_rules(u_int32_t ticket, int 
 	    rs->rules[rs_num].inactive.ticket != ticket)
 		return (0);
 	while ((rule = TAILQ_FIRST(rs->rules[rs_num].inactive.ptr)) != NULL) {
-		pf_rm_rule(rs->rules[rs_num].inactive.ptr, rule);
+		pf_unlink_rule(rs->rules[rs_num].inactive.ptr, rule);
 		rs->rules[rs_num].inactive.rcount--;
 	}
 	rs->rules[rs_num].inactive.open = 0;
@@ -907,6 +904,8 @@ pf_commit_rules(u_int32_t ticket, int rs
 	int			 error;
 	u_int32_t		 old_rcount;
 
+	PF_RULES_WASSERT();
+
 	if (rs_num < 0 || rs_num >= PF_RULESET_MAX)
 		return (EINVAL);
 	rs = pf_find_ruleset(anchor);
@@ -943,7 +942,7 @@ pf_commit_rules(u_int32_t ticket, int rs
 
 	/* Purge the old rule list. */
 	while ((rule = TAILQ_FIRST(old_rules)) != NULL)
-		pf_rm_rule(old_rules, rule);
+		pf_unlink_rule(old_rules, rule);
 	if (rs->rules[rs_num].inactive.ptr_array)
 		free(rs->rules[rs_num].inactive.ptr_array, M_TEMP);
 	rs->rules[rs_num].inactive.ptr_array = NULL;
@@ -1183,27 +1182,27 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 		struct pf_pooladdr	*pa;
 		int			 rs_num;
 
-		PF_LOCK();
+		PF_RULES_WLOCK();
 		pr->anchor[sizeof(pr->anchor) - 1] = 0;
 		ruleset = pf_find_ruleset(pr->anchor);
 		if (ruleset == NULL) {
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			error = EINVAL;
 			break;
 		}
 		rs_num = pf_get_ruleset_number(pr->rule.action);
 		if (rs_num >= PF_RULESET_MAX) {
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			error = EINVAL;
 			break;
 		}
 		if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			error = EINVAL;
 			break;
 		}
 		if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			DPFPRINTF(PF_DEBUG_MISC,
 			    ("ticket: %d != [%d]%d\n", pr->ticket, rs_num,
 			    ruleset->rules[rs_num].inactive.ticket));
@@ -1211,7 +1210,7 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 			break;
 		}
 		if (pr->pool_ticket != V_ticket_pabuf) {
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			DPFPRINTF(PF_DEBUG_MISC,
 			    ("pool_ticket: %d != %d\n", pr->pool_ticket,
 			    V_ticket_pabuf));
@@ -1220,7 +1219,7 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 		}
 		rule = uma_zalloc(V_pf_rule_z, M_NOWAIT);
 		if (rule == NULL) {
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			error = ENOMEM;
 			break;
 		}
@@ -1236,7 +1235,7 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 		rule->entries.tqe_prev = NULL;
 #ifndef INET
 		if (rule->af == AF_INET) {
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			uma_zfree(V_pf_rule_z, rule);
 			error = EAFNOSUPPORT;
 			break;
@@ -1244,7 +1243,7 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 #endif /* INET */
 #ifndef INET6
 		if (rule->af == AF_INET6) {
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			uma_zfree(V_pf_rule_z, rule);
 			error = EAFNOSUPPORT;
 			break;
@@ -1259,7 +1258,7 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 		if (rule->ifname[0]) {
 			rule->kif = pfi_kif_get(rule->ifname);
 			if (rule->kif == NULL) {
-				PF_UNLOCK();
+				PF_RULES_WUNLOCK();
 				uma_zfree(V_pf_rule_z, rule);
 				error = EINVAL;
 				break;
@@ -1328,8 +1327,8 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 			error = EINVAL;
 
 		if (error) {
-			pf_rm_rule(NULL, rule);
-			PF_UNLOCK();
+			pf_free_rule(rule);
+			PF_RULES_WUNLOCK();
 			break;
 		}
 
@@ -1339,7 +1338,7 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 		TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
 		    rule, entries);
 		ruleset->rules[rs_num].inactive.rcount++;
-		PF_UNLOCK();
+		PF_RULES_WUNLOCK();
 		break;
 	}
 
@@ -1349,17 +1348,17 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 		struct pf_rule		*tail;
 		int			 rs_num;
 
-		PF_LOCK();
+		PF_RULES_WLOCK();
 		pr->anchor[sizeof(pr->anchor) - 1] = 0;
 		ruleset = pf_find_ruleset(pr->anchor);
 		if (ruleset == NULL) {
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			error = EINVAL;
 			break;
 		}
 		rs_num = pf_get_ruleset_number(pr->rule.action);
 		if (rs_num >= PF_RULESET_MAX) {
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			error = EINVAL;
 			break;
 		}
@@ -1370,7 +1369,7 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 		else
 			pr->nr = 0;
 		pr->ticket = ruleset->rules[rs_num].active.ticket;
-		PF_UNLOCK();
+		PF_RULES_WUNLOCK();
 		break;
 	}
 
@@ -1380,22 +1379,22 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 		struct pf_rule		*rule;
 		int			 rs_num, i;
 
-		PF_LOCK();
+		PF_RULES_WLOCK();
 		pr->anchor[sizeof(pr->anchor) - 1] = 0;
 		ruleset = pf_find_ruleset(pr->anchor);
 		if (ruleset == NULL) {
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			error = EINVAL;
 			break;
 		}
 		rs_num = pf_get_ruleset_number(pr->rule.action);
 		if (rs_num >= PF_RULESET_MAX) {
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			error = EINVAL;
 			break;
 		}
 		if (pr->ticket != ruleset->rules[rs_num].active.ticket) {
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			error = EBUSY;
 			break;
 		}
@@ -1403,13 +1402,13 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 		while ((rule != NULL) && (rule->nr != pr->nr))
 			rule = TAILQ_NEXT(rule, entries);
 		if (rule == NULL) {
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			error = EBUSY;
 			break;
 		}
 		bcopy(rule, &pr->rule, sizeof(struct pf_rule));
 		if (pf_anchor_copyout(ruleset, rule, pr)) {
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			error = EBUSY;
 			break;
 		}
@@ -1428,7 +1427,7 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 			rule->bytes[0] = rule->bytes[1] = 0;
 			rule->states_tot = 0;
 		}
-		PF_UNLOCK();
+		PF_RULES_WUNLOCK();
 		break;
 	}
 
@@ -1439,47 +1438,47 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 		u_int32_t		 nr = 0;
 		int			 rs_num;
 
-		PF_LOCK();
+		PF_RULES_WLOCK();
 		if (!(pcr->action == PF_CHANGE_REMOVE ||
 		    pcr->action == PF_CHANGE_GET_TICKET) &&
 		    pcr->pool_ticket != V_ticket_pabuf) {
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			error = EBUSY;
 			break;
 		}
 
 		if (pcr->action < PF_CHANGE_ADD_HEAD ||
 		    pcr->action > PF_CHANGE_GET_TICKET) {
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			error = EINVAL;
 			break;
 		}
 		ruleset = pf_find_ruleset(pcr->anchor);
 		if (ruleset == NULL) {
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			error = EINVAL;
 			break;
 		}
 		rs_num = pf_get_ruleset_number(pcr->rule.action);
 		if (rs_num >= PF_RULESET_MAX) {
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			error = EINVAL;
 			break;
 		}
 
 		if (pcr->action == PF_CHANGE_GET_TICKET) {
 			pcr->ticket = ++ruleset->rules[rs_num].active.ticket;
-			PF_UNLOCK();
+			PF_RULES_WUNLOCK();
 			break;
 		} else {
 			if (pcr->ticket !=
 			    ruleset->rules[rs_num].active.ticket) {
-				PF_UNLOCK();
+				PF_RULES_WUNLOCK();
 				error = EINVAL;
 				break;
 			}
 			if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
-				PF_UNLOCK();
+				PF_RULES_WUNLOCK();
 				error = EINVAL;
 				break;
 			}
@@ -1488,7 +1487,7 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 		if (pcr->action != PF_CHANGE_REMOVE) {
 			newrule = uma_zalloc(V_pf_rule_z, M_NOWAIT);
 			if (newrule == NULL) {
-				PF_UNLOCK();
+				PF_RULES_WUNLOCK();
 				error = ENOMEM;
 				break;
 			}
@@ -1501,7 +1500,7 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 			newrule->entries.tqe_prev = NULL;
 #ifndef INET
 			if (newrule->af == AF_INET) {
-				PF_UNLOCK();
+				PF_RULES_WUNLOCK();
 				uma_zfree(V_pf_rule_z, newrule);
 				error = EAFNOSUPPORT;
 				break;
@@ -1509,7 +1508,7 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 #endif /* INET */
 #ifndef INET6
 			if (newrule->af == AF_INET6) {
-				PF_UNLOCK();
+				PF_RULES_WUNLOCK();
 				uma_zfree(V_pf_rule_z, newrule);
 				error = EAFNOSUPPORT;
 				break;
@@ -1518,7 +1517,7 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 			if (newrule->ifname[0]) {
 				newrule->kif = pfi_kif_get(newrule->ifname);
 				if (newrule->kif == NULL) {
-					PF_UNLOCK();
+					PF_RULES_WUNLOCK();
 					uma_zfree(V_pf_rule_z, newrule);
 					error = EINVAL;
 					break;
@@ -1594,8 +1593,8 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 				error = EINVAL;
 
 			if (error) {
-				pf_rm_rule(NULL, newrule);
-				PF_UNLOCK();
+				pf_free_rule(newrule);
+				PF_RULES_WUNLOCK();
 				break;
 			}
 
@@ -1619,15 +1618,16 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 				oldrule = TAILQ_NEXT(oldrule, entries);
 			if (oldrule == NULL) {
 				if (newrule != NULL)
-					pf_rm_rule(NULL, newrule);
-				PF_UNLOCK();
+					pf_free_rule(newrule);
+				PF_RULES_WUNLOCK();
 				error = EINVAL;
 				break;
 			}
 		}
 
 		if (pcr->action == PF_CHANGE_REMOVE) {
-			pf_rm_rule(ruleset->rules[rs_num].active.ptr, oldrule);
+			pf_unlink_rule(ruleset->rules[rs_num].active.ptr,
+			    oldrule);
 			ruleset->rules[rs_num].active.rcount--;
 		} else {
 			if (oldrule == NULL)
@@ -1654,7 +1654,7 @@ pfioctl(struct cdev *dev, u_long cmd, ca
 		pf_calc_skip_steps(ruleset->rules[rs_num].active.ptr);
 		pf_remove_if_empty_ruleset(ruleset);
 
-		PF_UNLOCK();
+		PF_RULES_WUNLOCK();
 		break;
 	}
 
@@ -2920,7 +2920,7 @@ DIOCGETSTATES_full:
 			free(ioes, M_TEMP);
 			break;
 		}
-		PF_LOCK();
+		PF_RULES_WLOCK();
 		for (i = 0, ioe = ioes; i < io->size; i++, ioe++) {
 			switch (ioe->rs_num) {
 #ifdef ALTQ
@@ -2947,7 +2947,7 @@ DIOCGETSTATES_full:
 				    sizeof(table.pfrt_anchor));
 				if ((error = pfr_ina_begin(&table,
 				    &ioe->ticket, NULL, 0))) {
-					PF_UNLOCK();
+					PF_RULES_WUNLOCK();
 					free(ioes, M_TEMP);
 					goto fail;
 				}
@@ -2956,14 +2956,14 @@ DIOCGETSTATES_full:
 			default:
 				if ((error = pf_begin_rules(&ioe->ticket,
 				    ioe->rs_num, ioe->anchor))) {
-					PF_UNLOCK();
+					PF_RULES_WUNLOCK();
 					free(ioes, M_TEMP);
 					goto fail;
 				}
 				break;
 			}
 		}
-		PF_UNLOCK();
+		PF_RULES_WUNLOCK();
 		error = copyout(ioes, io->array, totlen);
 		free(ioes, M_TEMP);
 		break;
@@ -2986,19 +2986,19 @@ DIOCGETSTATES_full:
 			free(ioes, M_TEMP);
 			break;
 		}
-		PF_LOCK();
+		PF_RULES_WLOCK();
 		for (i = 0, ioe = ioes; i < io->size; i++, ioe++) {
 			switch (ioe->rs_num) {
 #ifdef ALTQ
 			case PF_RULESET_ALTQ:
 				if (ioe->anchor[0]) {
-					PF_UNLOCK();
+					PF_RULES_WUNLOCK();
 					free(ioes, M_TEMP);
 					error = EINVAL;
 					goto fail;
 				}
 				if ((error = pf_rollback_altq(ioe->ticket))) {
-					PF_UNLOCK();
+					PF_RULES_WUNLOCK();
 					free(ioes, M_TEMP);
 					goto fail; /* really bad */
 				}
@@ -3013,7 +3013,7 @@ DIOCGETSTATES_full:
 				    sizeof(table.pfrt_anchor));
 				if ((error = pfr_ina_rollback(&table,
 				    ioe->ticket, NULL, 0))) {
-					PF_UNLOCK();
+					PF_RULES_WUNLOCK();
 					free(ioes, M_TEMP);
 					goto fail; /* really bad */
 				}
@@ -3022,14 +3022,14 @@ DIOCGETSTATES_full:
 			default:
 				if ((error = pf_rollback_rules(ioe->ticket,
 				    ioe->rs_num, ioe->anchor))) {
-					PF_UNLOCK();
+					PF_RULES_WUNLOCK();
 					free(ioes, M_TEMP);
 					goto fail; /* really bad */
 				}
 				break;
 			}
 		}
-		PF_UNLOCK();
+		PF_RULES_WUNLOCK();
 		free(ioes, M_TEMP);
 		break;
 	}
@@ -3052,21 +3052,21 @@ DIOCGETSTATES_full:
 			free(ioes, M_TEMP);
 			break;
 		}
-		PF_LOCK();
+		PF_RULES_WLOCK();
 		/* First makes sure everything will succeed. */
 		for (i = 0, ioe = ioes; i < io->size; i++, ioe++) {
 			switch (ioe->rs_num) {
 #ifdef ALTQ
 			case PF_RULESET_ALTQ:
 				if (ioe->anchor[0]) {
-					PF_UNLOCK();
+					PF_RULES_WUNLOCK();
 					free(ioes, M_TEMP);
 					error = EINVAL;
 					goto fail;
 				}
 				if (!V_altqs_inactive_open || ioe->ticket !=
 				    V_ticket_altqs_inactive) {
-					PF_UNLOCK();
+					PF_RULES_WUNLOCK();
 					free(ioes, M_TEMP);
 					error = EBUSY;
 					goto fail;
@@ -3077,7 +3077,7 @@ DIOCGETSTATES_full:
 				rs = pf_find_ruleset(ioe->anchor);
 				if (rs == NULL || !rs->topen || ioe->ticket !=
 				    rs->tticket) {
-					PF_UNLOCK();
+					PF_RULES_WUNLOCK();
 					free(ioes, M_TEMP);
 					error = EBUSY;
 					goto fail;
@@ -3086,7 +3086,7 @@ DIOCGETSTATES_full:
 			default:
 				if (ioe->rs_num < 0 || ioe->rs_num >=
 				    PF_RULESET_MAX) {
-					PF_UNLOCK();
+					PF_RULES_WUNLOCK();
 					free(ioes, M_TEMP);
 					error = EINVAL;
 					goto fail;
@@ -3096,7 +3096,7 @@ DIOCGETSTATES_full:
 				    !rs->rules[ioe->rs_num].inactive.open ||
 				    rs->rules[ioe->rs_num].inactive.ticket !=
 				    ioe->ticket) {
-					PF_UNLOCK();
+					PF_RULES_WUNLOCK();
 					free(ioes, M_TEMP);
 					error = EBUSY;
 					goto fail;
@@ -3110,7 +3110,7 @@ DIOCGETSTATES_full:
 #ifdef ALTQ
 			case PF_RULESET_ALTQ:
 				if ((error = pf_commit_altq(ioe->ticket))) {
-					PF_UNLOCK();
+					PF_RULES_WUNLOCK();
 					free(ioes, M_TEMP);
 					goto fail; /* really bad */
 				}
@@ -3125,7 +3125,7 @@ DIOCGETSTATES_full:
 				    sizeof(table.pfrt_anchor));
 				if ((error = pfr_ina_commit(&table,
 				    ioe->ticket, NULL, NULL, 0))) {
-					PF_UNLOCK();
+					PF_RULES_WUNLOCK();
 					free(ioes, M_TEMP);
 					goto fail; /* really bad */
 				}
@@ -3134,14 +3134,14 @@ DIOCGETSTATES_full:
 			default:
 				if ((error = pf_commit_rules(ioe->ticket,
 				    ioe->rs_num, ioe->anchor))) {
-					PF_UNLOCK();
+					PF_RULES_WUNLOCK();
 					free(ioes, M_TEMP);
 					goto fail; /* really bad */
 				}
 				break;
 			}
 		}
-		PF_UNLOCK();
+		PF_RULES_WUNLOCK();
 		free(ioes, M_TEMP);
 		break;
 	}

Modified: projects/pf/head/sys/contrib/pf/net/pfvar.h
==============================================================================
--- projects/pf/head/sys/contrib/pf/net/pfvar.h	Tue Apr 24 12:54:04 2012	(r234650)
+++ projects/pf/head/sys/contrib/pf/net/pfvar.h	Tue Apr 24 13:13:42 2012	(r234651)
@@ -234,6 +234,10 @@ extern struct mtx pf_mtx;
 #define	PF_STATE_LOCK_ASSERT(s)		do {} while (0)
 #endif /* INVARIANTS */
 
+extern struct mtx pf_unlnkdrules_mtx;
+#define	PF_UNLNKDRULES_LOCK()	mtx_lock(&pf_unlnkdrules_mtx)
+#define	PF_UNLNKDRULES_UNLOCK()	mtx_unlock(&pf_unlnkdrules_mtx)
+
 extern struct rwlock pf_rules_lock;
 #define	PF_RULES_RLOCK()	rw_rlock(&pf_rules_lock)
 #define	PF_RULES_RUNLOCK()	rw_runlock(&pf_rules_lock)
@@ -685,6 +689,7 @@ struct pf_rule {
 #define	PFRULE_NOSYNC		0x0010
 #define PFRULE_SRCTRACK		0x0020  /* track source states */
 #define PFRULE_RULESRCTRACK	0x0040  /* per rule */
+#define	PFRULE_REFS		0x0080	/* rule has references */
 
 /* scrub flags */
 #define	PFRULE_NODF		0x0100
@@ -1753,6 +1758,9 @@ VNET_DECLARE(struct pf_poolqueue *,	 pf_
 VNET_DECLARE(struct pf_poolqueue *,	 pf_pools_inactive);
 #define	V_pf_pools_inactive		 VNET(pf_pools_inactive)
 
+VNET_DECLARE(struct pf_rulequeue, pf_unlinked_rules);  
+#define	V_pf_unlinked_rules	VNET(pf_unlinked_rules)
+
 void				 pf_initialize(void);
 void				 pf_cleanup(void);
 
@@ -1844,8 +1852,8 @@ VNET_DECLARE(struct pf_rule,		 pf_defaul
 #define	V_pf_default_rule		  VNET(pf_default_rule)
 extern void			 pf_addrcpy(struct pf_addr *, struct pf_addr *,
 				    u_int8_t);
-void				 pf_rm_rule(struct pf_rulequeue *,
-				    struct pf_rule *);
+void				pf_free_rule(struct pf_rule *);
+
 #ifdef INET
 int	pf_test(int, struct ifnet *, struct mbuf **, struct inpcb *);
 #endif /* INET */


More information about the svn-src-projects mailing list