From 0e39751e82e35674eca062653e95bf40f7b2c614 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Wed, 11 Sep 2019 17:14:21 -0700 Subject: [PATCH] xfrm: handle percpu allocation failure gracefully Signed-off-by: Cong Wang --- net/xfrm/xfrm_ipcomp.c | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/net/xfrm/xfrm_ipcomp.c b/net/xfrm/xfrm_ipcomp.c index 32c364d3bfb3f3..5e9c938d9b9f4d 100644 --- a/net/xfrm/xfrm_ipcomp.c +++ b/net/xfrm/xfrm_ipcomp.c @@ -217,7 +217,7 @@ static void ipcomp_free_scratches(void) static void * __percpu *ipcomp_alloc_scratches(void) { void * __percpu *scratches; - int i; + int i, failed_cpu; if (ipcomp_scratch_users++) return ipcomp_scratches; @@ -232,12 +232,24 @@ static void * __percpu *ipcomp_alloc_scratches(void) void *scratch; scratch = vmalloc_node(IPCOMP_SCRATCH_SIZE, cpu_to_node(i)); - if (!scratch) - return NULL; + if (!scratch) { + failed_cpu = i; + goto fail; + } *per_cpu_ptr(scratches, i) = scratch; } return scratches; + +fail: + for_each_possible_cpu(i) { + if (i == failed_cpu) + break; + vfree(*per_cpu_ptr(scratches, i)); + } + ipcomp_scratches = NULL; + free_percpu(scratches); + return NULL; } static void ipcomp_free_tfms(struct crypto_comp * __percpu *tfms) @@ -272,7 +284,7 @@ static struct crypto_comp * __percpu *ipcomp_alloc_tfms(const char *alg_name) { struct ipcomp_tfms *pos; struct crypto_comp * __percpu *tfms; - int cpu; + int cpu, failed_cpu; list_for_each_entry(pos, &ipcomp_tfms_list, list) { @@ -297,20 +309,32 @@ static struct crypto_comp * __percpu *ipcomp_alloc_tfms(const char *alg_name) pos->tfms = tfms = alloc_percpu(struct crypto_comp *); if (!tfms) - goto error; + goto err_list_del; for_each_possible_cpu(cpu) { struct crypto_comp *tfm = crypto_alloc_comp(alg_name, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(tfm)) - goto error; + if (IS_ERR(tfm)) { + failed_cpu = cpu; + goto err_free; + } *per_cpu_ptr(tfms, cpu) = tfm; } return tfms; -error: - ipcomp_free_tfms(tfms); +err_free: + for_each_possible_cpu(cpu) { + struct crypto_comp *tfm = *per_cpu_ptr(tfms, cpu); + + if (cpu == failed_cpu) + break; + crypto_free_comp(tfm); + } + free_percpu(tfms); +err_list_del: + list_del(&pos->list); + kfree(pos); return NULL; }