linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 1/2] random: make add_hwgenerator_randomness() more flexible
@ 2022-08-31 17:20 Sven van Ashbrook
  2022-08-31 17:20 ` [PATCH v1 2/2] hwrng: core: fix potential suspend/resume race condition Sven van Ashbrook
  2022-09-01  5:05 ` [PATCH v1 1/2] random: make add_hwgenerator_randomness() more flexible Dominik Brodowski
  0 siblings, 2 replies; 6+ messages in thread
From: Sven van Ashbrook @ 2022-08-31 17:20 UTC (permalink / raw)
  To: LKML
  Cc: Alex Levin, Rajat Jain, Andrey Pronin, Stephen Boyd,
	Sven van Ashbrook, Dominik Brodowski, Eric Biggers, Herbert Xu,
	Jason A. Donenfeld, Olivia Mackall, Petr Mladek,
	Sebastian Andrzej Siewior, Theodore Ts'o, linux-crypto

add_hwgenerator_randomness() currently blocks until more entropy
is needed. But, the required delay function will depend on the
the caller: e.g. freezable kthreads have their own freezable_XXX()
APIs; and delayed_work might prefer to use mod_delayed_work().

To accommodate these requirements, remove the blocking wait, and
let the function return the delay needed until more entropy is needed.

Signed-off-by: Sven van Ashbrook <svenva@chromium.org>
---

 drivers/char/hw_random/core.c |  7 +++++--
 drivers/char/random.c         | 13 ++++++-------
 include/linux/random.h        |  2 +-
 3 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 16f227b995e8..3675122c6cce 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -491,6 +491,7 @@ static int __init register_miscdev(void)
 static int hwrng_fillfn(void *unused)
 {
 	size_t entropy, entropy_credit = 0; /* in 1/1024 of a bit */
+	unsigned long delay;
 	long rc;
 
 	while (!kthread_should_stop()) {
@@ -526,8 +527,10 @@ static int hwrng_fillfn(void *unused)
 			entropy_credit = entropy;
 
 		/* Outside lock, sure, but y'know: randomness. */
-		add_hwgenerator_randomness((void *)rng_fillbuf, rc,
-					   entropy >> 10);
+		delay = add_hwgenerator_randomness((void *)rng_fillbuf, rc,
+						   entropy >> 10);
+		if (delay > 0)
+			schedule_timeout_interruptible(delay);
 	}
 	hwrng_fill = NULL;
 	return 0;
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 79d7d4e4e582..7b6c27065cf9 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -686,7 +686,7 @@ static void __cold _credit_init_bits(size_t bits)
  * the above entropy accumulation routines:
  *
  *	void add_device_randomness(const void *buf, size_t len);
- *	void add_hwgenerator_randomness(const void *buf, size_t len, size_t entropy);
+ *	unsigned long add_hwgenerator_randomness(const void *buf, size_t len, size_t entropy);
  *	void add_bootloader_randomness(const void *buf, size_t len);
  *	void add_vmfork_randomness(const void *unique_vm_id, size_t len);
  *	void add_interrupt_randomness(int irq);
@@ -702,8 +702,8 @@ static void __cold _credit_init_bits(size_t bits)
  * available to them (particularly common in the embedded world).
  *
  * add_hwgenerator_randomness() is for true hardware RNGs, and will credit
- * entropy as specified by the caller. If the entropy pool is full it will
- * block until more entropy is needed.
+ * entropy as specified by the caller. Returns number time delay in jiffies
+ * until more entropy is needed.
  *
  * add_bootloader_randomness() is called by bootloader drivers, such as EFI
  * and device tree, and credits its input depending on whether or not the
@@ -857,10 +857,10 @@ EXPORT_SYMBOL(add_device_randomness);
 
 /*
  * Interface for in-kernel drivers of true hardware RNGs.
- * Those devices may produce endless random bits and will be throttled
+ * Those devices may produce endless random bits and should be throttled
  * when our pool is full.
  */
-void add_hwgenerator_randomness(const void *buf, size_t len, size_t entropy)
+unsigned long add_hwgenerator_randomness(const void *buf, size_t len, size_t entropy)
 {
 	mix_pool_bytes(buf, len);
 	credit_init_bits(entropy);
@@ -869,8 +869,7 @@ void add_hwgenerator_randomness(const void *buf, size_t len, size_t entropy)
 	 * Throttle writing to once every CRNG_RESEED_INTERVAL, unless
 	 * we're not yet initialized.
 	 */
-	if (!kthread_should_stop() && crng_ready())
-		schedule_timeout_interruptible(CRNG_RESEED_INTERVAL);
+	return crng_ready() ? CRNG_RESEED_INTERVAL : 0;
 }
 EXPORT_SYMBOL_GPL(add_hwgenerator_randomness);
 
diff --git a/include/linux/random.h b/include/linux/random.h
index 3fec206487f6..6608b0fb4402 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -17,7 +17,7 @@ void __init add_bootloader_randomness(const void *buf, size_t len);
 void add_input_randomness(unsigned int type, unsigned int code,
 			  unsigned int value) __latent_entropy;
 void add_interrupt_randomness(int irq) __latent_entropy;
-void add_hwgenerator_randomness(const void *buf, size_t len, size_t entropy);
+unsigned long add_hwgenerator_randomness(const void *buf, size_t len, size_t entropy);
 
 #if defined(LATENT_ENTROPY_PLUGIN) && !defined(__CHECKER__)
 static inline void add_latent_entropy(void)
-- 
2.37.2.672.g94769d06f0-goog


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v1 2/2] hwrng: core: fix potential suspend/resume race condition
  2022-08-31 17:20 [PATCH v1 1/2] random: make add_hwgenerator_randomness() more flexible Sven van Ashbrook
