svn commit: r355930 - head/sys/dev/random

Conrad Meyer cem at FreeBSD.org
Fri Dec 20 08:31:24 UTC 2019


Author: cem
Date: Fri Dec 20 08:31:23 2019
New Revision: 355930
URL: https://svnweb.freebsd.org/changeset/base/355930

Log:
  random(4): Fortuna: Enable concurrent generation by default for 13
  
  Flip the knob added in r349154 to "enabled."  The commit message from that
  revision and associated code comment describe the rationale, implementation,
  and motivation for the new default in detail.  I have dog-fooded this
  configuration on my own systems for six months, for what that's worth.
  
  For end-users: 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 restored by
  setting the kern.random.fortuna.concurrent_read="0" 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.  Work is ongoing to address both the generation-side (in
  more depth) and the harvest-side scaling problems.
  
  Approved by:	csprng(delphij, markm)
  Tested by:	markm
  Differential Revision:	https://reviews.freebsd.org/D22879

Modified:
  head/sys/dev/random/fortuna.c

Modified: head/sys/dev/random/fortuna.c
==============================================================================
--- head/sys/dev/random/fortuna.c	Fri Dec 20 08:15:55 2019	(r355929)
+++ head/sys/dev/random/fortuna.c	Fri Dec 20 08:31:23 2019	(r355930)
@@ -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
@@ -243,7 +247,7 @@ static struct fortuna_state {
  *
  * (stack_C == C_0; stack_K == K_0; stack_C' == C''; stack_K' == K'.)
  */
-static bool fortuna_concurrent_read __read_frequently = false;
+static bool fortuna_concurrent_read __read_frequently = true;
 
 #ifdef _KERNEL
 static struct sysctl_ctx_list random_clist;


More information about the svn-src-all mailing list