From: "Theodore Ts'o" <tytso@mit.edu>
To: Linux Kernel Developers List <linux-kernel@vger.kernel.org>
Cc: torvalds@linux-foundation.org, w@1wt.eu, ewust@umich.edu,
zakir@umich.edu, greg@kroah.com, mpm@selenic.com,
nadiah@cs.ucsd.edu, jhalderm@umich.edu, tglx@linutronix.de,
davem@davemloft.net, "Theodore Ts'o" <tytso@mit.edu>
Subject: [PATCH 02/10] random: use lockless techniques when mixing entropy pools
Date: Thu, 5 Jul 2012 14:12:05 -0400 [thread overview]
Message-ID: <1341511933-11169-3-git-send-email-tytso@mit.edu> (raw)
In-Reply-To: <1341511933-11169-1-git-send-email-tytso@mit.edu>
The real-time Linux folks didn't like add_interrupt_randomness()
taking a spinlock since it is called in the low-level interrupt
routine. Using atomic_t's and cmpxchg is also too expensive on some
of the older architectures. So we'll bite the bullet and use
ACCESS_ONCE() and smp_rmb()/smp_wmb() to minimize the race windows
when mixing in the entropy pool.
Also, we will use a trylock when trying to increase then entropy
accounting during the interrupt path to avoid taking a spinlock there;
if there is contention, we will simply not credit the entropy count,
thus failing safe. Thanks to Dan Carpenter for suggesting this
approach.
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
---
drivers/char/random.c | 41 ++++++++++++++++++++++++-----------------
1 file changed, 24 insertions(+), 17 deletions(-)
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 53b3e85..789709e 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -418,9 +418,9 @@ struct entropy_store {
/* read-write data: */
spinlock_t lock;
unsigned add_ptr;
+ unsigned input_rotate;
int entropy_count;
int entropy_total;
- int input_rotate;
unsigned int initialized:1;
__u8 last_data[EXTRACT_SIZE];
};
@@ -478,16 +478,16 @@ static void mix_pool_bytes_extract(struct entropy_store *r, const void *in,
__u32 w;
unsigned long flags;
- /* Taps are constant, so we can load them without holding r->lock. */
tap1 = r->poolinfo->tap1;
tap2 = r->poolinfo->tap2;
tap3 = r->poolinfo->tap3;
tap4 = r->poolinfo->tap4;
tap5 = r->poolinfo->tap5;
- spin_lock_irqsave(&r->lock, flags);
- input_rotate = r->input_rotate;
- i = r->add_ptr;
+ local_irq_save(flags);
+ smp_rmb();
+ input_rotate = ACCESS_ONCE(r->input_rotate);
+ i = ACCESS_ONCE(r->add_ptr);
/* mix one byte at a time to simplify size handling and churn faster */
while (nbytes--) {
@@ -514,19 +514,19 @@ static void mix_pool_bytes_extract(struct entropy_store *r, const void *in,
input_rotate += i ? 7 : 14;
}
- r->input_rotate = input_rotate;
- r->add_ptr = i;
+ ACCESS_ONCE(r->input_rotate) = input_rotate;
+ ACCESS_ONCE(r->add_ptr) = i;
+ local_irq_restore(flags);
+ smp_wmb();
if (out)
for (j = 0; j < 16; j++)
((__u32 *)out)[j] = r->pool[(i - j) & wordmask];
-
- spin_unlock_irqrestore(&r->lock, flags);
}
static void mix_pool_bytes(struct entropy_store *r, const void *in, int bytes)
{
- mix_pool_bytes_extract(r, in, bytes, NULL);
+ mix_pool_bytes_extract(r, in, bytes, NULL);
}
struct fast_pool {
@@ -558,10 +558,12 @@ static void fast_mix(struct fast_pool *f, const void *in, int nbytes)
f->rotate = input_rotate;
}
+#define CREDIT_ENTROPY_BITS_NOWAIT 0x01
+
/*
* Credit (or debit) the entropy store with n bits of entropy
*/
-static void credit_entropy_bits(struct entropy_store *r, int nbits)
+static void credit_entropy_bits(struct entropy_store *r, int nbits, int fl)
{
unsigned long flags;
int entropy_count;
@@ -569,7 +571,11 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits)
if (!nbits)
return;
- spin_lock_irqsave(&r->lock, flags);
+ if (fl & CREDIT_ENTROPY_BITS_NOWAIT) {
+ if (!spin_trylock_irqsave(&r->lock, flags))
+ return;
+ } else
+ spin_lock_irqsave(&r->lock, flags);
DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name);
entropy_count = r->entropy_count;
@@ -592,6 +598,7 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits)
wake_up_interruptible(&random_read_wait);
kill_fasync(&fasync, SIGIO, POLL_IN);
}
+
spin_unlock_irqrestore(&r->lock, flags);
}
@@ -714,7 +721,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
* and limit entropy entimate to 12 bits.
*/
credit_entropy_bits(&input_pool,
- min_t(int, fls(delta>>1), 11));
+ min_t(int, fls(delta>>1), 11), 0);
}
out:
preempt_enable();
@@ -764,7 +771,7 @@ void add_interrupt_randomness(int irq)
r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool;
mix_pool_bytes(r, &fast_pool->pool, sizeof(fast_pool->pool));
- credit_entropy_bits(r, 1);
+ credit_entropy_bits(r, 1, CREDIT_ENTROPY_BITS_NOWAIT);
}
#ifdef CONFIG_BLOCK
@@ -816,7 +823,7 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
bytes = extract_entropy(r->pull, tmp, bytes,
random_read_wakeup_thresh / 8, rsvd);
mix_pool_bytes(r, tmp, bytes);
- credit_entropy_bits(r, bytes*8);
+ credit_entropy_bits(r, bytes*8, 0);
}
}
@@ -1211,7 +1218,7 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
return -EPERM;
if (get_user(ent_count, p))
return -EFAULT;
- credit_entropy_bits(&input_pool, ent_count);
+ credit_entropy_bits(&input_pool, ent_count, 0);
return 0;
case RNDADDENTROPY:
if (!capable(CAP_SYS_ADMIN))
@@ -1226,7 +1233,7 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
size);
if (retval < 0)
return retval;
- credit_entropy_bits(&input_pool, ent_count);
+ credit_entropy_bits(&input_pool, ent_count, 0);
return 0;
case RNDZAPENTCNT:
case RNDCLEARPOOL:
--
1.7.11.1.108.gb129051
next prev parent reply other threads:[~2012-07-05 18:13 UTC|newest]
Thread overview: 56+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-07-05 18:12 [PATCH 00/10] /dev/random fixups Theodore Ts'o
2012-07-05 18:12 ` [PATCH 01/10] random: make 'add_interrupt_randomness()' do something sane Theodore Ts'o
2012-07-05 18:47 ` Matt Mackall
2012-07-05 18:52 ` Linus Torvalds
2012-07-05 21:39 ` Matt Mackall
2012-07-05 21:47 ` Linus Torvalds
2012-07-05 22:00 ` Theodore Ts'o
2012-07-05 22:21 ` Linus Torvalds
2012-07-05 22:31 ` Matt Mackall
2012-07-05 22:35 ` Linus Torvalds
2012-07-05 23:21 ` Theodore Ts'o
2012-07-06 2:59 ` Linus Torvalds
2012-07-06 13:01 ` Theodore Ts'o
2012-07-06 16:24 ` Linus Torvalds
2012-07-06 16:52 ` Theodore Ts'o
2012-07-09 19:15 ` Matt Mackall
2012-07-25 18:43 ` Thomas Gleixner
[not found] ` <CAGsuqq2MWuFnY7PMb_2ddBNNJr80xB_JW+Wryq3mhhmQuEojpg@mail.gmail.com>
2012-07-06 21:59 ` Theodore Ts'o
2012-07-05 18:12 ` Theodore Ts'o [this message]
2012-07-05 18:18 ` [PATCH 02/10] random: use lockless techniques when mixing entropy pools Linus Torvalds
2012-07-05 18:19 ` Greg KH
2012-07-05 23:09 ` Theodore Ts'o
2012-07-05 19:10 ` Matt Mackall
2012-07-05 19:47 ` Theodore Ts'o
2012-07-05 20:45 ` Matt Mackall
2012-07-05 18:12 ` [PATCH 03/10] random: create add_device_randomness() interface Theodore Ts'o
2012-07-05 18:12 ` [PATCH 04/10] usb: feed USB device information to the /dev/random driver Theodore Ts'o
2012-07-05 18:12 ` [PATCH 05/10] net: feed /dev/random with the MAC address when registering a device Theodore Ts'o
2012-07-05 18:12 ` [PATCH 06/10] random: use the arch-specific rng in xfer_secondary_pool Theodore Ts'o
2012-07-05 18:49 ` Linus Torvalds
2012-07-05 18:12 ` [PATCH 07/10] random: add new get_random_bytes_arch() function Theodore Ts'o
2012-07-05 18:35 ` Linus Torvalds
2012-07-05 19:50 ` Theodore Ts'o
2012-07-05 21:45 ` Matt Mackall
2012-07-25 3:37 ` H. Peter Anvin
2012-07-25 7:22 ` Ingo Molnar
2012-07-25 15:10 ` Theodore Ts'o
2012-07-25 15:19 ` H. Peter Anvin
2012-07-25 17:37 ` [PATCH] random: mix in architectural randomness in extract_buf() H. Peter Anvin
2012-07-25 23:50 ` Ben Hutchings
2012-07-26 0:32 ` H. Peter Anvin
2012-07-28 2:39 ` Theodore Ts'o
2012-07-28 2:48 ` H. Peter Anvin
2012-07-26 3:16 ` [PATCH 07/10] random: add new get_random_bytes_arch() function H. Peter Anvin
2012-07-26 3:24 ` H. Peter Anvin
2012-07-05 18:12 ` [PATCH 08/10] random: unify mix_pool_bytes() and mix_pool_bytes_entropy() Theodore Ts'o
2012-07-05 18:12 ` [PATCH 09/10] random: add tracepoints for easier debugging and verification Theodore Ts'o
2012-07-05 18:12 ` [PATCH 10/10] MAINTAINERS: Theodore Ts'o is taking over the random driver Theodore Ts'o
2012-07-06 11:40 ` [PATCH 00/10] /dev/random fixups Fengguang Wu
2012-07-06 12:44 ` Theodore Ts'o
2012-07-20 20:15 ` [PATCH] dmi: Feed DMI table to /dev/random driver Tony Luck
2012-07-20 21:03 ` Matt Mackall
2012-07-21 0:56 ` Theodore Ts'o
2012-07-21 1:19 ` Tony Luck
2012-07-21 2:02 ` Theodore Ts'o
2012-07-23 16:47 ` [PATCH] random: Add comment to random_initialize() Tony Luck
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1341511933-11169-3-git-send-email-tytso@mit.edu \
--to=tytso@mit.edu \
--cc=davem@davemloft.net \
--cc=ewust@umich.edu \
--cc=greg@kroah.com \
--cc=jhalderm@umich.edu \
--cc=linux-kernel@vger.kernel.org \
--cc=mpm@selenic.com \
--cc=nadiah@cs.ucsd.edu \
--cc=tglx@linutronix.de \
--cc=torvalds@linux-foundation.org \
--cc=w@1wt.eu \
--cc=zakir@umich.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®