On 04/07/17(Tue) 02:01, Alexander Bluhm wrote:
> 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.

> 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;

Reply via email to