Some upcoming changes will introduce additional callers of them. Signed-off-by: Thomas Weißschuh <thomas.weisssc...@linutronix.de> --- drivers/char/random.c | 51 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 18 deletions(-)
diff --git a/drivers/char/random.c b/drivers/char/random.c index b0b88c6f6a1afcdb770e39b7a64cb3408e33bd2c..73c53a4fb949bfd2ed723fa3cec3fe0d066a7fa3 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -246,6 +246,37 @@ static unsigned int crng_reseed_interval(void) /* Used by crng_reseed() and crng_make_state() to extract a new seed from the input pool. */ static void extract_entropy(void *buf, size_t len); +/* This updates the generation in the vDSO data page */ +static void random_vdso_update_generation(unsigned long next_gen) +{ + if (!IS_ENABLED(CONFIG_VDSO_GETRANDOM)) + return; + + /* base_crng.generation's invalid value is ULONG_MAX, while + * vdso_k_rng_data->generation's invalid value is 0, so add one to the + * former to arrive at the latter. Use smp_store_release so that this + * is ordered with the write above to base_crng.generation. Pairs with + * the smp_rmb() before the syscall in the vDSO code. + * + * Cast to unsigned long for 32-bit architectures, since atomic 64-bit + * operations are not supported on those architectures. This is safe + * because base_crng.generation is a 32-bit value. On big-endian + * architectures it will be stored in the upper 32 bits, but that's okay + * because the vDSO side only checks whether the value changed, without + * actually using or interpreting the value. + */ + smp_store_release((unsigned long *)&vdso_k_rng_data->generation, next_gen + 1); +} + +/* This sets is_ready in the vDSO data page */ +static void random_vdso_set_ready(void) +{ + if (!IS_ENABLED(CONFIG_VDSO_GETRANDOM)) + return; + + WRITE_ONCE(vdso_k_rng_data->is_ready, true); +} + /* This extracts a new crng key from the input pool. */ static void crng_reseed(struct work_struct *work) { @@ -272,22 +303,7 @@ static void crng_reseed(struct work_struct *work) if (next_gen == ULONG_MAX) ++next_gen; WRITE_ONCE(base_crng.generation, next_gen); - - /* base_crng.generation's invalid value is ULONG_MAX, while - * vdso_k_rng_data->generation's invalid value is 0, so add one to the - * former to arrive at the latter. Use smp_store_release so that this - * is ordered with the write above to base_crng.generation. Pairs with - * the smp_rmb() before the syscall in the vDSO code. - * - * Cast to unsigned long for 32-bit architectures, since atomic 64-bit - * operations are not supported on those architectures. This is safe - * because base_crng.generation is a 32-bit value. On big-endian - * architectures it will be stored in the upper 32 bits, but that's okay - * because the vDSO side only checks whether the value changed, without - * actually using or interpreting the value. - */ - if (IS_ENABLED(CONFIG_VDSO_GETRANDOM)) - smp_store_release((unsigned long *)&vdso_k_rng_data->generation, next_gen + 1); + random_vdso_update_generation(next_gen); if (!static_branch_likely(&crng_is_ready)) crng_init = CRNG_READY; @@ -741,8 +757,7 @@ static void __cold _credit_init_bits(size_t bits) if (static_key_initialized && system_unbound_wq) queue_work(system_unbound_wq, &set_ready); atomic_notifier_call_chain(&random_ready_notifier, 0, NULL); - if (IS_ENABLED(CONFIG_VDSO_GETRANDOM)) - WRITE_ONCE(vdso_k_rng_data->is_ready, true); + random_vdso_set_ready(); wake_up_interruptible(&crng_init_wait); kill_fasync(&fasync, SIGIO, POLL_IN); pr_notice("crng init done\n"); -- 2.51.0