Received: by 2002:a25:6193:0:0:0:0:0 with SMTP id v141csp3279260ybb; Tue, 31 Mar 2020 01:58:31 -0700 (PDT) X-Google-Smtp-Source: ADFU+vvRYmCsTTxITnt1ATN+xLZT+piKYEh32Y+8hoG83fcA48ss0127lwaXFYzYxfikU/n9zKYG X-Received: by 2002:aca:c350:: with SMTP id t77mr1277187oif.118.1585645111557; Tue, 31 Mar 2020 01:58:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1585645111; cv=none; d=google.com; s=arc-20160816; b=EZSF4qOdXDqvW/W6Liqu+s62jMR21JadId9oH2l3V6xLLbnuRCGKepC4DkUiUVdjq6 NNJcUXiFMUrwR0/QSEKlrAOnndT5osDgj7EwewWfxGnFIUGwkjRnCO6gPtrAZgVvPTUq pRbJzF09QOsH7au+VxspSDsA0718wSY5bzD5rxgNOFyJXiDmT7yURuQjTjwEg7mOvmeh vhZlo6C188j0AYNVCRK/lSf6hCvoPfibWpW5Q085FahHCh4uklci4mz0Ze9QUy6/rG7H qd2f18nWXWkWKMNZVstcsbz0P94Wjh4QcZA3sWcoJLyXT32L0Mn1v8MNp+dpnA72yQhK SgCQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:from:references:in-reply-to :message-id:date; bh=tOATHAwKjXw7CHieuTGy3DP/z705cHXDNiG6v1SLjnQ=; b=QP6uMjsbGVF6NiM5jJdIx5vA4pSB2R94N4lUHmnGLcTV1337EVzQPU6X6XIXdSx2dh tGleIpQ1AIzPFrpzBkBBRy2+RekPbeGDRDK7my5/98G+VKr8Y95dqKM6298X0z+C2rct 6kMZePAVJNcQ4172nGyPrQnllT2fxTN928+RLM4STYTzxZx7qRbFED6JkPxYE0i8PS7B isHpcOZEheNIt3047plQ04W46m3sZ5JXKGJ3JYiuxEn5lltzxmCIlQLIg4XxOcR1Lqpd 6SpR7Lu2gcZn2SDJODfXr6fmMfq/aI1G+FaWlCPydBBaO6mWkRnP9my/d8wVDPcvDGF9 tjiw== 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 e6si7605829oiy.229.2020.03.31.01.58.19; Tue, 31 Mar 2020 01:58:31 -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 S1730343AbgCaI5K (ORCPT + 99 others); Tue, 31 Mar 2020 04:57:10 -0400 Received: from mx.sdf.org ([205.166.94.20]:59173 "EHLO mx.sdf.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729425AbgCaI5G (ORCPT ); Tue, 31 Mar 2020 04:57:06 -0400 Received: from sdf.org (IDENT:lkml@sdf.lonestar.org [205.166.94.16]) by mx.sdf.org (8.15.2/8.14.5) with ESMTPS id 02V8uxem021803 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits) verified NO); Tue, 31 Mar 2020 08:57:00 GMT Received: (from lkml@localhost) by sdf.org (8.15.2/8.12.8/Submit) id 02V8uxMY024939; Tue, 31 Mar 2020 08:56:59 GMT Date: Tue, 31 Mar 2020 08:56:59 GMT Message-Id: <35dd80650fe673c446a5a016b51b6680ce49350d.1585644000.git.lkml@sdf.org> In-Reply-To: <9916203ec97be0f24886fc8478437d161b56f053.1585644000.git.lkml@sdf.org> References: <9916203ec97be0f24886fc8478437d161b56f053.1585644000.git.lkml@sdf.org> From: George Spelvin Subject: [PATCH 2/3] random: Factor helper calc_entropy_frac() out of credit_entropy_bits() To: "Theodore Ts'o" Cc: Andy Lutomirski , Yangtao Li , linux-kernel@vger.kernel.org, lkml@sdf.org Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The helper is mathematically complex, with a large comment explaining it. credit_entropy_bits() has atomicity complexity. Breaking them apart makes both easier to read and understand. No functional change. Signed-off-by: George Spelvin --- And it makes the approximation easier to change in the next patch. drivers/char/random.c | 114 +++++++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 51 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 273dcbb4a790..de90bab5af36 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -653,6 +653,64 @@ static void process_random_ready_list(void) spin_unlock_irqrestore(&random_ready_list_lock, flags); } +/* + * Add some new entropy to an existing pool with finite capacity. We have + * to account for the possibility of overwriting already present entropy. + * Even in the ideal case of pure Shannon entropy, new contributions + * approach the pool capacity asymptotically: + * + * entropy += (capacity - entropy) * (1 - exp(-add/capacity)) + * + * To avoid evaluating an exponential in interrupt context, we use a + * simple fixed-point underestimate. + * + * For add <= capacity/2 then + * (1 - exp(-add/capacity)) >= (add/capacity)*0.7869... + * so we can approximate the exponential with 3/4*add/capacity and still + * be on the safe side by adding at most capacity/2 at a time. + */ +static int calc_entropy_frac(int add, int entropy, + struct entropy_store const *r) +{ + struct poolinfo const *info = r->poolinfo; + const int capacity = info->poolfracbits; + + if (add < 0) { + /* Debit */ + entropy += add; + } else { + const int s = info->poolbitshift + ENTROPY_SHIFT + 2; + /* The +2 corresponds to the denominator of the 3/4 */ + + do { + unsigned int frac = min(add, capacity/2); + unsigned int delta = ((capacity - entropy)*frac*3) >> s; + + entropy += delta; + add -= frac; + } while (unlikely(add) && entropy < capacity-2); + /* + * Because we're careful to always round down, the pool + * will never be completely full. In fact, the maximum + * delta is 3/8 of the space remaining, which means that 3 + * fractional bits remaining will round to +1, but 2 will + * round to +0, so there's no sense continuing. + * + * Stopping at capacity-2 also limits the loop to + * log2(pool_size)/log2(5/8) = 1.475*log2(pool_size) + * iterations no matter how large add is. + */ + } + + if (WARN_ON(entropy < 0)) { + pr_warn("negative entropy/overflow: pool %s count %d\n", + r->name, entropy); + entropy = 0; + } else if (unlikely(entropy > capacity)) + entropy = capacity; + return entropy; +} + /* * Credit (or debit) the entropy store with n bits of entropy. * Use credit_entropy_bits_safe() if the value comes from userspace @@ -661,61 +719,15 @@ static void process_random_ready_list(void) static void credit_entropy_bits(struct entropy_store *r, int nbits) { int entropy_count, orig; - const int pool_size = r->poolinfo->poolfracbits; - int nfrac = nbits << ENTROPY_SHIFT; if (!nbits) return; -retry: - entropy_count = orig = READ_ONCE(r->entropy_count); - if (nfrac < 0) { - /* Debit */ - entropy_count += nfrac; - } else { - /* - * Credit: we have to account for the possibility of - * overwriting already present entropy. Even in the - * ideal case of pure Shannon entropy, new contributions - * approach the full value asymptotically: - * - * entropy <- entropy + (pool_size - entropy) * - * (1 - exp(-add_entropy/pool_size)) - * - * For add_entropy <= pool_size/2 then - * (1 - exp(-add_entropy/pool_size)) >= - * (add_entropy/pool_size)*0.7869... - * so we can approximate the exponential with - * 3/4*add_entropy/pool_size and still be on the - * safe side by adding at most pool_size/2 at a time. - * - * The use of pool_size-2 in the while statement is to - * prevent rounding artifacts from making the loop - * arbitrarily long; this limits the loop to log2(pool_size)*2 - * turns no matter how large nbits is. - */ - int pnfrac = nfrac; - const int s = r->poolinfo->poolbitshift + ENTROPY_SHIFT + 2; - /* The +2 corresponds to the /4 in the denominator */ - - do { - unsigned int anfrac = min(pnfrac, pool_size/2); - unsigned int add = - ((pool_size - entropy_count)*anfrac*3) >> s; - - entropy_count += add; - pnfrac -= anfrac; - } while (unlikely(entropy_count < pool_size-2 && pnfrac)); - } - - if (WARN_ON(entropy_count < 0)) { - pr_warn("negative entropy/overflow: pool %s count %d\n", - r->name, entropy_count); - entropy_count = 0; - } else if (entropy_count > pool_size) - entropy_count = pool_size; - if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) - goto retry; + do { + orig = READ_ONCE(r->entropy_count); + entropy_count = calc_entropy_frac(nbits << ENTROPY_SHIFT, + orig, r); + } while (cmpxchg(&r->entropy_count, orig, entropy_count) != orig); entropy_count >>= ENTROPY_SHIFT; /* Convert to bits */ trace_credit_entropy_bits(r->name, nbits, entropy_count, _RET_IP_); -- 2.26.0