Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 28 Apr 2021 10:07:25 GMT
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 5ebfa80f7543 - stable/12 - ipfw: do not use sleepable malloc in callout context.
Message-ID:  <202104281007.13SA7P0d006755@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/12 has been updated by ae:

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

commit 5ebfa80f7543d5cda828ee15ed20c9fc03f99208
Author:     Andrey V. Elsukov <ae@FreeBSD.org>
AuthorDate: 2021-04-16 07:22:44 +0000
Commit:     Andrey V. Elsukov <ae@FreeBSD.org>
CommitDate: 2021-04-28 10:06:33 +0000

    ipfw: do not use sleepable malloc in callout context.
    
    Use M_NOWAIT flag when hash growing is called from callout.
    
    PR:             255041
    Reviewed by:    kevans
    Differential Revision: https://reviews.freebsd.org/D29772
    
    (cherry picked from commit 9bacbf1ae243de43d642c3ac0b7318ae0e5c5235)
---
 sys/netpfil/ipfw/ip_fw_dynamic.c | 68 ++++++++++++++++++++++++++++++----------
 1 file changed, 51 insertions(+), 17 deletions(-)

diff --git a/sys/netpfil/ipfw/ip_fw_dynamic.c b/sys/netpfil/ipfw/ip_fw_dynamic.c
index 5e425c582f07..8321df175f9d 100644
--- a/sys/netpfil/ipfw/ip_fw_dynamic.c
+++ b/sys/netpfil/ipfw/ip_fw_dynamic.c
@@ -2585,7 +2585,7 @@ dyn_send_keepalive_ipv6(struct ip_fw_chain *chain)
 #endif /* INET6 */
 
 static void