@ 2022-08-31 17:20 ` Sven van Ashbrook
  2022-09-06 14:15   ` Sven van Ashbrook
  2022-09-07  6:29   ` Herbert Xu
  2022-09-01  5:05 ` [PATCH v1 1/2] random: make add_hwgenerator_randomness() more flexible Dominik Brodowski
  1 sibling, 2 replies; 6+ messages in thread
From: Sven van Ashbrook @ 2022-08-31 17:20 UTC (permalink / raw)
  To: LKML
  Cc: Alex Levin, Rajat Jain, Andrey Pronin, Stephen Boyd,
	Sven van Ashbrook, Dominik Brodowski, Eric Biggers, Herbert Xu,
	Jason A. Donenfeld, Olivia Mackall, linux-crypto

The hwrng fill function runs as a normal kthread. This thread
doesn't get frozen by the PM, i.e. it will keep running during,
or in, system suspend. It may call the client driver's
data_present()/data_read() functions during, or in, suspend;
which may generate errors or warnings. For example, if the
client driver uses an i2c bus, the following warning may be
intermittently generated:

  i2c: Transfer while suspended

Fix by converting the delay polled kthread into an ordered work
queue running a single, self-rearming delayed_work. Make the
workqueue WQ_FREEZABLE, so the PM will drain any work items
before going into suspend. This prevents client drivers from
being accessed during, or in, suspend.

Tested on a Chromebook containing an cr50 tpm over i2c. The test
consists of 31000 suspend/resume cycles. Occasional
"i2c: Transfer while suspended" warnings are seen. After applying
this patch, these warnings disappear.

This patch also does not appear to cause any regressions on the
ChromeOS test queues.

Signed-off-by: Sven van Ashbrook <svenva@chromium.org>
---

 drivers/char/hw_random/core.c | 95 +++++++++++++++++++----------------
 1 file changed, 51 insertions(+), 44 deletions(-)

diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 3675122c6cce..ee85ca97d215 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -17,7 +17,7 @@
 #include <linux/hw_random.h>
 #include <linux/random.h>
 #include <linux/kernel.h>
-#include <linux/kthread.h>
+#include <linux/workqueue.h>
 #include <linux/sched/signal.h>
 #include <linux/miscdevice.h>
 #include <linux/module.h>
@@ -28,14 +28,17 @@
 
 #define RNG_MODULE_NAME		"hw_random"
 
-static struct hwrng *current_rng;
 /* the current rng has been explicitly chosen by user via sysfs */
 static int cur_rng_set_by_user;
-static struct task_struct *hwrng_fill;
+static struct workqueue_struct *hwrng_wq;
+static struct delayed_work hwrng_fill_dwork;
+static size_t entropy_credit;
+/* Protects rng_list, current_rng, is_hwrng_wq_running */
+static DEFINE_MUTEX(rng_mutex);
 /* list of registered rngs */
 static LIST_HEAD(rng_list);
