chiark / gitweb /
util: don't block on getrandom()
authorLennart Poettering <lennart@poettering.net>
Thu, 30 Oct 2014 14:27:53 +0000 (15:27 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 30 Oct 2014 14:27:53 +0000 (15:27 +0100)
src/shared/missing.h
src/shared/util.c

index 85d3fec..7725e47 100644 (file)
@@ -149,6 +149,14 @@ static inline int getrandom(void *buffer, size_t count, unsigned flags) {
 }
 #endif
 
 }
 #endif
 
+#ifndef GRND_NONBLOCK
+#define GRND_NONBLOCK 0x0001
+#endif
+
+#ifndef GRND_RANDOM
+#define GRND_RANDOM 0x0002
+#endif
+
 #ifndef BTRFS_IOCTL_MAGIC
 #define BTRFS_IOCTL_MAGIC 0x94
 #endif
 #ifndef BTRFS_IOCTL_MAGIC
 #define BTRFS_IOCTL_MAGIC 0x94
 #endif
index ceafba8..1d67abe 100644 (file)
@@ -2470,10 +2470,17 @@ int dev_urandom(void *p, size_t n) {
         int r, fd;
         ssize_t k;
 
         int r, fd;
         ssize_t k;
 
-        /* Use the syscall unless we know we don't have it, or when
-         * the requested size is too large for it. */
+        /* Gathers some randomness from the kernel. This call will
+         * never block, and will always return some data from the
+         * kernel, regardless if the random pool is fully initialized
+         * or not. It thus makes no guarantee for the quality of the
+         * returned entropy, but is good enough for or usual usecases
+         * of seeding the hash functions for hashtable */
+
+        /* Use the getrandom() syscall unless we know we don't have
+         * it, or when the requested size is too large for it. */
         if (have_syscall != 0 || (size_t) (int) n != n) {
         if (have_syscall != 0 || (size_t) (int) n != n) {
-                r = getrandom(p, n, 0);
+                r = getrandom(p, n, GRND_NONBLOCK);
                 if (r == (int) n) {
                         have_syscall = true;
                         return 0;
                 if (r == (int) n) {
                         have_syscall = true;
                         return 0;
@@ -2481,8 +2488,17 @@ int dev_urandom(void *p, size_t n) {
 
                 if (r < 0) {
                         if (errno == ENOSYS)
 
                 if (r < 0) {
                         if (errno == ENOSYS)
-                                /* we lack the syscall, continue with reading from /dev/urandom */
+                                /* we lack the syscall, continue with
+                                 * reading from /dev/urandom */
                                 have_syscall = false;
                                 have_syscall = false;
+                        else if (errno == EAGAIN)
+                                /* not enough entropy for now. Let's
+                                 * remember to use the syscall the
+                                 * next time, again, but also read
+                                 * from /dev/urandom for now, which
+                                 * doesn't care about the current
+                                 * amount of entropy.  */
+                                have_syscall = true;
                         else
                                 return -errno;
                 } else
                         else
                                 return -errno;
                 } else