From 0695cdbd10b0252be0e6e4a594c35f6be1b9cc63 Mon Sep 17 00:00:00 2001 From: Dragos Motrea Date: Thu, 2 Nov 2017 18:04:12 +0100 Subject: openvswitch: fixed kernel crash Signed-off-by: Dragos Motrea Signed-off-by: Adrian Dudau --- .../0001-openvswitch-fixed-kernel-crash.patch | 241 +++++++++++++++++++++ recipes-kernel/linux/linux-cavium_4.9.inc | 1 + 2 files changed, 242 insertions(+) create mode 100644 recipes-kernel/linux/linux-cavium/0001-openvswitch-fixed-kernel-crash.patch diff --git a/recipes-kernel/linux/linux-cavium/0001-openvswitch-fixed-kernel-crash.patch b/recipes-kernel/linux/linux-cavium/0001-openvswitch-fixed-kernel-crash.patch new file mode 100644 index 0000000..ba631ea --- /dev/null +++ b/recipes-kernel/linux/linux-cavium/0001-openvswitch-fixed-kernel-crash.patch @@ -0,0 +1,241 @@ +From 65693212754e9f97d29504219327ce4807780c48 Mon Sep 17 00:00:00 2001 +From: Dragos Motrea +Date: Tue, 24 Oct 2017 13:10:10 +0200 +Subject: [meta-enea-bsp-arm][cavium-4.9][LXCR-8050][PATCHv1 1/1] openvswitch: + fixed kernel crash + +Inserting the openvswitch.ko is causing a kernel crash in +__percpu_counter_sum function. Applying this patch will replace the percpu +counter API with the atomic operations for fragmentation mem accounting. +The atomic operations should be used on architecture with many CPUs. + +The revert is made in kernel upstream by the commit: +fb452a1aa3fd4034d7999e309c5466ff2d7005aa + +Upstream-Status: Backport + +Signed-off-by: Dragos Motrea +--- + include/net/inet_frag.h | 40 ++++++++------------------------- + net/ieee802154/6lowpan/reassembly.c | 12 +++------- + net/ipv4/inet_fragment.c | 4 +--- + net/ipv4/ip_fragment.c | 15 ++++--------- + net/ipv6/netfilter/nf_conntrack_reasm.c | 12 +++------- + net/ipv6/reassembly.c | 12 +++------- + 6 files changed, 23 insertions(+), 72 deletions(-) + +diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h +index 909972a..38beec0 100644 +--- a/include/net/inet_frag.h ++++ b/include/net/inet_frag.h +@@ -1,14 +1,9 @@ + #ifndef __NET_FRAG_H__ + #define __NET_FRAG_H__ + +-#include +- + struct netns_frags { +- /* The percpu_counter "mem" need to be cacheline aligned. +- * mem.count must not share cacheline with other writers +- */ +- struct percpu_counter mem ____cacheline_aligned_in_smp; +- ++ /* Keep atomic mem on separate cachelines in structs that include it */ ++ atomic_t mem ____cacheline_aligned_in_smp; + /* sysctls */ + int timeout; + int high_thresh; +@@ -108,13 +103,9 @@ struct inet_frags { + int inet_frags_init(struct inet_frags *); + void inet_frags_fini(struct inet_frags *); + +-static inline int inet_frags_init_net(struct netns_frags *nf) +-{ +- return percpu_counter_init(&nf->mem, 0, GFP_KERNEL); +-} +-static inline void inet_frags_uninit_net(struct netns_frags *nf) ++static inline void inet_frags_init_net(struct netns_frags *nf) + { +- percpu_counter_destroy(&nf->mem); ++ atomic_set(&nf->mem, 0); + } + + void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f); +@@ -140,37 +131,24 @@ static inline bool inet_frag_evicting(struct inet_frag_queue *q) + + /* Memory Tracking Functions. */ + +-/* The default percpu_counter batch size is not big enough to scale to +- * fragmentation mem acct sizes. +- * The mem size of a 64K fragment is approx: +- * (44 fragments * 2944 truesize) + frag_queue struct(200) = 129736 bytes +- */ +-static unsigned int frag_percpu_counter_batch = 130000; +- + static inline int frag_mem_limit(struct netns_frags *nf) + { +- return percpu_counter_read(&nf->mem); ++ return atomic_read(&nf->mem); + } + + static inline void sub_frag_mem_limit(struct netns_frags *nf, int i) + { +- __percpu_counter_add(&nf->mem, -i, frag_percpu_counter_batch); ++ atomic_sub(i, &nf->mem); + } + + static inline void add_frag_mem_limit(struct netns_frags *nf, int i) + { +- __percpu_counter_add(&nf->mem, i, frag_percpu_counter_batch); ++ atomic_add(i, &nf->mem); + } + +-static inline unsigned int sum_frag_mem_limit(struct netns_frags *nf) ++static inline int sum_frag_mem_limit(struct netns_frags *nf) + { +- unsigned int res; +- +- local_bh_disable(); +- res = percpu_counter_sum_positive(&nf->mem); +- local_bh_enable(); +- +- return res; ++ return atomic_read(&nf->mem); + } + + /* RFC 3168 support : +diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c +index 30d875d..fb28a06 100644 +--- a/net/ieee802154/6lowpan/reassembly.c ++++ b/net/ieee802154/6lowpan/reassembly.c +@@ -580,21 +580,15 @@ static int __net_init lowpan_frags_init_net(struct net *net) + { + struct netns_ieee802154_lowpan *ieee802154_lowpan = + net_ieee802154_lowpan(net); +- int res; + + ieee802154_lowpan->frags.high_thresh = IPV6_FRAG_HIGH_THRESH; + ieee802154_lowpan->frags.low_thresh = IPV6_FRAG_LOW_THRESH; + ieee802154_lowpan->frags.timeout = IPV6_FRAG_TIMEOUT; + +- res = inet_frags_init_net(&ieee802154_lowpan->frags); +- if (res) +- return res; +- res = lowpan_frags_ns_sysctl_register(net); +- if (res) +- inet_frags_uninit_net(&ieee802154_lowpan->frags); +- return res; +-} ++ inet_frags_init_net(&ieee802154_lowpan->frags); + ++ return lowpan_frags_ns_sysctl_register(net); ++} + static void __net_exit lowpan_frags_exit_net(struct net *net) + { + struct netns_ieee802154_lowpan *ieee802154_lowpan = +diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c +index b5e9317..631c0d0 100644 +--- a/net/ipv4/inet_fragment.c ++++ b/net/ipv4/inet_fragment.c +@@ -234,10 +234,8 @@ evict_again: + cond_resched(); + + if (read_seqretry(&f->rnd_seqlock, seq) || +- percpu_counter_sum(&nf->mem)) ++ sum_frag_mem_limit(nf)) + goto evict_again; +- +- percpu_counter_destroy(&nf->mem); + } + EXPORT_SYMBOL(inet_frags_exit_net); + +diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c +index bbe7f72..0f0d89e 100644 +--- a/net/ipv4/ip_fragment.c ++++ b/net/ipv4/ip_fragment.c +@@ -835,8 +835,6 @@ static void __init ip4_frags_ctl_register(void) + + static int __net_init ipv4_frags_init_net(struct net *net) + { +- int res; +- + /* Fragment cache limits. + * + * The fragment memory accounting code, (tries to) account for +@@ -861,16 +859,11 @@ static int __net_init ipv4_frags_init_net(struct net *net) + net->ipv4.frags.timeout = IP_FRAG_TIME; + + net->ipv4.frags.max_dist = 64; +- +- res = inet_frags_init_net(&net->ipv4.frags); +- if (res) +- return res; +- res = ip4_frags_ns_ctl_register(net); +- if (res) +- inet_frags_uninit_net(&net->ipv4.frags); +- return res; ++ ++ inet_frags_init_net(&net->ipv4.frags); ++ ++ return ip4_frags_ns_ctl_register(net); + } +- + static void __net_exit ipv4_frags_exit_net(struct net *net) + { + ip4_frags_ns_ctl_unregister(net); +diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c +index 9948b5c..8734e2c 100644 +--- a/net/ipv6/netfilter/nf_conntrack_reasm.c ++++ b/net/ipv6/netfilter/nf_conntrack_reasm.c +@@ -621,18 +621,12 @@ EXPORT_SYMBOL_GPL(nf_ct_frag6_gather); + + static int nf_ct_net_init(struct net *net) + { +- int res; +- + net->nf_frag.frags.high_thresh = IPV6_FRAG_HIGH_THRESH; + net->nf_frag.frags.low_thresh = IPV6_FRAG_LOW_THRESH; + net->nf_frag.frags.timeout = IPV6_FRAG_TIMEOUT; +- res = inet_frags_init_net(&net->nf_frag.frags); +- if (res) +- return res; +- res = nf_ct_frag6_sysctl_register(net); +- if (res) +- inet_frags_uninit_net(&net->nf_frag.frags); +- return res; ++ ++ inet_frags_init_net(&net->nf_frag.frags); ++ return nf_ct_frag6_sysctl_register(net); + } + + static void nf_ct_net_exit(struct net *net) +diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c +index 3815e85..fe67cf4 100644 +--- a/net/ipv6/reassembly.c ++++ b/net/ipv6/reassembly.c +@@ -709,19 +709,13 @@ static void ip6_frags_sysctl_unregister(void) + + static int __net_init ipv6_frags_init_net(struct net *net) + { +- int res; +- + net->ipv6.frags.high_thresh = IPV6_FRAG_HIGH_THRESH; + net->ipv6.frags.low_thresh = IPV6_FRAG_LOW_THRESH; + net->ipv6.frags.timeout = IPV6_FRAG_TIMEOUT; + +- res = inet_frags_init_net(&net->ipv6.frags); +- if (res) +- return res; +- res = ip6_frags_ns_sysctl_register(net); +- if (res) +- inet_frags_uninit_net(&net->ipv6.frags); +- return res; ++ inet_frags_init_net(&net->ipv6.frags); ++ ++ return ip6_frags_ns_sysctl_register(net); + } + + static void __net_exit ipv6_frags_exit_net(struct net *net) +-- +2.7.4 + diff --git a/recipes-kernel/linux/linux-cavium_4.9.inc b/recipes-kernel/linux/linux-cavium_4.9.inc index 0089d62..1c504fe 100644 --- a/recipes-kernel/linux/linux-cavium_4.9.inc +++ b/recipes-kernel/linux/linux-cavium_4.9.inc @@ -38,6 +38,7 @@ SRC_URI = "git://git@git.enea.com/linux/linux-cavium.git;protocol=ssh;name=machi file://CVE-2017-8069.patch \ file://CVE-2017-8831.patch \ file://CVE-2017-1000364.patch \ + file://0001-openvswitch-fixed-kernel-crash.patch \ " LINUX_KERNEL_TYPE = "tiny" -- cgit v1.2.3-54-g00ecf