-/* Protects rng_list and current_rng */
-static DEFINE_MUTEX(rng_mutex);
+static struct hwrng *current_rng;
+static bool is_hwrng_wq_running;
 /* Protects rng read functions, data_avail, rng_buffer and rng_fillbuf */
 static DEFINE_MUTEX(reading_mutex);
 static int data_avail;
@@ -488,37 +491,29 @@ static int __init register_miscdev(void)
 	return misc_register(&rng_miscdev);
 }
 
-static int hwrng_fillfn(void *unused)
+static void hwrng_fillfn(struct work_struct *unused)
 {
-	size_t entropy, entropy_credit = 0; /* in 1/1024 of a bit */
+	unsigned short quality;
 	unsigned long delay;
+	struct hwrng *rng;
+	size_t entropy; /* in 1/1024 of a bit */
 	long rc;
 
-	while (!kthread_should_stop()) {
-		unsigned short quality;
-		struct hwrng *rng;
-
-		rng = get_current_rng();
-		if (IS_ERR(rng) || !rng)
-			break;
-		mutex_lock(&reading_mutex);
-		rc = rng_get_data(rng, rng_fillbuf,
-				  rng_buffer_size(), 1);
-		if (current_quality != rng->quality)
-			rng->quality = current_quality; /* obsolete */
-		quality = rng->quality;
-		mutex_unlock(&reading_mutex);
-		put_rng(rng);
-
-		if (!quality)
-			break;
+	rng = get_current_rng();
+	if (IS_ERR(rng) || !rng)
+		return;
+	mutex_lock(&reading_mutex);
+	rc = rng_get_data(rng, rng_fillbuf, rng_buffer_size(), 1);
+	if (current_quality != rng->quality)
+		rng->quality = current_quality; /* obsolete */
+	quality = rng->quality;
+	mutex_unlock(&reading_mutex);
+	put_rng(rng);
 
-		if (rc <= 0) {
-			pr_warn("hwrng: no data available\n");
-			msleep_interruptible(10000);
-			continue;
-		}
+	if (!quality)
+		return;
 
+	if (rc > 0) {
 		/* If we cannot credit at least one bit of entropy,
 		 * keep track of the remainder for the next iteration
 		 */
@@ -529,11 +524,11 @@ static int hwrng_fillfn(void *unused)
 		/* Outside lock, sure, but y'know: randomness. */
 		delay = add_hwgenerator_randomness((void *)rng_fillbuf, rc,
 						   entropy >> 10);
-		if (delay > 0)
-			schedule_timeout_interruptible(delay);
+	} else {
+		pr_warn("hwrng: no data available\n");
+		delay = 10 * HZ;
 	}
-	hwrng_fill = NULL;
-	return 0;
+	mod_delayed_work(hwrng_wq, &hwrng_fill_dwork, delay);
 }
 
 static void hwrng_manage_rngd(struct hwrng *rng)
@@ -541,14 +536,12 @@ static void hwrng_manage_rngd(struct hwrng *rng)
 	if (WARN_ON(!mutex_is_locked(&rng_mutex)))
 		return;
 
-	if (rng->quality == 0 && hwrng_fill)
-		kthread_stop(hwrng_fill);
-	if (rng->quality > 0 && !hwrng_fill) {
-		hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng");
-		if (IS_ERR(hwrng_fill)) {
-			pr_err("hwrng_fill thread creation failed\n");
-			hwrng_fill = NULL;
-		}
+	if (rng->quality == 0 && is_hwrng_wq_running) {
+		cancel_delayed_work(&hwrng_fill_dwork);
+		is_hwrng_wq_running = false;
+	} else if (rng->quality > 0 && !is_hwrng_wq_running) {
+		mod_delayed_work(hwrng_wq, &hwrng_fill_dwork, 0);
+		is_hwrng_wq_running = true;
 	}
 }
 
@@ -631,8 +624,7 @@ void hwrng_unregister(struct hwrng *rng)
 	new_rng = get_current_rng_nolock();
 	if (list_empty(&rng_list)) {
 		mutex_unlock(&rng_mutex);
-		if (hwrng_fill)
-			kthread_stop(hwrng_fill);
+		cancel_delayed_work_sync(&hwrng_fill_dwork);
 	} else
 		mutex_unlock(&rng_mutex);
 
@@ -703,17 +695,32 @@ static int __init hwrng_modinit(void)
 		return -ENOMEM;
 	}
 
