Skip to content

Commit 3092adc

Browse files
committed
random: unify batched entropy implementations
There are currently two separate batched entropy implementations, for u32 and u64, with nearly identical code, with the goal of avoiding unaligned memory accesses and letting the buffers be used more efficiently. Having to maintain these two functions independently is a bit of a hassle though, considering that they always need to be kept in sync. This commit factors them out into a type-generic macro, so that the expansion produces the same code as before, such that diffing the assembly shows no differences. This will also make it easier in the future to add u16 and u8 batches. This was initially tested using an always_inline function and letting gcc constant fold the type size in, but the code gen was less efficient, and in general it was more verbose and harder to follow. So this patch goes with the boring macro solution, similar to what's already done for the _wait functions in random.h. Cc: Dominik Brodowski <linux@dominikbrodowski.net> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
1 parent 5ad7dd8 commit 3092adc

1 file changed

Lines changed: 55 additions & 92 deletions

File tree

drivers/char/random.c

Lines changed: 55 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -460,99 +460,62 @@ static ssize_t get_random_bytes_user(void __user *ubuf, size_t len)
460460
* provided by this function is okay, the function wait_for_random_bytes()
461461
* should be called and return 0 at least once at any point prior.
462462
*/
463-
struct batched_entropy {
464-
union {
465-
/*
466-
* We make this 1.5x a ChaCha block, so that we get the
467-
* remaining 32 bytes from fast key erasure, plus one full
468-
* block from the detached ChaCha state. We can increase
469-
* the size of this later if needed so long as we keep the
470-
* formula of (integer_blocks + 0.5) * CHACHA_BLOCK_SIZE.
471-
*/
472-
u64 entropy_u64[CHACHA_BLOCK_SIZE * 3 / (2 * sizeof(u64))];
473-
u32 entropy_u32[CHACHA_BLOCK_SIZE * 3 / (2 * sizeof(u32))];
474-
};
475-
local_lock_t lock;
476-
unsigned long generation;
477-
unsigned int position;
478-
};
479-
480-
481-
static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u64) = {
482-
.lock = INIT_LOCAL_LOCK(batched_entropy_u64.lock),
483-
.position = UINT_MAX
484-
};
485-
486-
u64 get_random_u64(void)
487-
{
488-
u64 ret;
489-
unsigned long flags;
490-
struct batched_entropy *batch;
491-
unsigned long next_gen;
492-
493-
warn_unseeded_randomness();
494-
495-
if (!crng_ready()) {
496-
_get_random_bytes(&ret, sizeof(ret));
497-
return ret;
498-
}
499-
500-
local_lock_irqsave(&batched_entropy_u64.lock, flags);
501-
batch = raw_cpu_ptr(&batched_entropy_u64);
502-
503-
next_gen = READ_ONCE(base_crng.generation);
504-
if (batch->position >= ARRAY_SIZE(batch->entropy_u64) ||
505-
next_gen != batch->generation) {
506-
_get_random_bytes(batch->entropy_u64, sizeof(batch->entropy_u64));
507-
batch->position = 0;
508-
batch->generation = next_gen;
509-
}
510463

511-
ret = batch->entropy_u64[batch->position];
512-
batch->entropy_u64[batch->position] = 0;
513-
++batch->position;
514-
local_unlock_irqrestore(&batched_entropy_u64.lock, flags);
515-
return ret;
516-
}
517-
EXPORT_SYMBOL(get_random_u64);
518-
519-
static DEFINE_PER_CPU(struct batched_entropy, batched_entropy_u32) = {
520-
.lock = INIT_LOCAL_LOCK(batched_entropy_u32.lock),
521-
.position = UINT_MAX
522-
};
523-
524-
u32 get_random_u32(void)
525-
{
526-
u32 ret;
527-
unsigned long flags;
528-
struct batched_entropy *batch;
529-
unsigned long next_gen;
530-
531-
warn_unseeded_randomness();
532-
533-
if (!crng_ready()) {
534-
_get_random_bytes(&ret, sizeof(ret));
535-
return ret;
536-
}
537-
538-
local_lock_irqsave(&batched_entropy_u32.lock, flags);
539-
batch = raw_cpu_ptr(&batched_entropy_u32);
540-
541-
next_gen = READ_ONCE(base_crng.generation);
542-
if (batch->position >= ARRAY_SIZE(batch->entropy_u32) ||
543-
next_gen != batch->generation) {
544-
_get_random_bytes(batch->entropy_u32, sizeof(batch->entropy_u32));
545-
batch->position = 0;
546-
batch->generation = next_gen;
547-
}
548-
549-
ret = batch->entropy_u32[batch->position];
550-
batch->entropy_u32[batch->position] = 0;
551-
++batch->position;
552-
local_unlock_irqrestore(&batched_entropy_u32.lock, flags);
553-
return ret;
554-
}
555-
EXPORT_SYMBOL(get_random_u32);
464+
#define DEFINE_BATCHED_ENTROPY(type) \
465+
struct batch_ ##type { \
466+
/* \
467+
* We make this 1.5x a ChaCha block, so that we get the \
468+
* remaining 32 bytes from fast key erasure, plus one full \
469+
* block from the detached ChaCha state. We can increase \
470+
* the size of this later if needed so long as we keep the \
471+
* formula of (integer_blocks + 0.5) * CHACHA_BLOCK_SIZE. \
472+
*/ \
473+
type entropy[CHACHA_BLOCK_SIZE * 3 / (2 * sizeof(type))]; \
474+
local_lock_t lock; \
475+
unsigned long generation; \
476+
unsigned int position; \
477+
}; \
478+
\
479+
static DEFINE_PER_CPU(struct batch_ ##type, batched_entropy_ ##type) = { \
480+
.lock = INIT_LOCAL_LOCK(batched_entropy_ ##type.lock), \
481+
.position = UINT_MAX \
482+
}; \
483+
\
484+
type get_random_ ##type(void) \
485+
{ \
486+
type ret; \
487+
unsigned long flags; \
488+
struct batch_ ##type *batch; \
489+
unsigned long next_gen; \
490+
\
491+
warn_unseeded_randomness(); \
492+
\
493+
if (!crng_ready()) { \
494+
_get_random_bytes(&ret, sizeof(ret)); \
495+
return ret; \
496+
} \
497+
\
498+
local_lock_irqsave(&batched_entropy_ ##type.lock, flags); \
499+
batch = raw_cpu_ptr(&batched_entropy_##type); \
500+
\
501+
next_gen = READ_ONCE(base_crng.generation); \
502+
if (batch->position >= ARRAY_SIZE(batch->entropy) || \
503+
next_gen != batch->generation) { \
504+
_get_random_bytes(batch->entropy, sizeof(batch->entropy)); \
505+
batch->position = 0; \
506+
batch->generation = next_gen; \
507+
} \
508+
\
509+
ret = batch->entropy[batch->position]; \
510+
batch->entropy[batch->position] = 0; \
511+
++batch->position; \
512+
local_unlock_irqrestore(&batched_entropy_ ##type.lock, flags); \
513+
return ret; \
514+
} \
515+
EXPORT_SYMBOL(get_random_ ##type);
516+
517+
DEFINE_BATCHED_ENTROPY(u64)
518+
DEFINE_BATCHED_ENTROPY(u32)
556519

557520
#ifdef CONFIG_SMP
558521
/*

0 commit comments

Comments
 (0)