From: Timo Sirainen Date: Thu, 22 Apr 2021 08:09:49 +0000 (+0300) Subject: lib: Use 32 byte buffer for getting randomness X-Git-Tag: 2.3.17~296 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a7146d0939d7dbf4e72a2d53a98649fb7f2fe067;p=thirdparty%2Fdovecot%2Fcore.git lib: Use 32 byte buffer for getting randomness This reduces the number of syscalls when small amount of randomness is requested, like i_rand*() calls using only 4 bytes at a time. --- diff --git a/src/lib/randgen.c b/src/lib/randgen.c index b90e32160e..c56c01a718 100644 --- a/src/lib/randgen.c +++ b/src/lib/randgen.c @@ -61,6 +61,17 @@ static int init_refcount = 0; static int urandom_fd = -1; #if defined(USE_GETRANDOM) || defined(USE_RANDOM_DEV) +/* Use a small buffer when reading randomness. This is mainly to make small + random reads more efficient, such as i_rand*(). When reading larger amount + of randomness this buffer is bypassed. + + There doesn't seem to be a big difference in Linux system CPU usage when + buffer size is above 16 bytes. Double it just to be safe. Avoid it being + too large anyway so we don't unnecessarily waste CPU and memory. */ +#define RANDOM_READ_BUFFER_SIZE 32 +static unsigned char random_next[RANDOM_READ_BUFFER_SIZE]; +static size_t random_next_size = 0; + static void random_open_urandom(void) { urandom_fd = open(DEV_URANDOM_PATH, O_RDONLY); @@ -75,7 +86,7 @@ static void random_open_urandom(void) fd_close_on_exec(urandom_fd, TRUE); } -static inline int random_read(char *buf, size_t size) +static inline int random_read(unsigned char *buf, size_t size) { ssize_t ret = 0; # if defined(USE_GETRANDOM) @@ -132,9 +143,29 @@ void random_fill(void *buf, size_t size) ssize_t ret; for (pos = 0; pos < size; ) { - ret = random_read(PTR_OFFSET(buf, pos), size - pos); - if (ret > -1) - pos += ret; + if (size >= sizeof(random_next) && random_next_size == 0) { + /* Asking for lots of randomness. Read directly to the + destination buffer. */ + ret = random_read(PTR_OFFSET(buf, pos), size - pos); + if (ret > -1) + pos += ret; + } else { + /* Asking for a little randomness. Read via a larger + buffer to reduce the number of syscalls. */ + if (random_next_size > 0) + ret = random_next_size; + else + ret = random_read(random_next, + sizeof(random_next)); + if (ret > 0) { + size_t used = I_MIN(size - pos, (size_t)ret); + memcpy(PTR_OFFSET(buf, pos), random_next, used); + random_next_size = ret - used; + memmove(random_next, random_next + used, + random_next_size); + pos += used; + } + } } #endif /* defined(USE_ARC4RANDOM) */ }