Received: by 2002:ac0:a594:0:0:0:0:0 with SMTP id m20-v6csp2950166imm; Thu, 24 May 2018 19:43:56 -0700 (PDT) X-Google-Smtp-Source: AB8JxZrQUCNYJD37sGjR7qZ6fQKMG8pbHiF+8Nb8i5DgZ5EiyeMWD9icxv+/zIVztaF9yP/mGBWv X-Received: by 2002:a62:c987:: with SMTP id l7-v6mr561806pfk.221.1527216236425; Thu, 24 May 2018 19:43:56 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1527216236; cv=none; d=google.com; s=arc-20160816; b=yJiSTMs+6AV+eg7NFwbJ0rcNIvVeLTPT11jRznqJ96GLLJmKzsqLIba5PEOfaPtmL2 Lm1TFO6pzVdKgonXM2qB/g/mMFqWebHIodbCNQj5Ni/Jka9xNqJ841LDgitp9BEdgA+e bAKodWsS8PqeykuKb1zCVA3YYyUIJVkUBu3cRqY2LtW02oqcljnGIgQ2xg7y6NRIE6Un +E+G8ikaHxfsinuT+KqpTfu4H+T9dNrD3XZPa68voXrqX2sdUSMq+gRs1Iapm3ojSrfV XMSrZApUlySwXUWAr7ZxLplowFJfESrR0DBb2pnJWqW0WMCYXHp4WiKh6PzqwFTzDMjj b2GA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=PF26q/c9i3IfvmrJu2MUiJz5KHNtZsdiOwdWgIJ9wLk=; b=I64FcfXQTkW8kdjl0LhcduD9kToRNGFUkXW2BI1W2/g0qz3B+zUo2U0AecaVgr0/V0 ygPCFlqgZIHbuyZJneCdgMzfMG1w1b7c+ZUJaNg9aEivn3InucoTh0YCs4IkyqXkc9jJ gsDgwb0AUC2c9ciAVZGSFY5Rp1EuU+j7ANvbr2ipUcO8h4p3jN5CC/IWnHZJ0qE06SMA /iG7HaNmMME9OEcazWUReYgkrm++0nTFpkjt25CqLjNba+pxi9xdhQZDovpwg/WEdRmi jiQzakLiYwv1GuaV5hCDgbgse3NcGmAyCpcpwnQ8KVR30+113oL5PoFjosRcTj3tB7yC /TOQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id z4-v6si23127530pff.159.2018.05.24.19.43.42; Thu, 24 May 2018 19:43:56 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1161341AbeEXV21 (ORCPT + 99 others); Thu, 24 May 2018 17:28:27 -0400 Received: from smtp2.provo.novell.com ([137.65.250.81]:33372 "EHLO smtp2.provo.novell.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1161325AbeEXV2Y (ORCPT ); Thu, 24 May 2018 17:28:24 -0400 Received: from linux-n805.suse.de (prv-ext-foundry1int.gns.novell.com [137.65.251.240]) by smtp2.provo.novell.com with ESMTP (TLS encrypted); Thu, 24 May 2018 15:28:17 -0600 From: Davidlohr Bueso To: akpm@linux-foundation.org, torvalds@linux-foundation.org Cc: tgraf@suug.ch, herbert@gondor.apana.org.au, manfred@colorfullife.com, guillaume.knispel@supersonicimagine.com, linux-api@vger.kernel.org, linux-kernel@vger.kernel.org, Davidlohr Bueso , Davidlohr Bueso Subject: [PATCH 2/6] lib/rhashtable: guarantee initial hashtable allocation Date: Thu, 24 May 2018 14:11:31 -0700 Message-Id: <20180524211135.27760-3-dave@stgolabs.net> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180524211135.27760-1-dave@stgolabs.net> References: <20180524211135.27760-1-dave@stgolabs.net> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org rhashtable_init() may fail due to -ENOMEM, thus making the entire api unusable. This patch removes this scenario, however unlikely. In order to guarantee memory allocation, this patch refactors bucket_table_alloc() to add a 'retry' parameter which always ends up doing GFP_KERNEL|__GFP_NOFAIL for both the tbl as well as alloc_bucket_spinlocks(). So upon the first table allocation failure, we shrink the size to the smallest value that makes sense and retry the alloc with the same semantics. If we fail again, then we force the call with __GFP_NOFAIL. With the defaults, this means that from 64 buckets, we retry with only 4. Any later issues regarding performance due to collisions or larger table resizing (when more memory becomes available) is the last of our problems. Suggested-by: Linus Torvalds Signed-off-by: Davidlohr Bueso --- lib/rhashtable.c | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/lib/rhashtable.c b/lib/rhashtable.c index 05a4b1b8b8ce..28f28602e2f5 100644 --- a/lib/rhashtable.c +++ b/lib/rhashtable.c @@ -166,15 +166,20 @@ static struct bucket_table *nested_bucket_table_alloc(struct rhashtable *ht, return tbl; } -static struct bucket_table *bucket_table_alloc(struct rhashtable *ht, - size_t nbuckets, - gfp_t gfp) +static struct bucket_table *__bucket_table_alloc(struct rhashtable *ht, + size_t nbuckets, + gfp_t gfp, bool retry) { struct bucket_table *tbl = NULL; size_t size, max_locks; int i; size = sizeof(*tbl) + nbuckets * sizeof(tbl->buckets[0]); + if (retry) { + gfp |= __GFP_NOFAIL; + tbl = kzalloc(size, gfp); + } /* fall-through */ + if (gfp != GFP_KERNEL) tbl = kzalloc(size, gfp | __GFP_NOWARN | __GFP_NORETRY); else @@ -211,6 +216,20 @@ static struct bucket_table *bucket_table_alloc(struct rhashtable *ht, return tbl; } +static struct bucket_table *bucket_table_alloc(struct rhashtable *ht, + size_t nbuckets, + gfp_t gfp) +{ + return __bucket_table_alloc(ht, nbuckets, gfp, false); +} + +static struct bucket_table *bucket_table_alloc_retry(struct rhashtable *ht, + size_t nbuckets, + gfp_t gfp) +{ + return __bucket_table_alloc(ht, nbuckets, gfp, true); +} + static struct bucket_table *rhashtable_last_table(struct rhashtable *ht, struct bucket_table *tbl) { @@ -1067,9 +1086,20 @@ int rhashtable_init(struct rhashtable *ht, } } + /* + * This is api initialization and thus we need to guarantee the + * initial rhashtable allocation. Upon failure, retry with a + * smallest possible size, otherwise we exhaust our options with + * __GFP_NOFAIL. + */ tbl = bucket_table_alloc(ht, size, GFP_KERNEL); - if (tbl == NULL) - return -ENOMEM; + if (unlikely(tbl == NULL)) { + size = HASH_MIN_SIZE; + + tbl = bucket_table_alloc(ht, size, GFP_KERNEL); + if (tbl == NULL) + tbl = bucket_table_alloc_retry(ht, size, GFP_KERNEL); + } atomic_set(&ht->nelems, 0); -- 2.13.6