+	/* ordered wq to mimic delay-polled kthread behaviour */
+	hwrng_wq = alloc_ordered_workqueue("hwrng",
+		WQ_FREEZABLE |	/* prevent work from running during suspend/resume */
+		WQ_MEM_RECLAIM	/* client drivers may need memory reclaim */
+	);
+	if (!hwrng_wq) {
+		kfree(rng_fillbuf);
+		kfree(rng_buffer);
+		return -ENOMEM;
+	}
+
 	ret = register_miscdev();
 	if (ret) {
+		destroy_workqueue(hwrng_wq);
 		kfree(rng_fillbuf);
 		kfree(rng_buffer);
 	}
 
+	INIT_DELAYED_WORK(&hwrng_fill_dwork, hwrng_fillfn);
+
 	return ret;
 }
 
 static void __exit hwrng_modexit(void)
 {
+	destroy_workqueue(hwrng_wq);
 	mutex_lock(&rng_mutex);
 	BUG_ON(current_rng);
 	kfree(rng_buffer);
-- 
2.37.2.672.g94769d06f0-goog


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v1 1/2] random: make add_hwgenerator_randomness() more flexible
  2022-08-31 17:20 [PATCH v1 1/2] random: make add_hwgenerator_randomness() more flexible Sven van Ashbrook
  2022-08-31 17:20 ` [PATCH v1 2/2] hwrng: core: fix potential suspend/resume race condition Sven van Ashbrook
@ 2022-09-01  5:05 ` Dominik Brodowski
  1 sibling, 0 replies; 6+ messages in thread
From: Dominik Brodowski @ 2022-09-01  5:05 UTC (permalink / raw)
  To: Sven van Ashbrook
  Cc: LKML, Alex Levin, Rajat Jain, Andrey Pronin, Stephen Boyd,
	Eric Biggers, Herbert Xu, Jason A. Donenfeld, Olivia Mackall,
	Petr Mladek, Sebastian Andrzej Siewior, Theodore Ts'o,
	linux-crypto


Am Wed, Aug 31, 2022 at 05:20:23PM +0000 schrieb Sven van Ashbrook:
> add_hwgenerator_randomness() currently blocks until more entropy
> is needed. But, the required delay function will depend on the
> the caller: e.g. freezable kthreads have their own freezable_XXX()
> APIs; and delayed_work might prefer to use mod_delayed_work().
> 
> To accommodate these requirements, remove the blocking wait, and
> let the function return the delay needed until more entropy is needed.

AFAICS, there's only one caller in the kernel, and its specific requirements
are currently met by the callee. So the rationale for this patch is wanting,
yet you may wish to justify this patch more explicitly as a preparation for
the second patch.

