git: d84d8a42e9dc - stable/12 - random(4): Fortuna: Update concurrent generation documentation

From: David E. O'Brien <obrien_at_FreeBSD.org>
Date: Thu, 17 Feb 2022 05:06:01 UTC
The branch stable/12 has been updated by obrien:

URL: https://cgit.FreeBSD.org/src/commit/?id=d84d8a42e9dc1b23c494514172074f15817f1ac2

commit d84d8a42e9dc1b23c494514172074f15817f1ac2
Author:     Conrad Meyer <cem@FreeBSD.org>
AuthorDate: 2019-12-20 08:31:23 +0000
Commit:     David E. O'Brien <obrien@FreeBSD.org>
CommitDate: 2022-02-17 04:57:46 +0000

    random(4): Fortuna: Update concurrent generation documentation
    
    The knob added in r349154 remains "disabled."  The commit message from that
    revision and associated code comment describe the rationale, implementation,
    and motivation for the new option in detail.
    
    For end-users: if you enable this, the result is just as secure.
    The benefit is a faster, more responsive system when processes
    produce significant demand on random(4).
    
    As mentioned in the earlier commit, the prior behavior may be enabled by
    setting the kern.random.fortuna.concurrent_read="1" knob in loader.conf(5).
    
    This scales the random generation side of random(4) somewhat, although there
    is still a global mutex being shared by all cores and rand_harvestq; the
    situation is generally much better than it was before on small CPU systems,
    but do not expect miracles on 256-core systems running 256-thread full-rate
    random(4) read.
    
    (cherry picked from commit 548dca90ae2fc3c0900c94a97e89aa97d6c36eae)
---
 sys/dev/random/fortuna.c | 26 +++++++++++++++-----------
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/sys/dev/random/fortuna.c b/sys/dev/random/fortuna.c
index f93cf7145ca3..52e93a594014 100644
--- a/sys/dev/random/fortuna.c
+++ b/sys/dev/random/fortuna.c
@@ -125,14 +125,14 @@ static struct fortuna_state {
 } fortuna_state;
 
 /*
- * This knob enables or disables Concurrent Reads.  The plan is to turn it on
- * by default sometime before 13.0 branches.
+ * This knob enables or disables the "Concurrent Reads" Fortuna feature.
  *
- * The benefit is improved concurrency in Fortuna.  That is reflected in two
- * related aspects:
+ * The benefit of Concurrent Reads is improved concurrency in Fortuna.  That is
+ * reflected in two related aspects:
  *
- * 1. Concurrent devrandom readers can achieve similar throughput to a single
- *    reader thread.
+ * 1. Concurrent full-rate devrandom readers can achieve similar throughput to
+ *    a single reader thread (at least up to a modest number of cores; the
+ *    non-concurrent design falls over at 2 readers).
  *
  * 2. The rand_harvestq process spends much less time spinning when one or more
  *    readers is processing a large request.  Partially this is due to
@@ -142,16 +142,20 @@ static struct fortuna_state {
  *    mutexes assume that a lock holder currently on CPU will release the lock
  *    quickly, and spin if the owning thread is currently running.
  *
+ *    (There is no reason rand_harvestq necessarily has to use the same lock as
+ *    the generator, or that it must necessarily drop and retake locks
+ *    repeatedly, but that is the current status quo.)
+ *
  * The concern is that the reduced lock scope might results in a less safe
  * random(4) design.  However, the reduced-lock scope design is still
  * fundamentally Fortuna.  This is discussed below.
  *
  * Fortuna Read() only needs mutual exclusion between readers to correctly
- * update the shared read-side state: just C, the 128-bit counter, and K, the
- * current cipher key.
+ * update the shared read-side state: C, the 128-bit counter; and K, the
+ * current cipher/PRF key.
  *
  * In the Fortuna design, the global counter C should provide an independent
- * range of values per generator (CTR-mode cipher or similar) invocation.
+ * range of values per request.
  *
  * Under lock, we can save a copy of C on the stack, and increment the global C
  * by the number of blocks a Read request will require.
@@ -159,7 +163,7 @@ static struct fortuna_state {
  * Still under lock, we can save a copy of the key K on the stack, and then
  * perform the usual key erasure K' <- Keystream(C, K, ...).  This does require
  * generating 256 bits (32 bytes) of cryptographic keystream output with the
- * global lock held, but that's all; none of the user keystream generation must
+ * global lock held, but that's all; none of the API keystream generation must
  * be performed under lock.
  *
  * At this point, we may unlock.
@@ -210,7 +214,7 @@ static struct fortuna_state {
  * 2:  <- GenBytes()
  * 2:Unlock()
  *
- * Just prior to unlock, shared state is still identical:
+ * Just prior to unlock, global state is identical:
  * ------------------------------------------------------
  *
  * C'''' == (C_0 + N + 1) + M + 1      C'''' == (C_0 + N + 1) + M + 1