-dyn_grow_hashtable(struct ip_fw_chain *chain, uint32_t new)
+dyn_grow_hashtable(struct ip_fw_chain *chain, uint32_t new, int flags)
 {
 #ifdef INET6
 	struct dyn_ipv6ck_slist *ipv6, *ipv6_parent;
@@ -2603,31 +2603,64 @@ dyn_grow_hashtable(struct ip_fw_chain *chain, uint32_t new)
 	DYN_DEBUG("grow hash size %u -> %u", V_curr_dyn_buckets, new);
 	/*
 	 * Allocate and initialize new lists.
-	 * XXXAE: on memory pressure this can disable callout timer.
 	 */
 	bucket_lock = malloc(new * sizeof(struct mtx), M_IPFW,
-	    M_WAITOK | M_ZERO);
+	    flags | M_ZERO);
+	if (bucket_lock == NULL)
+		return;
+
+	ipv4 = ipv4_parent = NULL;
+	ipv4_add = ipv4_del = ipv4_parent_add = ipv4_parent_del = NULL;
+#ifdef INET6
+	ipv6 = ipv6_parent = NULL;
+	ipv6_add = ipv6_del = ipv6_parent_add = ipv6_parent_del = NULL;
+#endif
+
 	ipv4 = malloc(new * sizeof(struct dyn_ipv4ck_slist), M_IPFW,
-	    M_WAITOK | M_ZERO);
+	    flags | M_ZERO);
+	if (ipv4 == NULL)
+		goto bad;
 	ipv4_parent = malloc(new * sizeof(struct dyn_ipv4ck_slist), M_IPFW,
-	    M_WAITOK | M_ZERO);
-	ipv4_add = malloc(new * sizeof(uint32_t), M_IPFW, M_WAITOK | M_ZERO);
-	ipv4_del = malloc(new * sizeof(uint32_t), M_IPFW, M_WAITOK | M_ZERO);
+	    flags | M_ZERO);
+	if (ipv4_parent == NULL)
+		goto bad;
+	ipv4_add = malloc(new * sizeof(uint32_t), M_IPFW, flags | M_ZERO);
+	if (ipv4_add == NULL)
+		goto bad;
+	ipv4_del = malloc(new * sizeof(uint32_t), M_IPFW, flags | M_ZERO);
+	if (ipv4_del == NULL)
+		goto bad;
 	ipv4_parent_add = malloc(new * sizeof(uint32_t), M_IPFW,
-	    M_WAITOK | M_ZERO);
+	    flags | M_ZERO);
+	if (ipv4_parent_add == NULL)
+		goto bad;
 	ipv4_parent_del = malloc(new * sizeof(uint32_t), M_IPFW,
-	    M_WAITOK | M_ZERO);
+	    flags | M_ZERO);
+	if (ipv4_parent_del == NULL)
+		goto bad;
 #ifdef INET6
 	ipv6 = malloc(new * sizeof(struct dyn_ipv6ck_slist), M_IPFW,
-	    M_WAITOK | M_ZERO);
+	    flags | M_ZERO);
+	if (ipv6 == NULL)
+		goto bad;
 	ipv6_parent = malloc(new * sizeof(struct dyn_ipv6ck_slist), M_IPFW,
-	    M_WAITOK | M_ZERO);
-	ipv6_add = malloc(new * sizeof(uint32_t), M_IPFW, M_WAITOK | M_ZERO);
-	ipv6_del = malloc(new * sizeof(uint32_t), M_IPFW, M_WAITOK | M_ZERO);
+	    flags | M_ZERO);
+	if (ipv6_parent == NULL)
+		goto bad;
+	ipv6_add = malloc(new * sizeof(uint32_t), M_IPFW, flags | M_ZERO);
+	if (ipv6_add == NULL)
+		goto bad;
+	ipv6_del = malloc(new * sizeof(uint32_t), M_IPFW, flags | M_ZERO);
+	if (ipv6_del == NULL)
+		goto bad;
 	ipv6_parent_add = malloc(new * sizeof(uint32_t), M_IPFW,
-	    M_WAITOK | M_ZERO);
+	    flags | M_ZERO);
+	if (ipv6_parent_add == NULL)
+		goto bad;
 	ipv6_parent_del = malloc(new * sizeof(uint32_t), M_IPFW,
-	    M_WAITOK | M_ZERO);
+	    flags | M_ZERO);
+	if (ipv6_parent_del == NULL)
+		goto bad;
 #endif
 	for (bucket = 0; bucket < new; bucket++) {
 		DYN_BUCKET_LOCK_INIT(bucket_lock, bucket);
@@ -2698,6 +2731,7 @@ dyn_grow_hashtable(struct ip_fw_chain *chain, uint32_t new)
 	/* Release old resources */
 	while (bucket-- != 0)
 		DYN_BUCKET_LOCK_DESTROY(bucket_lock, bucket);
+bad:
 	free(bucket_lock, M_IPFW);
 	free(ipv4, M_IPFW);
 	free(ipv4_parent, M_IPFW);
@@ -2762,7 +2796,7 @@ dyn_tick(void *vnetx)
 		buckets = 1 << fls(V_dyn_count);
 		if (buckets > V_dyn_buckets_max)
 			buckets = V_dyn_buckets_max;
-		dyn_grow_hashtable(&V_layer3_chain, buckets);
+		dyn_grow_hashtable(&V_layer3_chain, buckets, M_NOWAIT);
 	}
 
 	callout_reset_on(&V_dyn_timeout, hz, dyn_tick, vnetx, 0);
@@ -3187,7 +3221,7 @@ ipfw_dyn_init(struct ip_fw_chain *chain)
 	/* Initialize buckets. */
 	V_curr_dyn_buckets = 0;
 	V_dyn_bucket_lock = NULL;
-	dyn_grow_hashtable(chain, 256);
+	dyn_grow_hashtable(chain, 256, M_WAITOK);
 
 	if (IS_DEFAULT_VNET(curvnet))
 		dyn_hp_cache = malloc(mp_ncpus * sizeof(void *), M_IPFW,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202104281007.13SA7P0d006755>