From 5de9d1563aba549f16b7a6bca9d235cb3b22632b Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Fri, 27 Aug 2021 13:35:50 -0400 Subject: [PATCH] Fixes for 4.19 Signed-off-by: Sasha Levin --- queue-4.19/arc-fix-config_stackdepot.patch | 47 +++++ ...ack-collect-all-entries-in-one-cycle.patch | 185 ++++++++++++++++++ .../once-fix-panic-when-module-unload.patch | 123 ++++++++++++ queue-4.19/series | 3 + 4 files changed, 358 insertions(+) create mode 100644 queue-4.19/arc-fix-config_stackdepot.patch create mode 100644 queue-4.19/netfilter-conntrack-collect-all-entries-in-one-cycle.patch create mode 100644 queue-4.19/once-fix-panic-when-module-unload.patch diff --git a/queue-4.19/arc-fix-config_stackdepot.patch b/queue-4.19/arc-fix-config_stackdepot.patch new file mode 100644 index 00000000000..77c2b45956c --- /dev/null +++ b/queue-4.19/arc-fix-config_stackdepot.patch @@ -0,0 +1,47 @@ +From d6db6beb3c5404668458d1d6d5fb49b471e83589 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 10 Jul 2021 07:50:33 -0700 +Subject: ARC: Fix CONFIG_STACKDEPOT + +From: Guenter Roeck + +[ 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 +Signed-off-by: Vineet Gupta +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..6a030f9d0ee --- /dev/null +++ b/queue-4.19/netfilter-conntrack-collect-all-entries-in-one-cycle.patch @@ -0,0 +1,185 @@ +From e539d4de64fec93d7178171afbbe224070028824 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Jul 2021 00:29:19 +0200 +Subject: netfilter: conntrack: collect all entries in one cycle + +From: Florian Westphal + +[ 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 +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..719a34ae180 --- /dev/null +++ b/queue-4.19/once-fix-panic-when-module-unload.patch @@ -0,0 +1,123 @@ +From addad0be13e55e2fbe1996aeff4498cd186432ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Aug 2021 16:21:24 +0800 +Subject: once: Fix panic when module unload + +From: Kefeng Wang + +[ 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 +Cc: Daniel Borkmann +Cc: David S. Miller +Cc: Eric Dumazet +Reported-by: Minmin chen +Signed-off-by: Kefeng Wang +Acked-by: Hannes Frederic Sowa +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + + 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 + diff --git a/queue-4.19/series b/queue-4.19/series index 5d247b92986..051f2e9cfaf 100644 --- a/queue-4.19/series +++ b/queue-4.19/series @@ -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 -- 2.47.3