summaryrefslogtreecommitdiffstats
path: root/sys/contrib/pf
diff options
context:
space:
mode:
authormlaier <mlaier@FreeBSD.org>2009-08-19 00:17:00 +0000
committermlaier <mlaier@FreeBSD.org>2009-08-19 00:17:00 +0000
commit450df1df9b2b0e9085240d0742eb98466e3cde1d (patch)
treef6a81e076afcd00d03b1a7e1b7ad25f66f3573da /sys/contrib/pf
parent3654a8b28d5874f51b1c50fee5561d9fb4992450 (diff)
downloadFreeBSD-src-450df1df9b2b0e9085240d0742eb98466e3cde1d.zip
FreeBSD-src-450df1df9b2b0e9085240d0742eb98466e3cde1d.tar.gz
MFC r196372:
If we cannot immediately get the pf_consistency_lock in the purge thread, restart the scan after acquiring the lock the hard way. Otherwise we might end up with a dead reference. Approved by: re (kib)
Diffstat (limited to 'sys/contrib/pf')
-rw-r--r--sys/contrib/pf/net/pf.c89
-rw-r--r--sys/contrib/pf/net/pfvar.h5
2 files changed, 70 insertions, 24 deletions
diff --git a/sys/contrib/pf/net/pf.c b/sys/contrib/pf/net/pf.c
index 591ea36..e8031ac 100644
--- a/sys/contrib/pf/net/pf.c
+++ b/sys/contrib/pf/net/pf.c
@@ -971,6 +971,9 @@ void
pf_purge_thread(void *v)
{
int nloops = 0, s;
+#ifdef __FreeBSD__
+ int locked;
+#endif
for (;;) {
tsleep(pf_purge_thread, PWAIT, "pftm", 1 * hz);
@@ -978,14 +981,19 @@ pf_purge_thread(void *v)
#ifdef __FreeBSD__
sx_slock(&pf_consistency_lock);
PF_LOCK();
+ locked = 0;
if (pf_end_threads) {
- pf_purge_expired_states(pf_status.states);
+ PF_UNLOCK();
+ sx_sunlock(&pf_consistency_lock);
+ sx_xlock(&pf_consistency_lock);
+ PF_LOCK();
+ pf_purge_expired_states(pf_status.states, 1);
pf_purge_expired_fragments();
- pf_purge_expired_src_nodes(0);
+ pf_purge_expired_src_nodes(1);
pf_end_threads++;
- sx_sunlock(&pf_consistency_lock);
+ sx_xunlock(&pf_consistency_lock);
PF_UNLOCK();
wakeup(pf_purge_thread);
kproc_exit(0);
@@ -994,20 +1002,44 @@ pf_purge_thread(void *v)
s = splsoftnet();
/* process a fraction of the state table every second */
+#ifdef __FreeBSD__
+ if(!pf_purge_expired_states(1 + (pf_status.states
+ / pf_default_rule.timeout[PFTM_INTERVAL]), 0)) {
+ PF_UNLOCK();
+ sx_sunlock(&pf_consistency_lock);
+ sx_xlock(&pf_consistency_lock);
+ PF_LOCK();
+ locked = 1;
+
+ pf_purge_expired_states(1 + (pf_status.states
+ / pf_default_rule.timeout[PFTM_INTERVAL]), 1);
+ }
+#else
pf_purge_expired_states(1 + (pf_status.states
/ pf_default_rule.timeout[PFTM_INTERVAL]));
+#endif
/* purge other expired types every PFTM_INTERVAL seconds */
if (++nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) {
pf_purge_expired_fragments();
- pf_purge_expired_src_nodes(0);
+ if (!pf_purge_expired_src_nodes(locked)) {
+ PF_UNLOCK();
+ sx_sunlock(&pf_consistency_lock);
+ sx_xlock(&pf_consistency_lock);
+ PF_LOCK();
+ locked = 1;
+ pf_purge_expired_src_nodes(1);
+ }
nloops = 0;
}
splx(s);
#ifdef __FreeBSD__
PF_UNLOCK();
- sx_sunlock(&pf_consistency_lock);
+ if (locked)
+ sx_xunlock(&pf_consistency_lock);
+ else
+ sx_sunlock(&pf_consistency_lock);
#endif
}
}
@@ -1056,8 +1088,13 @@ pf_state_expires(const struct pf_state *state)
return (state->expire + timeout);
}
+#ifdef __FreeBSD__
+int
+pf_purge_expired_src_nodes(int waslocked)
+#else
void
pf_purge_expired_src_nodes(int waslocked)
+#endif
{
struct pf_src_node *cur, *next;
int locked = waslocked;
@@ -1068,12 +1105,8 @@ pf_purge_expired_src_nodes(int waslocked)
if (cur->states <= 0 && cur->expire <= time_second) {
if (! locked) {
#ifdef __FreeBSD__
- if (!sx_try_upgrade(&pf_consistency_lock)) {
- PF_UNLOCK();
- sx_sunlock(&pf_consistency_lock);
- sx_xlock(&pf_consistency_lock);
- PF_LOCK();
- }
+ if (!sx_try_upgrade(&pf_consistency_lock))
+ return (0);
#else
rw_enter_write(&pf_consistency_lock);
#endif
@@ -1100,6 +1133,10 @@ pf_purge_expired_src_nodes(int waslocked)
#else
rw_exit_write(&pf_consistency_lock);
#endif
+
+#ifdef __FreeBSD__
+ return (1);
+#endif
}
void
@@ -1202,12 +1239,21 @@ pf_free_state(struct pf_state *cur)
pf_status.states--;
}
+#ifdef __FreeBSD__
+int
+pf_purge_expired_states(u_int32_t maxcheck, int waslocked)
+#else
void
pf_purge_expired_states(u_int32_t maxcheck)
+#endif
{
static struct pf_state *cur = NULL;
struct pf_state *next;
+#ifdef __FreeBSD__
+ int locked = waslocked;
+#else
int locked = 0;
+#endif
while (maxcheck--) {
/* wrap to start of list when we hit the end */
@@ -1224,12 +1270,8 @@ pf_purge_expired_states(u_int32_t maxcheck)
/* free unlinked state */
if (! locked) {
#ifdef __FreeBSD__
- if (!sx_try_upgrade(&pf_consistency_lock)) {
- PF_UNLOCK();
- sx_sunlock(&pf_consistency_lock);
- sx_xlock(&pf_consistency_lock);
- PF_LOCK();
- }
+ if (!sx_try_upgrade(&pf_consistency_lock))
+ return (0);
#else
rw_enter_write(&pf_consistency_lock);
#endif
@@ -1241,12 +1283,8 @@ pf_purge_expired_states(u_int32_t maxcheck)
pf_unlink_state(cur);
if (! locked) {
#ifdef __FreeBSD__
- if (!sx_try_upgrade(&pf_consistency_lock)) {
- PF_UNLOCK();
- sx_sunlock(&pf_consistency_lock);
- sx_xlock(&pf_consistency_lock);
- PF_LOCK();
- }
+ if (!sx_try_upgrade(&pf_consistency_lock))
+ return (0);
#else
rw_enter_write(&pf_consistency_lock);
#endif
@@ -1257,10 +1295,13 @@ pf_purge_expired_states(u_int32_t maxcheck)
cur = next;
}
- if (locked)
#ifdef __FreeBSD__
+ if (!waslocked && locked)
sx_downgrade(&pf_consistency_lock);
+
+ return (1);
#else
+ if (locked)
rw_exit_write(&pf_consistency_lock);
#endif
}
diff --git a/sys/contrib/pf/net/pfvar.h b/sys/contrib/pf/net/pfvar.h
index 2c176db..32e721c 100644
--- a/sys/contrib/pf/net/pfvar.h
+++ b/sys/contrib/pf/net/pfvar.h
@@ -1593,8 +1593,13 @@ extern struct pool pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
extern struct pool pf_state_scrub_pl;
#endif
extern void pf_purge_thread(void *);
+#ifdef __FreeBSD__
+extern int pf_purge_expired_src_nodes(int);
+extern int pf_purge_expired_states(u_int32_t, int);
+#else
extern void pf_purge_expired_src_nodes(int);
extern void pf_purge_expired_states(u_int32_t);
+#endif
extern void pf_unlink_state(struct pf_state *);
extern void pf_free_state(struct pf_state *);
extern int pf_insert_state(struct pfi_kif *,
OpenPOWER on IntegriCloud