From c08c48813d7943cd937bf4f10e126c329116d5a8 Mon Sep 17 00:00:00 2001 From: "Anand H. Krishnan" Date: Wed, 31 Aug 2016 11:59:18 +0530 Subject: [PATCH] When in a softirq context, memory allocation should be atomic Eviction of flows based on TCP state machine happens in the softirq context. The process of evicting a flow depends on the kernel work queues, for which allocation of memory needs to happen. Under such cases, the allocation should not wait. Hence, pass GFP_ATOMIC as the allocation flag when in softirq context to indicate that the path is not willing to block. Change-Id: I2c56203c2666a981ff3218268611d95e18281151 Closes-Bug: #1618375 --- dp-core/vr_flow.c | 3 +-- dpdk/vr_dpdk_host.c | 4 +++- freebsd/vrouter_mod.c | 5 +++-- host/vrouter_host_mod.c | 4 ++-- include/vrouter.h | 2 +- linux/vrouter_mod.c | 16 ++++++++++++---- 6 files changed, 22 insertions(+), 12 deletions(-) diff --git a/dp-core/vr_flow.c b/dp-core/vr_flow.c index a14a9485d..f2f31dc64 100644 --- a/dp-core/vr_flow.c +++ b/dp-core/vr_flow.c @@ -1714,8 +1714,7 @@ __vr_flow_schedule_transition(struct vrouter *router, struct vr_flow_entry *fe, } flmd->flmd_defer_data = defer; - vr_schedule_work(vr_get_cpu(), vr_flow_work, (void *)flmd); - return 0; + return vr_schedule_work(vr_get_cpu(), vr_flow_work, (void *)flmd); } static int diff --git a/dpdk/vr_dpdk_host.c b/dpdk/vr_dpdk_host.c index 54edc97b4..b42ef0d21 100644 --- a/dpdk/vr_dpdk_host.c +++ b/dpdk/vr_dpdk_host.c @@ -502,11 +502,13 @@ dpdk_get_mono_time(unsigned int *sec, unsigned int *nsec) } /* Work callback called on NetLink lcore */ -static void +static int dpdk_schedule_work(unsigned int cpu, void (*fn)(void *), void *arg) { /* no RCU reader lock needed, just do the work */ fn(arg); + + return 0; } static void diff --git a/freebsd/vrouter_mod.c b/freebsd/vrouter_mod.c index 7381c4ec3..0d0ad2b31 100644 --- a/freebsd/vrouter_mod.c +++ b/freebsd/vrouter_mod.c @@ -331,11 +331,12 @@ fh_get_cpu(void) return (cpuid); } -static void +static int fh_schedule_work(unsigned int cpu, void (*fn)(void *), void *arg) { - vr_log(VR_ERR, "%s: not implemented\n", __func__); + + return -EOPNOTSUPP; } static void diff --git a/host/vrouter_host_mod.c b/host/vrouter_host_mod.c index 6c4227505..e91780a9d 100644 --- a/host/vrouter_host_mod.c +++ b/host/vrouter_host_mod.c @@ -225,10 +225,10 @@ vr_lib_get_cpu(void) return 0; } -static void +static int vr_lib_schedule_work(unsigned int cpu, void (*fn)(void *), void *arg) { - return; + return -EOPNOTSUPP; } static void diff --git a/include/vrouter.h b/include/vrouter.h index 70bb75e5a..2ce15892f 100644 --- a/include/vrouter.h +++ b/include/vrouter.h @@ -159,7 +159,7 @@ struct host_os { unsigned int (*hos_pgso_size)(struct vr_packet *); unsigned int (*hos_get_cpu)(void); - void (*hos_schedule_work)(unsigned int, void (*)(void *), void *); + int (*hos_schedule_work)(unsigned int, void (*)(void *), void *); void (*hos_delay_op)(void); void (*hos_defer)(struct vrouter *, vr_defer_cb, void *); void *(*hos_get_defer_data)(unsigned int); diff --git a/linux/vrouter_mod.c b/linux/vrouter_mod.c index c18db6f1a..b6e956a09 100644 --- a/linux/vrouter_mod.c +++ b/linux/vrouter_mod.c @@ -416,20 +416,28 @@ lh_work(struct work_struct *work) return; } -static void +static int lh_schedule_work(unsigned int cpu, void (*fn)(void *), void *arg) { - struct work_arg *wa = kzalloc(sizeof(*wa), GFP_KERNEL); + unsigned int alloc_flag; + struct work_arg *wa; + + if (in_softirq()) { + alloc_flag = GFP_ATOMIC; + } else { + alloc_flag = GFP_KERNEL; + } + wa = kzalloc(sizeof(*wa), alloc_flag); if (!wa) - return; + return -ENOMEM; wa->fn = fn; wa->wa_arg = arg; INIT_WORK(&wa->wa_work, lh_work); schedule_work_on(cpu, &wa->wa_work); - return; + return 0; } static void