Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

timekeeping: Add raw clock fallback for random_get_entropy()

The addition of random_get_entropy_fallback() provides access to
whichever time source has the highest frequency, which is useful for
gathering entropy on platforms without available cycle counters. It's
not necessarily as good as being able to quickly access a cycle counter
that the CPU has, but it's still something, even when it falls back to
being jiffies-based.

In the event that a given arch does not define get_cycles(), falling
back to the get_cycles() default implementation that returns 0 is really
not the best we can do. Instead, at least calling
random_get_entropy_fallback() would be preferable, because that always
needs to return _something_, even falling back to jiffies eventually.
It's not as though random_get_entropy_fallback() is super high precision
or guaranteed to be entropic, but basically anything that's not zero all
the time is better than returning zero all the time.

Finally, since random_get_entropy_fallback() is used during extremely
early boot when randomizing freelists in mm_init(), it can be called
before timekeeping has been initialized. In that case there really is
nothing we can do; jiffies hasn't even started ticking yet. So just give
up and return 0.

Suggested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Theodore Ts'o <tytso@mit.edu>

+23
+8
include/linux/timex.h
··· 62 62 #include <linux/types.h> 63 63 #include <linux/param.h> 64 64 65 + unsigned long random_get_entropy_fallback(void); 66 + 65 67 #include <asm/timex.h> 66 68 67 69 #ifndef random_get_entropy ··· 76 74 * 77 75 * By default we use get_cycles() for this purpose, but individual 78 76 * architectures may override this in their asm/timex.h header file. 77 + * If a given arch does not have get_cycles(), then we fallback to 78 + * using random_get_entropy_fallback(). 79 79 */ 80 + #ifdef get_cycles 80 81 #define random_get_entropy() ((unsigned long)get_cycles()) 82 + #else 83 + #define random_get_entropy() random_get_entropy_fallback() 84 + #endif 81 85 #endif 82 86 83 87 /*
+15
kernel/time/timekeeping.c
··· 17 17 #include <linux/clocksource.h> 18 18 #include <linux/jiffies.h> 19 19 #include <linux/time.h> 20 + #include <linux/timex.h> 20 21 #include <linux/tick.h> 21 22 #include <linux/stop_machine.h> 22 23 #include <linux/pvclock_gtod.h> ··· 2381 2380 return 0; 2382 2381 } 2383 2382 2383 + /** 2384 + * random_get_entropy_fallback - Returns the raw clock source value, 2385 + * used by random.c for platforms with no valid random_get_entropy(). 2386 + */ 2387 + unsigned long random_get_entropy_fallback(void) 2388 + { 2389 + struct tk_read_base *tkr = &tk_core.timekeeper.tkr_mono; 2390 + struct clocksource *clock = READ_ONCE(tkr->clock); 2391 + 2392 + if (unlikely(timekeeping_suspended || !clock)) 2393 + return 0; 2394 + return clock->read(clock); 2395 + } 2396 + EXPORT_SYMBOL_GPL(random_get_entropy_fallback); 2384 2397 2385 2398 /** 2386 2399 * do_adjtimex() - Accessor function to NTP __do_adjtimex function