Thanks,
	Dominik

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v1 2/2] hwrng: core: fix potential suspend/resume race condition
  2022-08-31 17:20 ` [PATCH v1 2/2] hwrng: core: fix potential suspend/resume race condition Sven van Ashbrook
@ 2022-09-06 14:15   ` Sven van Ashbrook
  2022-09-07  6:29   ` Herbert Xu
  1 sibling, 0 replies; 6+ messages in thread
From: Sven van Ashbrook @ 2022-09-06 14:15 UTC (permalink / raw)
  To: LKML, Herbert Xu
  Cc: Alex Levin, Rajat Jain, Andrey Pronin, Stephen Boyd,
	Dominik Brodowski, Eric Biggers, Jason A. Donenfeld,
	Olivia Mackall, linux-crypto

Any feedback on this patch, good/bad, any suggestions?

Herbert, this patch should fix hw_random/core suspend/resume issues, without
having to freeze the kthread - which should avoid the freeze regression problems
that popped up.

See earlier kthread freeze attempt here:
https://lore.kernel.org/all/4a45b3e0-ed3a-61d3-bfc6-957c7ba631bb@maciej.szmigiero.name/T/#m2c37e2c176c4efc362116b57493749664b960f45

I was hoping you could take a look.

On Wed, Aug 31, 2022 at 1:20 PM Sven van Ashbrook <svenva@chromium.org> wrote:
>
> The hwrng fill function runs as a normal kthread. This thread
> doesn't get frozen by the PM, i.e. it will keep running during,
> or in, system suspend. It may call the client driver's
> data_present()/data_read() functions during, or in, suspend;
> which may generate errors or warnings. For example, if the
> client driver uses an i2c bus, the following warning may be
> intermittently generated:
>
>   i2c: Transfer while suspended
>
> Fix by converting the delay polled kthread into an ordered work
> queue running a single, self-rearming delayed_work. Make the
> workqueue WQ_FREEZABLE, so the PM will drain any work items
> before going into suspend. This prevents client drivers from
> being accessed during, or in, suspend.
>
> Tested on a Chromebook containing an cr50 tpm over i2c. The test
> consists of 31000 suspend/resume cycles. Occasional
> "i2c: Transfer while suspended" warnings are seen. After applying
> this patch, these warnings disappear.
>
> This patch also does not appear to cause any regressions on the
> ChromeOS test queues.
>
> Signed-off-by: Sven van Ashbrook <svenva@chromium.org>
> ---
>
>  drivers/char/hw_random/core.c | 95 +++++++++++++++++++----------------
>  1 file changed, 51 insertions(+), 44 deletions(-)
>
> diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
> index 3675122c6cce..ee85ca97d215 100644
> --- a/drivers/char/hw_random/core.c
> +++ b/drivers/char/hw_random/core.c
> @@ -17,7 +17,7 @@
>  #include <linux/hw_random.h>
>  #include <linux/random.h>
>  #include <linux/kernel.h>
> -#include <linux/kthread.h>
> +#include <linux/workqueue.h>
>  #include <linux/sched/signal.h>
>  #include <linux/miscdevice.h>
>  #include <linux/module.h>
> @@ -28,14 +28,17 @@
>
>  #define RNG_MODULE_NAME                "hw_random"
>
> -static struct hwrng *current_rng;
>  /* the current rng has been explicitly chosen by user via sysfs */
>  static int cur_rng_set_by_user;
> -static struct task_struct *hwrng_fill;
> +static struct workqueue_struct *hwrng_wq;
> +static struct delayed_work hwrng_fill_dwork;
> +static size_t entropy_credit;
> +/* Protects rng_list, current_rng, is_hwrng_wq_running */
> +static DEFINE_MUTEX(rng_mutex);
>  /* list of registered rngs */
>  static LIST_HEAD(rng_list);
> -/* Protects rng_list and current_rng */
> -static DEFINE_MUTEX(rng_mutex);
> +static struct hwrng *current_rng;
> +static bool is_hwrng_wq_running;
>  /* Protects rng read functions, data_avail, rng_buffer and rng_fillbuf */
>  static DEFINE_MUTEX(reading_mutex);
>  static int data_avail;
> @@ -488,37 +491,29 @@ static int __init register_miscdev(void)
>         return misc_register(&rng_miscdev);
>  }
>
> -static int hwrng_fillfn(void *unused)
> +static void hwrng_fillfn(struct work_struct *unused)
>  {
> -       size_t entropy, entropy_credit = 0; /* in 1/1024 of a bit */
> +       unsigned short quality;
>         unsigned long delay;
> +       struct hwrng *rng;
> +       size_t entropy; /* in 1/1024 of a bit */
>         long rc;
>
> -       while (!kthread_should_stop()) {
> -               unsigned short quality;
> -               struct hwrng *rng;
> -
> -               rng = get_current_rng();
> -               if (IS_ERR(rng) || !rng)
> -                       break;
> -               mutex_lock(&reading_mutex);
> -               rc = rng_get_data(rng, rng_fillbuf,
> -                                 rng_buffer_size(), 1);
> -               if (current_quality != rng->quality)
> -                       rng->quality = current_quality; /* obsolete */
> -               quality = rng->quality;
> -               mutex_unlock(&reading_mutex);
> -               put_rng(rng);
> -
> -               if (!quality)
> -                       break;
> +       rng = get_current_rng();
> +       if (IS_ERR(rng) || !rng)
> +               return;
> +       mutex_lock(&reading_mutex);
> +       rc = rng_get_data(rng, rng_fillbuf, rng_buffer_size(), 1);
> +       if (current_quality != rng->quality)
> +               rng->quality = current_quality; /* obsolete */
> +       quality = rng->quality;
> +       mutex_unlock(&reading_mutex);
> +       put_rng(rng);
>
> -               if (rc <= 0) {
> -                       pr_warn("hwrng: no data available\n");
> -                       msleep_interruptible(10000);
> -                       continue;
> -               }
> +       if (!quality)
> +               return;
>
> +       if (rc > 0) {
>                 /* If we cannot credit at least one bit of entropy,
>                  * keep track of the remainder for the next iteration
>                  */
> @@ -529,11 +524,11 @@ static int hwrng_fillfn(void *unused)
>                 /* Outside lock, sure, but y'know: randomness. */
>                 delay = add_hwgenerator_randomness((void *)rng_fillbuf, rc,
>                                                    entropy >> 10);
> -               if (delay > 0)
> -                       schedule_timeout_interruptible(delay);
> +       } else {
> +               pr_warn("hwrng: no data available\n");
> +               delay = 10 * HZ;
>         }
> -       hwrng_fill = NULL;
> -       return 0;
> +       mod_delayed_work(hwrng_wq, &hwrng_fill_dwork, delay);
>  }
>
>  static void hwrng_manage_rngd(struct hwrng *rng)
> @@ -541,14 +536,12 @@ static void hwrng_manage_rngd(struct hwrng *rng)
>         if (WARN_ON(!mutex_is_locked(&rng_mutex)))
>                 return;
>
> -       if (rng->quality == 0 && hwrng_fill)
> -               kthread_stop(hwrng_fill);
> -       if (rng->quality > 0 && !hwrng_fill) {
> -               hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng");
> -               if (IS_ERR(hwrng_fill)) {
> -                       pr_err("hwrng_fill thread creation failed\n");
> -                       hwrng_fill = NULL;
> -               }
> +       if (rng->quality == 0 && is_hwrng_wq_running) {
> +               cancel_delayed_work(&hwrng_fill_dwork);
> +               is_hwrng_wq_running = false;
> +       } else if (rng->quality > 0 && !is_hwrng_wq_running) {
> +               mod_delayed_work(hwrng_wq, &hwrng_fill_dwork, 0);
> +               is_hwrng_wq_running = true;
>         }
>  }
>
> @@ -631,8 +624,7 @@ void hwrng_unregister(struct hwrng *rng)
>         new_rng = get_current_rng_nolock();
>         if (list_empty(&rng_list)) {
>                 mutex_unlock(&rng_mutex);
> -               if (hwrng_fill)
> -                       kthread_stop(hwrng_fill);
> +               cancel_delayed_work_sync(&hwrng_fill_dwork);
>         } else
>                 mutex_unlock(&rng_mutex);
>
> @@ -703,17 +695,32 @@ static int __init hwrng_modinit(void)
>                 return -ENOMEM;
>         }
>
> +       /* ordered wq to mimic delay-polled kthread behaviour */
> +       hwrng_wq = alloc_ordered_workqueue("hwrng",
> +               WQ_FREEZABLE |  /* prevent work from running during suspend/resume */
> +               WQ_MEM_RECLAIM  /* client drivers may need memory reclaim */
> +       );
> +       if (!hwrng_wq) {
> +               kfree(rng_fillbuf);
> +               kfree(rng_buffer);
> +               return -ENOMEM;
> +       }
> +
>         ret = register_miscdev();
>         if (ret) {
> +               destroy_workqueue(hwrng_wq);
>                 kfree(rng_fillbuf);
>                 kfree(rng_buffer);
>         }
>
> +       INIT_DELAYED_WORK(&hwrng_fill_dwork, hwrng_fillfn);
> +
>         return ret;
>  }
>
>  static void __exit hwrng_modexit(void)
>  {
> +       destroy_workqueue(hwrng_wq);
>         mutex_lock(&rng_mutex);
>         BUG_ON(current_rng);
>         kfree(rng_buffer);
> --
> 2.37.2.672.g94769d06f0-goog
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v1 2/2] hwrng: core: fix potential suspend/resume race condition
  2022-08-31 17:20 ` [PATCH v1 2/2] hwrng: core: fix potential suspend/resume race condition Sven van Ashbrook
  2022-09-06 14:15   ` Sven van Ashbrook
@ 2022-09-07  6:29   ` Herbert Xu
  2022-09-07 14:53     ` Sven van Ashbrook
  1 sibling, 1 reply; 6+ messages in thread
From: Herbert Xu @ 2022-09-07  6:29 UTC (permalink / raw)
  To: Sven van Ashbrook
  Cc: LKML, Alex Levin, Rajat Jain, Andrey Pronin, Stephen Boyd,
	Dominik Brodowski, Eric Biggers, Jason A. Donenfeld,
	Olivia Mackall, linux-crypto

On Wed, Aug 31, 2022 at 05:20:24PM +0000, Sven van Ashbrook wrote:
> The hwrng fill function runs as a normal kthread. This thread
> doesn't get frozen by the PM, i.e. it will keep running during,
> or in, system suspend. It may call the client driver's
> data_present()/data_read() functions during, or in, suspend;
> which may generate errors or warnings. For example, if the
> client driver uses an i2c bus, the following warning may be
> intermittently generated:
> 
>   i2c: Transfer while suspended
> 
> Fix by converting the delay polled kthread into an ordered work
> queue running a single, self-rearming delayed_work. Make the
> workqueue WQ_FREEZABLE, so the PM will drain any work items
> before going into suspend. This prevents client drivers from
> being accessed during, or in, suspend.
> 
> Tested on a Chromebook containing an cr50 tpm over i2c. The test
> consists of 31000 suspend/resume cycles. Occasional
> "i2c: Transfer while suspended" warnings are seen. After applying
> this patch, these warnings disappear.
> 
> This patch also does not appear to cause any regressions on the
> ChromeOS test queues.
> 
> Signed-off-by: Sven van Ashbrook <svenva@chromium.org>

The general concept seems to be fine.

> -		if (rc <= 0) {
> -			pr_warn("hwrng: no data available\n");
> -			msleep_interruptible(10000);
> -			continue;
> -		}
> +	if (!quality)
> +		return;
>  
> +	if (rc > 0) {
>  		/* If we cannot credit at least one bit of entropy,
>  		 * keep track of the remainder for the next iteration
>  		 */

You need to refresh your patch-set against the latest tree.  This
function has changed quite a bit.


> @@ -541,14 +536,12 @@ static void hwrng_manage_rngd(struct hwrng *rng)
>  	if (WARN_ON(!mutex_is_locked(&rng_mutex)))
>  		return;
>  
> -	if (rng->quality == 0 && hwrng_fill)
> -		kthread_stop(hwrng_fill);
> -	if (rng->quality > 0 && !hwrng_fill) {
> -		hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng");
> -		if (IS_ERR(hwrng_fill)) {
> -			pr_err("hwrng_fill thread creation failed\n");
> -			hwrng_fill = NULL;
> -		}
> +	if (rng->quality == 0 && is_hwrng_wq_running) {
> +		cancel_delayed_work(&hwrng_fill_dwork);
> +		is_hwrng_wq_running = false;
> +	} else if (rng->quality > 0 && !is_hwrng_wq_running) {
> +		mod_delayed_work(hwrng_wq, &hwrng_fill_dwork, 0);
> +		is_hwrng_wq_running = true;
>  	}
>  }
>  
> @@ -631,8 +624,7 @@ void hwrng_unregister(struct hwrng *rng)
>  	new_rng = get_current_rng_nolock();
>  	if (list_empty(&rng_list)) {
>  		mutex_unlock(&rng_mutex);
> -		if (hwrng_fill)
> -			kthread_stop(hwrng_fill);
> +		cancel_delayed_work_sync(&hwrng_fill_dwork);

What if hwrng_manage_rngd races against hwrng_unregister?

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v1 2/2] hwrng: core: fix potential suspend/resume race condition
  2022-09-07  6:29   ` Herbert Xu
