]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 4.19
authorSasha Levin <sashal@kernel.org>
Fri, 27 Aug 2021 17:35:50 +0000 (13:35 -0400)
committerSasha Levin <sashal@kernel.org>
Fri, 27 Aug 2021 17:35:50 +0000 (13:35 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-4.19/arc-fix-config_stackdepot.patch [new file with mode: 0644]
queue-4.19/netfilter-conntrack-collect-all-entries-in-one-cycle.patch [new file with mode: 0644]
queue-4.19/once-fix-panic-when-module-unload.patch [new file with mode: 0644]
queue-4.19/series

diff --git a/queue-4.19/arc-fix-config_stackdepot.patch b/queue-4.19/arc-fix-config_stackdepot.patch
new file mode 100644 (file)
index 0000000..77c2b45
--- /dev/null
@@ -0,0 +1,47 @@
+From d6db6beb3c5404668458d1d6d5fb49b471e83589 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 10 Jul 2021 07:50:33 -0700
+Subject: ARC: Fix CONFIG_STACKDEPOT
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+[ Upstream commit bf79167fd86f3b97390fe2e70231d383526bd9cc ]
+
+Enabling CONFIG_STACKDEPOT results in the following build error.
+
+arc-elf-ld: lib/stackdepot.o: in function `filter_irq_stacks':
+stackdepot.c:(.text+0x456): undefined reference to `__irqentry_text_start'
+arc-elf-ld: stackdepot.c:(.text+0x456): undefined reference to `__irqentry_text_start'
+arc-elf-ld: stackdepot.c:(.text+0x476): undefined reference to `__irqentry_text_end'
+arc-elf-ld: stackdepot.c:(.text+0x476): undefined reference to `__irqentry_text_end'
+arc-elf-ld: stackdepot.c:(.text+0x484): undefined reference to `__softirqentry_text_start'
+arc-elf-ld: stackdepot.c:(.text+0x484): undefined reference to `__softirqentry_text_start'
+arc-elf-ld: stackdepot.c:(.text+0x48c): undefined reference to `__softirqentry_text_end'
+arc-elf-ld: stackdepot.c:(.text+0x48c): undefined reference to `__softirqentry_text_end'
+
+Other architectures address this problem by adding IRQENTRY_TEXT and
+SOFTIRQENTRY_TEXT to the text segment, so do the same here.
+
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arc/kernel/vmlinux.lds.S | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/arc/kernel/vmlinux.lds.S b/arch/arc/kernel/vmlinux.lds.S
+index f35ed578e007..4d823d3f65bb 100644
+--- a/arch/arc/kernel/vmlinux.lds.S
++++ b/arch/arc/kernel/vmlinux.lds.S
+@@ -92,6 +92,8 @@ SECTIONS
+               CPUIDLE_TEXT
+               LOCK_TEXT
+               KPROBES_TEXT
++              IRQENTRY_TEXT
++              SOFTIRQENTRY_TEXT
+               *(.fixup)
+               *(.gnu.warning)
+       }
+-- 
+2.30.2
+
diff --git a/queue-4.19/netfilter-conntrack-collect-all-entries-in-one-cycle.patch b/queue-4.19/netfilter-conntrack-collect-all-entries-in-one-cycle.patch
new file mode 100644 (file)
index 0000000..6a030f9
--- /dev/null
@@ -0,0 +1,185 @@
+From e539d4de64fec93d7178171afbbe224070028824 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Jul 2021 00:29:19 +0200
+Subject: netfilter: conntrack: collect all entries in one cycle
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit 4608fdfc07e116f9fc0895beb40abad7cdb5ee3d ]
+
+Michal Kubecek reports that conntrack gc is responsible for frequent
+wakeups (every 125ms) on idle systems.
+
+On busy systems, timed out entries are evicted during lookup.
+The gc worker is only needed to remove entries after system becomes idle
+after a busy period.
+
+To resolve this, always scan the entire table.
+If the scan is taking too long, reschedule so other work_structs can run
+and resume from next bucket.
+
+After a completed scan, wait for 2 minutes before the next cycle.
+Heuristics for faster re-schedule are removed.
+
+GC_SCAN_INTERVAL could be exposed as a sysctl in the future to allow
+tuning this as-needed or even turn the gc worker off.
+
+Reported-by: Michal Kubecek <mkubecek@suse.cz>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_conntrack_core.c | 71 ++++++++++---------------------
+ 1 file changed, 22 insertions(+), 49 deletions(-)
+
+diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
+index c5590d36b775..a38caf317dbb 100644
+--- a/net/netfilter/nf_conntrack_core.c
++++ b/net/netfilter/nf_conntrack_core.c
+@@ -70,10 +70,9 @@ EXPORT_SYMBOL_GPL(nf_conntrack_hash);
+ struct conntrack_gc_work {
+       struct delayed_work     dwork;
+-      u32                     last_bucket;
++      u32                     next_bucket;
+       bool                    exiting;
+       bool                    early_drop;
+-      long                    next_gc_run;
+ };
+ static __read_mostly struct kmem_cache *nf_conntrack_cachep;
+@@ -81,12 +80,8 @@ static __read_mostly spinlock_t nf_conntrack_locks_all_lock;
+ static __read_mostly DEFINE_SPINLOCK(nf_conntrack_locks_all_lock);
+ static __read_mostly bool nf_conntrack_locks_all;
+-/* every gc cycle scans at most 1/GC_MAX_BUCKETS_DIV part of table */
+-#define GC_MAX_BUCKETS_DIV    128u
+-/* upper bound of full table scan */
+-#define GC_MAX_SCAN_JIFFIES   (16u * HZ)
+-/* desired ratio of entries found to be expired */
+-#define GC_EVICT_RATIO        50u
++#define GC_SCAN_INTERVAL      (120u * HZ)
++#define GC_SCAN_MAX_DURATION  msecs_to_jiffies(10)
+ static struct conntrack_gc_work conntrack_gc_work;
+@@ -1198,17 +1193,13 @@ static void nf_ct_offload_timeout(struct nf_conn *ct)
+ static void gc_worker(struct work_struct *work)
+ {
+-      unsigned int min_interval = max(HZ / GC_MAX_BUCKETS_DIV, 1u);
+-      unsigned int i, goal, buckets = 0, expired_count = 0;
+-      unsigned int nf_conntrack_max95 = 0;
++      unsigned long end_time = jiffies + GC_SCAN_MAX_DURATION;
++      unsigned int i, hashsz, nf_conntrack_max95 = 0;
++      unsigned long next_run = GC_SCAN_INTERVAL;
+       struct conntrack_gc_work *gc_work;
+-      unsigned int ratio, scanned = 0;
+-      unsigned long next_run;
+-
+       gc_work = container_of(work, struct conntrack_gc_work, dwork.work);
+-      goal = nf_conntrack_htable_size / GC_MAX_BUCKETS_DIV;
+-      i = gc_work->last_bucket;
++      i = gc_work->next_bucket;
+       if (gc_work->early_drop)
+               nf_conntrack_max95 = nf_conntrack_max / 100u * 95u;
+@@ -1216,22 +1207,21 @@ static void gc_worker(struct work_struct *work)
+               struct nf_conntrack_tuple_hash *h;
+               struct hlist_nulls_head *ct_hash;
+               struct hlist_nulls_node *n;
+-              unsigned int hashsz;
+               struct nf_conn *tmp;
+-              i++;
+               rcu_read_lock();
+               nf_conntrack_get_ht(&ct_hash, &hashsz);
+-              if (i >= hashsz)
+-                      i = 0;
++              if (i >= hashsz) {
++                      rcu_read_unlock();
++                      break;
++              }
+               hlist_nulls_for_each_entry_rcu(h, n, &ct_hash[i], hnnode) {
+                       struct net *net;
+                       tmp = nf_ct_tuplehash_to_ctrack(h);
+-                      scanned++;
+                       if (test_bit(IPS_OFFLOAD_BIT, &tmp->status)) {
+                               nf_ct_offload_timeout(tmp);
+                               continue;
+@@ -1239,7 +1229,6 @@ static void gc_worker(struct work_struct *work)
+                       if (nf_ct_is_expired(tmp)) {
+                               nf_ct_gc_expired(tmp);
+-                              expired_count++;
+                               continue;
+                       }
+@@ -1271,7 +1260,14 @@ static void gc_worker(struct work_struct *work)
+                */
+               rcu_read_unlock();
+               cond_resched();
+-      } while (++buckets < goal);
++              i++;
++
++              if (time_after(jiffies, end_time) && i < hashsz) {
++                      gc_work->next_bucket = i;
++                      next_run = 0;
++                      break;
++              }
++      } while (i < hashsz);
+       if (gc_work->exiting)
+               return;
+@@ -1282,40 +1278,17 @@ static void gc_worker(struct work_struct *work)
+        *
+        * This worker is only here to reap expired entries when system went
+        * idle after a busy period.
+-       *
+-       * The heuristics below are supposed to balance conflicting goals:
+-       *
+-       * 1. Minimize time until we notice a stale entry
+-       * 2. Maximize scan intervals to not waste cycles
+-       *
+-       * Normally, expire ratio will be close to 0.
+-       *
+-       * As soon as a sizeable fraction of the entries have expired
+-       * increase scan frequency.
+        */
+-      ratio = scanned ? expired_count * 100 / scanned : 0;
+-      if (ratio > GC_EVICT_RATIO) {
+-              gc_work->next_gc_run = min_interval;
+-      } else {
+-              unsigned int max = GC_MAX_SCAN_JIFFIES / GC_MAX_BUCKETS_DIV;
+-
+-              BUILD_BUG_ON((GC_MAX_SCAN_JIFFIES / GC_MAX_BUCKETS_DIV) == 0);
+-
+-              gc_work->next_gc_run += min_interval;
+-              if (gc_work->next_gc_run > max)
+-                      gc_work->next_gc_run = max;
++      if (next_run) {
++              gc_work->early_drop = false;
++              gc_work->next_bucket = 0;
+       }
+-
+-      next_run = gc_work->next_gc_run;
+-      gc_work->last_bucket = i;
+-      gc_work->early_drop = false;
+       queue_delayed_work(system_power_efficient_wq, &gc_work->dwork, next_run);
+ }
+ static void conntrack_gc_work_init(struct conntrack_gc_work *gc_work)
+ {
+       INIT_DEFERRABLE_WORK(&gc_work->dwork, gc_worker);
+-      gc_work->next_gc_run = HZ;
+       gc_work->exiting = false;
+ }
+-- 
+2.30.2
+
diff --git a/queue-4.19/once-fix-panic-when-module-unload.patch b/queue-4.19/once-fix-panic-when-module-unload.patch
new file mode 100644 (file)
index 0000000..719a34a
--- /dev/null
@@ -0,0 +1,123 @@
+From addad0be13e55e2fbe1996aeff4498cd186432ba Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 6 Aug 2021 16:21:24 +0800
+Subject: once: Fix panic when module unload
+
+From: Kefeng Wang <wangkefeng.wang@huawei.com>
+
+[ Upstream commit 1027b96ec9d34f9abab69bc1a4dc5b1ad8ab1349 ]
+
+DO_ONCE
+DEFINE_STATIC_KEY_TRUE(___once_key);
+__do_once_done
+  once_disable_jump(once_key);
+    INIT_WORK(&w->work, once_deferred);
+    struct once_work *w;
+    w->key = key;
+    schedule_work(&w->work);                     module unload
+                                                   //*the key is
+destroy*
+process_one_work
+  once_deferred
+    BUG_ON(!static_key_enabled(work->key));
+       static_key_count((struct static_key *)x)    //*access key, crash*
+
+When module uses DO_ONCE mechanism, it could crash due to the above
+concurrency problem, we could reproduce it with link[1].
+
+Fix it by add/put module refcount in the once work process.
+
+[1] https://lore.kernel.org/netdev/eaa6c371-465e-57eb-6be9-f4b16b9d7cbf@huawei.com/
+
+Cc: Hannes Frederic Sowa <hannes@stressinduktion.org>
+Cc: Daniel Borkmann <daniel@iogearbox.net>
+Cc: David S. Miller <davem@davemloft.net>
+Cc: Eric Dumazet <edumazet@google.com>
+Reported-by: Minmin chen <chenmingmin@huawei.com>
+Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
+Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/once.h |  4 ++--
+ lib/once.c           | 11 ++++++++---
+ 2 files changed, 10 insertions(+), 5 deletions(-)
+
+diff --git a/include/linux/once.h b/include/linux/once.h
+index 9225ee6d96c7..ae6f4eb41cbe 100644
+--- a/include/linux/once.h
++++ b/include/linux/once.h
+@@ -7,7 +7,7 @@
+ bool __do_once_start(bool *done, unsigned long *flags);
+ void __do_once_done(bool *done, struct static_key_true *once_key,
+-                  unsigned long *flags);
++                  unsigned long *flags, struct module *mod);
+ /* Call a function exactly once. The idea of DO_ONCE() is to perform
+  * a function call such as initialization of random seeds, etc, only
+@@ -46,7 +46,7 @@ void __do_once_done(bool *done, struct static_key_true *once_key,
+                       if (unlikely(___ret)) {                              \
+                               func(__VA_ARGS__);                           \
+                               __do_once_done(&___done, &___once_key,       \
+-                                             &___flags);                   \
++                                             &___flags, THIS_MODULE);      \
+                       }                                                    \
+               }                                                            \
+               ___ret;                                                      \
+diff --git a/lib/once.c b/lib/once.c
+index 8b7d6235217e..59149bf3bfb4 100644
+--- a/lib/once.c
++++ b/lib/once.c
+@@ -3,10 +3,12 @@
+ #include <linux/spinlock.h>
+ #include <linux/once.h>
+ #include <linux/random.h>
++#include <linux/module.h>
+ struct once_work {
+       struct work_struct work;
+       struct static_key_true *key;
++      struct module *module;
+ };
+ static void once_deferred(struct work_struct *w)
+@@ -16,10 +18,11 @@ static void once_deferred(struct work_struct *w)
+       work = container_of(w, struct once_work, work);
+       BUG_ON(!static_key_enabled(work->key));
+       static_branch_disable(work->key);
++      module_put(work->module);
+       kfree(work);
+ }
+-static void once_disable_jump(struct static_key_true *key)
++static void once_disable_jump(struct static_key_true *key, struct module *mod)
+ {
+       struct once_work *w;
+@@ -29,6 +32,8 @@ static void once_disable_jump(struct static_key_true *key)
+       INIT_WORK(&w->work, once_deferred);
+       w->key = key;
++      w->module = mod;
++      __module_get(mod);
+       schedule_work(&w->work);
+ }
+@@ -53,11 +58,11 @@ bool __do_once_start(bool *done, unsigned long *flags)
+ EXPORT_SYMBOL(__do_once_start);
+ void __do_once_done(bool *done, struct static_key_true *once_key,
+-                  unsigned long *flags)
++                  unsigned long *flags, struct module *mod)
+       __releases(once_lock)
+ {
+       *done = true;
+       spin_unlock_irqrestore(&once_lock, *flags);
+-      once_disable_jump(once_key);
++      once_disable_jump(once_key, mod);
+ }
+ EXPORT_SYMBOL(__do_once_done);
+-- 
+2.30.2
+
index 5d247b92986e9b7382d018f935b15b025894ea33..051f2e9cfaf305461d26ca087c25ecab3301482c 100644 (file)
@@ -2,3 +2,6 @@ net-qrtr-fix-another-oob-read-in-qrtr_endpoint_post.patch
 bpf-do-not-use-ax-register-in-interpreter-on-div-mod.patch
 bpf-fix-32-bit-src-register-truncation-on-div-mod.patch
 bpf-fix-truncation-handling-for-mod32-dst-reg-wrt-zero.patch
+arc-fix-config_stackdepot.patch
+netfilter-conntrack-collect-all-entries-in-one-cycle.patch
+once-fix-panic-when-module-unload.patch