mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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


  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®