@ 2022-09-07 14:53     ` Sven van Ashbrook
  0 siblings, 0 replies; 6+ messages in thread
From: Sven van Ashbrook @ 2022-09-07 14:53 UTC (permalink / raw)
  To: Herbert Xu
  Cc: LKML, Alex Levin, Rajat Jain, Andrey Pronin, Stephen Boyd,
	Dominik Brodowski, Eric Biggers, Jason A. Donenfeld,
	Olivia Mackall, linux-crypto

Hi Herbert,

On Wed, Sep 7, 2022 at 2:29 AM Herbert Xu <herbert@gondor.apana.org.au> wrote:
>
> The general concept seems to be fine.

Thank you kindly for the fast review. I plan to get a v2 out in the
next few days.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2022-09-07 14:54 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-31 17:20 [PATCH v1 1/2] random: make add_hwgenerator_randomness() more flexible Sven van Ashbrook
2022-08-31 17:20 ` [PATCH v1 2/2] hwrng: core: fix potential suspend/resume race condition Sven van Ashbrook
2022-09-06 14:15   ` Sven van Ashbrook
2022-09-07  6:29   ` Herbert Xu
2022-09-07 14:53     ` Sven van Ashbrook
2022-09-01  5:05 ` [PATCH v1 1/2] random: make add_hwgenerator_randomness() more flexible Dominik Brodowski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).