Discussion:
panic in pf purge thread
Alexander Bluhm
2017-07-04 00:01:08 UTC
Permalink
Hi,

One of the regression tests triggers this panic in the pf purge
thread. I am not sure which test it is as the panic may be delayed.
It happens on a remote machine, the test machine connects to it in
a multi machine setup.

bluhm

login: panic: kernel diagnostic assertion "_kernel_lock_held()" failed: file "/usr/src/sys/kern/kern_malloc.c", line 373
Stopped at db_enter+0x7: leave
TID PID UID PRFLAGS PFLAGS CPU COMMAND
*284526 76934 0 0x14000 0x200 0 pfpurge
db_enter(d0b626ba,f5480d38,d0a1f6c4,f5480d38,d06dce8d) at db_enter+0x7
panic(d0a1f6c4,d09ca4f6,d09d052d,d09e933c,175) at panic+0x71
__assert(d09ca4f6,d09e933c,175,d09d052d,d8247280) at __assert+0x2e
free(d8247200,5,0,0,d0c51668) at free+0x251
pfr_destroy_ktable(db6a5420,1,f5480e5c,d03665a8,d0be0f80) at pfr_destroy_ktable+0x49
pfr_setflags_ktable(db6a5420,0,f5480e5c,d037c2b2,d75fda8c) at pfr_setflags_ktable+0xe3
pfr_setflags_ktable(db6a4f18,6,f5480eac,d036c8a9,d71c8980,0,8a796f54,f5480e9c,d04281c5) at pfr_setflags_ktable+0x141
pfr_detach_table(db6a4f18,0,d63f0234,d036c985,d71c8938) at pfr_detach_table+0x3c
pf_tbladdr_remove(db75c4f0,2,f5480efc,d036c8dd,db75c7b4) at pf_tbladdr_remove+0x25
pf_rm_rule(0,db75c4c0,f5480f5c,d0635d28,d0bd150c) at pf_rm_rule+0x224
pf_free_state(d75fdb64,ffffffff,40,0,1) at pf_free_state+0x176
pf_purge_expired_states(5,d0bd150c,20,d09f81dd,64) at pf_purge_expired_states+0x62
pf_purge_thread(d774c2cc) at pf_purge_thread+0x6e
Martin Pieuchot
2017-07-04 10:22:23 UTC
Permalink
Post by Alexander Bluhm
Hi,
One of the regression tests triggers this panic in the pf purge
thread. I am not sure which test it is as the panic may be delayed.
It happens on a remote machine, the test machine connects to it in
a multi machine setup.
Using a pool for 'radix_node_head' should fix the problem. pf_table
seems to be the only place where such nodes are freed. I converted
rn_inithead() to be able to audit all consumers of this API.

Diff below.
Post by Alexander Bluhm
login: panic: kernel diagnostic assertion "_kernel_lock_held()" failed: file "/usr/src/sys/kern/kern_malloc.c", line 373
Stopped at db_enter+0x7: leave
TID PID UID PRFLAGS PFLAGS CPU COMMAND
*284526 76934 0 0x14000 0x200 0 pfpurge
db_enter(d0b626ba,f5480d38,d0a1f6c4,f5480d38,d06dce8d) at db_enter+0x7
panic(d0a1f6c4,d09ca4f6,d09d052d,d09e933c,175) at panic+0x71
__assert(d09ca4f6,d09e933c,175,d09d052d,d8247280) at __assert+0x2e
free(d8247200,5,0,0,d0c51668) at free+0x251
pfr_destroy_ktable(db6a5420,1,f5480e5c,d03665a8,d0be0f80) at pfr_destroy_ktable+0x49
pfr_setflags_ktable(db6a5420,0,f5480e5c,d037c2b2,d75fda8c) at pfr_setflags_ktable+0xe3
pfr_setflags_ktable(db6a4f18,6,f5480eac,d036c8a9,d71c8980,0,8a796f54,f5480e9c,d04281c5) at pfr_setflags_ktable+0x141
pfr_detach_table(db6a4f18,0,d63f0234,d036c985,d71c8938) at pfr_detach_table+0x3c
pf_tbladdr_remove(db75c4f0,2,f5480efc,d036c8dd,db75c7b4) at pf_tbladdr_remove+0x25
pf_rm_rule(0,db75c4c0,f5480f5c,d0635d28,d0bd150c) at pf_rm_rule+0x224
pf_free_state(d75fdb64,ffffffff,40,0,1) at pf_free_state+0x176
pf_purge_expired_states(5,d0bd150c,20,d09f81dd,64) at pf_purge_expired_states+0x62
pf_purge_thread(d774c2cc) at pf_purge_thread+0x6e
Index: kern/vfs_subr.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_subr.c,v
retrieving revision 1.259
diff -u -p -r1.259 vfs_subr.c
--- kern/vfs_subr.c 20 Apr 2017 14:13:00 -0000 1.259
+++ kern/vfs_subr.c 4 Jul 2017 09:36:53 -0000
@@ -1405,7 +1405,7 @@ vfs_hang_addrlist(struct mount *mp, stru
switch (i) {
case AF_INET:
if ((rnh = nep->ne_rtable_inet) == NULL) {
- if (!rn_inithead((void **)&nep->ne_rtable_inet,
+ if (!rn_inithead(&nep->ne_rtable_inet,
offsetof(struct sockaddr_in, sin_addr))) {
error = ENOBUFS;
goto out;
Index: net/pf_table.c
===================================================================
RCS file: /cvs/src/sys/net/pf_table.c,v
retrieving revision 1.126
diff -u -p -r1.126 pf_table.c
--- net/pf_table.c 8 May 2017 20:24:03 -0000 1.126
+++ net/pf_table.c 4 Jul 2017 09:36:32 -0000
@@ -2010,9 +2010,9 @@ pfr_create_ktable(struct pfr_table *tbl,
rs->tables++;
}

- if (!rn_inithead((void **)&kt->pfrkt_ip4,
+ if (!rn_inithead(&kt->pfrkt_ip4,
offsetof(struct sockaddr_in, sin_addr)) ||
- !rn_inithead((void **)&kt->pfrkt_ip6,
+ !rn_inithead(&kt->pfrkt_ip6,
offsetof(struct sockaddr_in6, sin6_addr))) {
pfr_destroy_ktable(kt, 0);
return (NULL);
@@ -2046,10 +2046,8 @@ pfr_destroy_ktable(struct pfr_ktable *kt
pfr_clean_node_mask(kt, &addrq);
pfr_destroy_kentries(&addrq);
}
- if (kt->pfrkt_ip4 != NULL)
- free((caddr_t)kt->pfrkt_ip4, M_RTABLE, 0);
- if (kt->pfrkt_ip6 != NULL)
- free((caddr_t)kt->pfrkt_ip6, M_RTABLE, 0);
+ rn_freehead(kt->pfrkt_ip4);
+ rn_freehead(kt->pfrkt_ip6);
if (kt->pfrkt_shadow != NULL)
pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr);
if (kt->pfrkt_rs != NULL) {
Index: net/pipex.c
===================================================================
RCS file: /cvs/src/sys/net/pipex.c,v
retrieving revision 1.102
diff -u -p -r1.102 pipex.c
--- net/pipex.c 6 Jun 2017 13:07:22 -0000 1.102
+++ net/pipex.c 4 Jul 2017 09:39:08 -0000
@@ -151,12 +151,12 @@ pipex_iface_init(struct pipex_iface_cont
pipex_iface->ifnet_this = ifp;

if (pipex_rd_head4 == NULL) {
- if (!rn_inithead((void **)&pipex_rd_head4,
+ if (!rn_inithead(&pipex_rd_head4,
offsetof(struct sockaddr_in, sin_addr)))
panic("rn_inithead() failed on pipex_init()");
}
if (pipex_rd_head6 == NULL) {
- if (!rn_inithead((void **)&pipex_rd_head6,
+ if (!rn_inithead(&pipex_rd_head6,
offsetof(struct sockaddr_in6, sin6_addr)))
panic("rn_inithead() failed on pipex_init()");
}
Index: net/radix.h
===================================================================
RCS file: /cvs/src/sys/net/radix.h,v
retrieving revision 1.30
diff -u -p -r1.30 radix.h
--- net/radix.h 19 Jun 2017 09:42:45 -0000 1.30
+++ net/radix.h 4 Jul 2017 09:36:09 -0000
@@ -97,7 +97,8 @@ struct radix_node_head {
};

void rn_init(unsigned int);
-int rn_inithead(void **, int);
+int rn_inithead(struct radix_node_head **, int);
+void rn_freehead(struct radix_node_head *);

int rn_walktree(struct radix_node_head *,
int (*)(struct radix_node *, void *, u_int), void *);
Index: net/radix.c
===================================================================
RCS file: /cvs/src/sys/net/radix.c,v
retrieving revision 1.58
diff -u -p -r1.58 radix.c
--- net/radix.c 20 Jun 2017 09:03:39 -0000 1.58
+++ net/radix.c 4 Jul 2017 09:35:59 -0000
@@ -60,7 +60,8 @@ static unsigned int max_keylen; /* size


struct radix_node_head *mask_rnhead; /* head of shared mask tree */
-struct pool rtmask_pool; /* pool for radix_mask structures */
+struct pool rthead_pool; /* pool for radix_node_head structs */
+struct pool rtmask_pool; /* pool for radix_mask structs */

static inline int rn_satisfies_leaf(char *, struct radix_node *, int);
static inline int rn_lexobetter(void *, void *);
@@ -1097,7 +1098,7 @@ rn_initmask(void)

KASSERT(max_keylen > 0);

- mask_rnhead = malloc(sizeof(*mask_rnhead), M_RTABLE, M_NOWAIT);
+ mask_rnhead = pool_get(&rthead_pool, PR_NOWAIT);
if (mask_rnhead == NULL)
return (1);

@@ -1106,7 +1107,7 @@ rn_initmask(void)
}

int
-rn_inithead(void **head, int off)
+rn_inithead(struct radix_node_head **head, int off)
{
struct radix_node_head *rnh;

@@ -1116,7 +1117,7 @@ rn_inithead(void **head, int off)
if (rn_initmask())
panic("failed to initialize the mask tree");

- rnh = malloc(sizeof(*rnh), M_RTABLE, M_NOWAIT);
+ rnh = pool_get(&rthead_pool, PR_NOWAIT);
if (rnh == NULL)
return (0);
*head = rnh;
@@ -1124,6 +1125,14 @@ rn_inithead(void **head, int off)
return (1);
}

+void
+rn_freehead(struct radix_node_head *rnh)
+{
+ if (rnh == NULL)
+ return;
+ pool_put(&rthead_pool, rnh);
+}
+
int
rn_inithead0(struct radix_node_head *rnh, int offset)
{
@@ -1158,6 +1167,8 @@ rn_init(unsigned int keylen)
if (max_keylen == 0) {
pool_init(&rtmask_pool, sizeof(struct radix_mask), 0,
IPL_SOFTNET, 0, "rtmask", NULL);
+ pool_init(&rthead_pool, sizeof(struct radix_node_head), 0,
+ IPL_SOFTNET, 0, "rthead", NULL);
}

if (keylen <= max_keylen)
Index: netinet/ip_spd.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_spd.c,v
retrieving revision 1.92
diff -u -p -r1.92 ip_spd.c
--- netinet/ip_spd.c 6 Apr 2017 14:25:18 -0000 1.92
+++ netinet/ip_spd.c 4 Jul 2017 09:37:19 -0000
@@ -98,7 +98,7 @@ spd_table_add(unsigned int rtableid)
}

if (spd_tables[rdomain] == NULL) {
- if (rn_inithead((void **)&rnh,
+ if (rn_inithead(&rnh,
offsetof(struct sockaddr_encap, sen_type)) == 0)
rnh = NULL;
spd_tables[rdomain] = rnh;
Alexander Bluhm
2017-07-04 15:19:46 UTC
Permalink
Post by Martin Pieuchot
Using a pool for 'radix_node_head' should fix the problem. pf_table
seems to be the only place where such nodes are freed. I converted
rn_inithead() to be able to audit all consumers of this API.
Diff below.
New diff, new problem, this time in NFS server.
Panic happens during /usr/src/regress/sys/ffs/nfs setup.

login: panic: free: non-malloced addr 0xd4b81630 type rtable
Stopped at db_enter+0x7: leave
TID PID UID PRFLAGS PFLAGS CPU COMMAND
382123 44974 0 0x100002 0 1 sh
*424094 92583 0 0 0 0 mountd
db_enter(d09d2ab3,f5820bb8,d0baf53c,f5820bb8,d4aa5600) at db_enter+0x7
panic(d0baf53c,d4b81630,d0aaab21,d4aa5600,2) at panic+0x71
free(d4b81630,5,0,d09157dc,d4ad2a9c) at free+0xd5
vfs_free_addrlist(d5f88954,d4ad15f0,f5820c5c,d0779a59,d4ad2a9c) at vfs_free_add
rlist+0x45
vfs_export(d5e58c00,d5f88954,f5820cb0,d4ad15f0,d4a99454) at vfs_export+0x63
ffs_mount(d5e58c00,f5820e92,cf7cd2fc,f5820e2c,d4a99454) at ffs_mount+0x55d
sys_mount(d4a99454,f5820f54,f5820f7c,0,286) at sys_mount+0x2f0
syscall() at syscall+0x250
--- syscall (number -813903004) ---
0x6:

bluhm
Alexander Bluhm
2017-07-04 17:25:35 UTC
Permalink
Post by Alexander Bluhm
Panic happens during /usr/src/regress/sys/ffs/nfs setup.
login: panic: free: non-malloced addr 0xd4b81630 type rtable
Stopped at db_enter+0x7: leave
TID PID UID PRFLAGS PFLAGS CPU COMMAND
382123 44974 0 0x100002 0 1 sh
*424094 92583 0 0 0 0 mountd
db_enter(d09d2ab3,f5820bb8,d0baf53c,f5820bb8,d4aa5600) at db_enter+0x7
panic(d0baf53c,d4b81630,d0aaab21,d4aa5600,2) at panic+0x71
free(d4b81630,5,0,d09157dc,d4ad2a9c) at free+0xd5
vfs_free_addrlist(d5f88954,d4ad15f0,f5820c5c,d0779a59,d4ad2a9c) at vfs_free_add
rlist+0x45
vfs_export(d5e58c00,d5f88954,f5820cb0,d4ad15f0,d4a99454) at vfs_export+0x63
ffs_mount(d5e58c00,f5820e92,cf7cd2fc,f5820e2c,d4a99454) at ffs_mount+0x55d
sys_mount(d4a99454,f5820f54,f5820f7c,0,286) at sys_mount+0x2f0
syscall() at syscall+0x250
--- syscall (number -813903004) ---
Replacing free() with rn_freehead() in vfs_free_addrlist() fixes
this panic. NFS test passes, doing a full test run now.

bluhm

Index: kern/vfs_subr.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/kern/vfs_subr.c,v
retrieving revision 1.259
diff -u -p -r1.259 vfs_subr.c
--- kern/vfs_subr.c 20 Apr 2017 14:13:00 -0000 1.259
+++ kern/vfs_subr.c 4 Jul 2017 16:36:03 -0000
@@ -1405,7 +1405,7 @@ vfs_hang_addrlist(struct mount *mp, stru
switch (i) {
case AF_INET:
if ((rnh = nep->ne_rtable_inet) == NULL) {
- if (!rn_inithead((void **)&nep->ne_rtable_inet,
+ if (!rn_inithead(&nep->ne_rtable_inet,
offsetof(struct sockaddr_in, sin_addr))) {
error = ENOBUFS;
goto out;
@@ -1450,7 +1450,7 @@ vfs_free_addrlist(struct netexport *nep)

if ((rnh = nep->ne_rtable_inet) != NULL) {
rn_walktree(rnh, vfs_free_netcred, rnh);
- free(rnh, M_RTABLE, 0);
+ rn_freehead(rnh);
nep->ne_rtable_inet = NULL;
}
}
Index: net/pf_table.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/pf_table.c,v
retrieving revision 1.126
diff -u -p -r1.126 pf_table.c
--- net/pf_table.c 8 May 2017 20:24:03 -0000 1.126
+++ net/pf_table.c 4 Jul 2017 16:30:17 -0000
@@ -2010,9 +2010,9 @@ pfr_create_ktable(struct pfr_table *tbl,
rs->tables++;
}

- if (!rn_inithead((void **)&kt->pfrkt_ip4,
+ if (!rn_inithead(&kt->pfrkt_ip4,
offsetof(struct sockaddr_in, sin_addr)) ||
- !rn_inithead((void **)&kt->pfrkt_ip6,
+ !rn_inithead(&kt->pfrkt_ip6,
offsetof(struct sockaddr_in6, sin6_addr))) {
pfr_destroy_ktable(kt, 0);
return (NULL);
@@ -2046,10 +2046,8 @@ pfr_destroy_ktable(struct pfr_ktable *kt
pfr_clean_node_mask(kt, &addrq);
pfr_destroy_kentries(&addrq);
}
- if (kt->pfrkt_ip4 != NULL)
- free((caddr_t)kt->pfrkt_ip4, M_RTABLE, 0);
- if (kt->pfrkt_ip6 != NULL)
- free((caddr_t)kt->pfrkt_ip6, M_RTABLE, 0);
+ rn_freehead(kt->pfrkt_ip4);
+ rn_freehead(kt->pfrkt_ip6);
if (kt->pfrkt_shadow != NULL)
pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr);
if (kt->pfrkt_rs != NULL) {
Index: net/pipex.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/pipex.c,v
retrieving revision 1.102
diff -u -p -r1.102 pipex.c
--- net/pipex.c 6 Jun 2017 13:07:22 -0000 1.102
+++ net/pipex.c 4 Jul 2017 16:30:17 -0000
@@ -151,12 +151,12 @@ pipex_iface_init(struct pipex_iface_cont
pipex_iface->ifnet_this = ifp;

if (pipex_rd_head4 == NULL) {
- if (!rn_inithead((void **)&pipex_rd_head4,
+ if (!rn_inithead(&pipex_rd_head4,
offsetof(struct sockaddr_in, sin_addr)))
panic("rn_inithead() failed on pipex_init()");
}
if (pipex_rd_head6 == NULL) {
- if (!rn_inithead((void **)&pipex_rd_head6,
+ if (!rn_inithead(&pipex_rd_head6,
offsetof(struct sockaddr_in6, sin6_addr)))
panic("rn_inithead() failed on pipex_init()");
}
Index: net/radix.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/radix.c,v
retrieving revision 1.58
diff -u -p -r1.58 radix.c
--- net/radix.c 20 Jun 2017 09:03:39 -0000 1.58
+++ net/radix.c 4 Jul 2017 16:30:17 -0000
@@ -60,7 +60,8 @@ static unsigned int max_keylen; /* size


struct radix_node_head *mask_rnhead; /* head of shared mask tree */
-struct pool rtmask_pool; /* pool for radix_mask structures */
+struct pool rthead_pool; /* pool for radix_node_head structs */
+struct pool rtmask_pool; /* pool for radix_mask structs */

static inline int rn_satisfies_leaf(char *, struct radix_node *, int);
static inline int rn_lexobetter(void *, void *);
@@ -1097,7 +1098,7 @@ rn_initmask(void)

KASSERT(max_keylen > 0);

- mask_rnhead = malloc(sizeof(*mask_rnhead), M_RTABLE, M_NOWAIT);
+ mask_rnhead = pool_get(&rthead_pool, PR_NOWAIT);
if (mask_rnhead == NULL)
return (1);

@@ -1106,7 +1107,7 @@ rn_initmask(void)
}

int
-rn_inithead(void **head, int off)
+rn_inithead(struct radix_node_head **head, int off)
{
struct radix_node_head *rnh;

@@ -1116,7 +1117,7 @@ rn_inithead(void **head, int off)
if (rn_initmask())
panic("failed to initialize the mask tree");

- rnh = malloc(sizeof(*rnh), M_RTABLE, M_NOWAIT);
+ rnh = pool_get(&rthead_pool, PR_NOWAIT);
if (rnh == NULL)
return (0);
*head = rnh;
@@ -1124,6 +1125,14 @@ rn_inithead(void **head, int off)
return (1);
}

+void
+rn_freehead(struct radix_node_head *rnh)
+{
+ if (rnh == NULL)
+ return;
+ pool_put(&rthead_pool, rnh);
+}
+
int
rn_inithead0(struct radix_node_head *rnh, int offset)
{
@@ -1158,6 +1167,8 @@ rn_init(unsigned int keylen)
if (max_keylen == 0) {
pool_init(&rtmask_pool, sizeof(struct radix_mask), 0,
IPL_SOFTNET, 0, "rtmask", NULL);
+ pool_init(&rthead_pool, sizeof(struct radix_node_head), 0,
+ IPL_SOFTNET, 0, "rthead", NULL);
}

if (keylen <= max_keylen)
Index: net/radix.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/radix.h,v
retrieving revision 1.30
diff -u -p -r1.30 radix.h
--- net/radix.h 19 Jun 2017 09:42:45 -0000 1.30
+++ net/radix.h 4 Jul 2017 16:30:17 -0000
@@ -97,7 +97,8 @@ struct radix_node_head {
};

void rn_init(unsigned int);
-int rn_inithead(void **, int);
+int rn_inithead(struct radix_node_head **, int);
+void rn_freehead(struct radix_node_head *);

int rn_walktree(struct radix_node_head *,
int (*)(struct radix_node *, void *, u_int), void *);
Index: netinet/ip_spd.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_spd.c,v
retrieving revision 1.92
diff -u -p -r1.92 ip_spd.c
--- netinet/ip_spd.c 6 Apr 2017 14:25:18 -0000 1.92
+++ netinet/ip_spd.c 4 Jul 2017 16:30:17 -0000
@@ -98,7 +98,7 @@ spd_table_add(unsigned int rtableid)
}

if (spd_tables[rdomain] == NULL) {
- if (rn_inithead((void **)&rnh,
+ if (rn_inithead(&rnh,
offsetof(struct sockaddr_encap, sen_type)) == 0)
rnh = NULL;
spd_tables[rdomain] = rnh;
Alexander Bluhm
2017-07-04 18:10:21 UTC
Permalink
Hi,

Here is another one panic tag_unref(). Note that the change in
pf_purge_thread() has been backouted, but I test and report anyway
as we want to fix this stuff.

Basically we have to remove all malloc(9) from pf or make it MP
safe.

bluhm

login: panic: kernel diagnostic assertion "_kernel_lock_held()" failed: file "/usr/src/sys/kern/kern_malloc.c", line 373
Stopped at db_enter+0x7: leave
TID PID UID PRFLAGS PFLAGS CPU COMMAND
*159741 24648 0 0x14000 0x200 0 pfpurge
db_enter(d0b75a09,f5480e38,d0baed34,f5480e38,d0be3fe0) at db_enter+0x7
panic(d0baed34,d09c409a,d0a42528,d0a92068,175) at panic+0x71
__assert(d09c409a,d0a92068,175,d0a42528,b8f) at __assert+0x2e
free(d7ecdd00,5,50,f5480ecc,d07b3375) at free+0x251
tag_unref(d0bdc660,1,f5480010,0,0) at tag_unref+0x77
pf_tag_unref(1,1,f5480f5c,d06dcb38,d0be0908) at pf_tag_unref+0x1a
pf_free_state(d7329380,ffffffff,40,0,1) at pf_free_state+0x186
pf_purge_expired_states(2,d0be0908,20,d0a39846,64) at pf_purge_expired_states+0
x62
pf_purge_thread(d774e2cc) at pf_purge_thread+0x6e
Alexander Bluhm
2017-07-04 22:45:37 UTC
Permalink
Post by Alexander Bluhm
Basically we have to remove all malloc(9) from pf or make it MP
safe.
login: panic: kernel diagnostic assertion "_kernel_lock_held()" failed: file "/usr/src/sys/kern/kern_malloc.c", line 373
Stopped at db_enter+0x7: leave
TID PID UID PRFLAGS PFLAGS CPU COMMAND
*159741 24648 0 0x14000 0x200 0 pfpurge
db_enter(d0b75a09,f5480e38,d0baed34,f5480e38,d0be3fe0) at db_enter+0x7
panic(d0baed34,d09c409a,d0a42528,d0a92068,175) at panic+0x71
__assert(d09c409a,d0a92068,175,d0a42528,b8f) at __assert+0x2e
free(d7ecdd00,5,50,f5480ecc,d07b3375) at free+0x251
tag_unref(d0bdc660,1,f5480010,0,0) at tag_unref+0x77
pf_tag_unref(1,1,f5480f5c,d06dcb38,d0be0908) at pf_tag_unref+0x1a
pf_free_state(d7329380,ffffffff,40,0,1) at pf_free_state+0x186
pf_purge_expired_states(2,d0be0908,20,d0a39846,64) at pf_purge_expired_states+0
x62
pf_purge_thread(d774e2cc) at pf_purge_thread+0x6e
Convert pf tag malloc(9) and free(9) into a pool to make it MP safe.
While there use TAILQ_FOREACH macro for traversing tags.

ok?

bluhm

Index: net/pf_ioctl.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/pf_ioctl.c,v
retrieving revision 1.317
diff -u -p -r1.317 pf_ioctl.c
--- net/pf_ioctl.c 28 Jun 2017 19:30:24 -0000 1.317
+++ net/pf_ioctl.c 4 Jul 2017 22:22:15 -0000
@@ -84,6 +84,8 @@
#include <net/if_pfsync.h>
#endif /* NPFSYNC > 0 */

+struct pool pf_tag_pl;
+
void pfattach(int);
void pf_thread_create(void *);
int pfopen(dev_t, int, int, struct proc *);
@@ -165,6 +167,8 @@ pfattach(int num)
IPL_SOFTNET, 0, "pfruleitem", NULL);
pool_init(&pf_queue_pl, sizeof(struct pf_queuespec), 0,
IPL_SOFTNET, 0, "pfqueue", NULL);
+ pool_init(&pf_tag_pl, sizeof(struct pf_tagname), 0,
+ IPL_SOFTNET, 0, "pftag", NULL);
hfsc_initialize();
pfr_initialize();
pfi_initialize();
@@ -348,16 +352,17 @@ tagname2tag(struct pf_tags *head, char *
*/

/* new entry */
- if (!TAILQ_EMPTY(head))
- for (p = TAILQ_FIRST(head); p != NULL &&
- p->tag == new_tagid; p = TAILQ_NEXT(p, entries))
- new_tagid = p->tag + 1;
+ TAILQ_FOREACH(p, head, entries) {
+ if (p->tag != new_tagid)
+ break;
+ new_tagid = p->tag + 1;
+ }

if (new_tagid > TAGID_MAX)
return (0);

/* allocate and fill new struct pf_tagname */
- tag = malloc(sizeof(*tag), M_RTABLE, M_NOWAIT|M_ZERO);
+ tag = pool_get(&pf_tag_pl, PR_NOWAIT | PR_ZERO);
if (tag == NULL)
return (0);
strlcpy(tag->name, tagname, sizeof(tag->name));
@@ -392,12 +397,11 @@ tag_unref(struct pf_tags *head, u_int16_
if (tag == 0)
return;

- for (p = TAILQ_FIRST(head); p != NULL; p = next) {
- next = TAILQ_NEXT(p, entries);
+ TAILQ_FOREACH_SAFE(p, head, entries, next) {
if (tag == p->tag) {
if (--p->ref == 0) {
TAILQ_REMOVE(head, p, entries);
- free(p, M_RTABLE, sizeof(*p));
+ pool_put(&pf_tag_pl, p);
}
break;
}

Loading...