All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] Ensure some device initialization before init task
@ 2026-01-22  7:34 ` Yicong Yang
  0 siblings, 0 replies; 28+ messages in thread
From: Yicong Yang @ 2026-01-22  7:34 UTC (permalink / raw)
  To: rafael, lenb, tglx, gregkh, dakr
  Cc: akpm, apatel, pjw, palmer, aou, alex, geshijian, weidong.wd,
	yang.yicong, linux-acpi, linux-kernel, linux-riscv

Fix two issues that may cause devices initialization finished
after entering init task.

Patch 1 ensure the device object scanning by acpi_scan_clear_dep_fn()
is finished before entering init task. Otherwise if some key devices
like console or root device are not ready when entering init task,
the system will panic (no available console) or enter rescure shell
(no root device). It's more possible on RISCV since these devices
are scan and created by acpi_scan_clear_dep_fn() and we've observed
this.

Patch 2 fix a theoretical issue that the console initialization is
still in process by the time we open the console. Since we call
console_on_rootfs() before async_synchronize_full(), there's no
guaranteed for the order.

Thanks Thomas for the discussion to debug these two issues [1].

[1] https://lore.kernel.org/linux-riscv/20260114063730.78009-1-yang.yicong@picoheart.com/

Yicong Yang (2):
  ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
  init: Move console_on_rootfs after async_synchronize_full

 drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
 init/main.c         |  4 ++--
 2 files changed, 18 insertions(+), 21 deletions(-)

-- 
2.34.1

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

* [PATCH 0/2] Ensure some device initialization before init task
@ 2026-01-22  7:34 ` Yicong Yang
  0 siblings, 0 replies; 28+ messages in thread
From: Yicong Yang @ 2026-01-22  7:34 UTC (permalink / raw)
  To: rafael, lenb, tglx, gregkh, dakr
  Cc: akpm, apatel, pjw, palmer, aou, alex, geshijian, weidong.wd,
	yang.yicong, linux-acpi, linux-kernel, linux-riscv

Fix two issues that may cause devices initialization finished
after entering init task.

Patch 1 ensure the device object scanning by acpi_scan_clear_dep_fn()
is finished before entering init task. Otherwise if some key devices
like console or root device are not ready when entering init task,
the system will panic (no available console) or enter rescure shell
(no root device). It's more possible on RISCV since these devices
are scan and created by acpi_scan_clear_dep_fn() and we've observed
this.

Patch 2 fix a theoretical issue that the console initialization is
still in process by the time we open the console. Since we call
console_on_rootfs() before async_synchronize_full(), there's no
guaranteed for the order.

Thanks Thomas for the discussion to debug these two issues [1].

[1] https://lore.kernel.org/linux-riscv/20260114063730.78009-1-yang.yicong@picoheart.com/

Yicong Yang (2):
  ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
  init: Move console_on_rootfs after async_synchronize_full

 drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
 init/main.c         |  4 ++--
 2 files changed, 18 insertions(+), 21 deletions(-)

-- 
2.34.1

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
  2026-01-22  7:34 ` Yicong Yang
@ 2026-01-22  7:34   ` Yicong Yang
  -1 siblings, 0 replies; 28+ messages in thread
From: Yicong Yang @ 2026-01-22  7:34 UTC (permalink / raw)
  To: rafael, lenb, tglx, gregkh, dakr
  Cc: akpm, apatel, pjw, palmer, aou, alex, geshijian, weidong.wd,
	yang.yicong, linux-acpi, linux-kernel, linux-riscv

The device object rescan in acpi_scan_clear_dep_fn is scheduled
in the system workqueue which is not guaranteed to be finished
before entering userspace. This will cause the problem that
some key devices are missed when the init task try to find them,
e.g. console devices and root devices (PCIe nvme, etc).
This issues is more possbile to happen on RISCV since these
devices using GSI interrupt may depend on APLIC and will be
scanned in acpi_scan_clear_dep_queue() after APLIC initialized.

Fix this by scheduling the acpi_scan_clear_dep_queue() using async
schedule function rather than the system workqueue. The deferred
works will be synchronized by async_synchronize_full() before
entering init task.

Update the comment as well.

Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
---
 drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
 1 file changed, 16 insertions(+), 19 deletions(-)

diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 416d87f9bd10..bf0d8ba9ba19 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -5,6 +5,7 @@
 
 #define pr_fmt(fmt) "ACPI: " fmt
 
+#include <linux/async.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
 	struct acpi_device *adev;
 };
 
-static void acpi_scan_clear_dep_fn(struct work_struct *work)
+static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
 {
-	struct acpi_scan_clear_dep_work *cdw;
-
-	cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
+	struct acpi_device *adev = to_acpi_device(dev);
 
 	acpi_scan_lock_acquire();
-	acpi_bus_attach(cdw->adev, (void *)true);
+	acpi_bus_attach(adev, (void *)true);
 	acpi_scan_lock_release();
 
-	acpi_dev_put(cdw->adev);
-	kfree(cdw);
+	acpi_dev_put(adev);
 }
 
 static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
 {
-	struct acpi_scan_clear_dep_work *cdw;
-
 	if (adev->dep_unmet)
 		return false;
 
-	cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
-	if (!cdw)
-		return false;
-
-	cdw->adev = adev;
-	INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
 	/*
-	 * Since the work function may block on the lock until the entire
-	 * initial enumeration of devices is complete, put it into the unbound
-	 * workqueue.
+	 * Async schedule the deferred acpi_scan_clear_dep_fn() since:
+	 * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
+	 *   be acquired under acpi_dep_list_lock (held here)
+	 * - the deferred work at boot stage is ensured to be finished
+	 *   before entering init task by the async_synchronize_full()
+	 *   barrier
+	 *
+	 * Use _nocall variant since it'll return on failure instead of
+	 * run the function synchronously.
 	 */
-	queue_work(system_dfl_wq, &cdw->work);
+	if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))
+		return false;
 
 	return true;
 }
-- 
2.34.1

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

* [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
@ 2026-01-22  7:34   ` Yicong Yang
  0 siblings, 0 replies; 28+ messages in thread
From: Yicong Yang @ 2026-01-22  7:34 UTC (permalink / raw)
  To: rafael, lenb, tglx, gregkh, dakr
  Cc: akpm, apatel, pjw, palmer, aou, alex, geshijian, weidong.wd,
	yang.yicong, linux-acpi, linux-kernel, linux-riscv

The device object rescan in acpi_scan_clear_dep_fn is scheduled
in the system workqueue which is not guaranteed to be finished
before entering userspace. This will cause the problem that
some key devices are missed when the init task try to find them,
e.g. console devices and root devices (PCIe nvme, etc).
This issues is more possbile to happen on RISCV since these
devices using GSI interrupt may depend on APLIC and will be
scanned in acpi_scan_clear_dep_queue() after APLIC initialized.

Fix this by scheduling the acpi_scan_clear_dep_queue() using async
schedule function rather than the system workqueue. The deferred
works will be synchronized by async_synchronize_full() before
entering init task.

Update the comment as well.

Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
---
 drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
 1 file changed, 16 insertions(+), 19 deletions(-)

diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 416d87f9bd10..bf0d8ba9ba19 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -5,6 +5,7 @@
 
 #define pr_fmt(fmt) "ACPI: " fmt
 
+#include <linux/async.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
 	struct acpi_device *adev;
 };
 
-static void acpi_scan_clear_dep_fn(struct work_struct *work)
+static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
 {
-	struct acpi_scan_clear_dep_work *cdw;
-
-	cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
+	struct acpi_device *adev = to_acpi_device(dev);
 
 	acpi_scan_lock_acquire();
-	acpi_bus_attach(cdw->adev, (void *)true);
+	acpi_bus_attach(adev, (void *)true);
 	acpi_scan_lock_release();
 
-	acpi_dev_put(cdw->adev);
-	kfree(cdw);
+	acpi_dev_put(adev);
 }
 
 static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
 {
-	struct acpi_scan_clear_dep_work *cdw;
-
 	if (adev->dep_unmet)
 		return false;
 
-	cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
-	if (!cdw)
-		return false;
-
-	cdw->adev = adev;
-	INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
 	/*
-	 * Since the work function may block on the lock until the entire
-	 * initial enumeration of devices is complete, put it into the unbound
-	 * workqueue.
+	 * Async schedule the deferred acpi_scan_clear_dep_fn() since:
+	 * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
+	 *   be acquired under acpi_dep_list_lock (held here)
+	 * - the deferred work at boot stage is ensured to be finished
+	 *   before entering init task by the async_synchronize_full()
+	 *   barrier
+	 *
+	 * Use _nocall variant since it'll return on failure instead of
+	 * run the function synchronously.
 	 */
-	queue_work(system_dfl_wq, &cdw->work);
+	if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))
+		return false;
 
 	return true;
 }
-- 
2.34.1

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* [PATCH 2/2] init: Move console_on_rootfs after async_synchronize_full
  2026-01-22  7:34 ` Yicong Yang
@ 2026-01-22  7:34   ` Yicong Yang
  -1 siblings, 0 replies; 28+ messages in thread
From: Yicong Yang @ 2026-01-22  7:34 UTC (permalink / raw)
  To: rafael, lenb, tglx, gregkh, dakr
  Cc: akpm, apatel, pjw, palmer, aou, alex, geshijian, weidong.wd,
	yang.yicong, linux-acpi, linux-kernel, linux-riscv

Currently the console_on_rootfs() is called before
async_synchronize_full(), the console initialization
could be still in process in theory due to async
probe, etc. Make it after the async_synchronize_full()
to make sure the initialization work is done.

Log the error code as well if we failed to open the console.

Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
---
 init/main.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/init/main.c b/init/main.c
index b84818ad9685..c37ba5f89b96 100644
--- a/init/main.c
+++ b/init/main.c
@@ -1578,6 +1578,7 @@ static int __ref kernel_init(void *unused)
 	kernel_init_freeable();
 	/* need to finish all async __init code before freeing the memory */
 	async_synchronize_full();
+	console_on_rootfs();
 
 	system_state = SYSTEM_FREEING_INITMEM;
 	kprobe_free_init_mem();
@@ -1647,7 +1648,7 @@ void __init console_on_rootfs(void)
 	struct file *file = filp_open("/dev/console", O_RDWR, 0);
 
 	if (IS_ERR(file)) {
-		pr_err("Warning: unable to open an initial console.\n");
+		pr_err("Warning: unable to open an initial console, err = %ld\n", PTR_ERR(file));
 		return;
 	}
 	init_dup(file);
@@ -1690,7 +1691,6 @@ static noinline void __init kernel_init_freeable(void)
 	kunit_run_all_tests();
 
 	wait_for_initramfs();
-	console_on_rootfs();
 
 	/*
 	 * check if there is an early userspace init.  If yes, let it do all
-- 
2.34.1

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

* [PATCH 2/2] init: Move console_on_rootfs after async_synchronize_full
@ 2026-01-22  7:34   ` Yicong Yang
  0 siblings, 0 replies; 28+ messages in thread
From: Yicong Yang @ 2026-01-22  7:34 UTC (permalink / raw)
  To: rafael, lenb, tglx, gregkh, dakr
  Cc: akpm, apatel, pjw, palmer, aou, alex, geshijian, weidong.wd,
	yang.yicong, linux-acpi, linux-kernel, linux-riscv

Currently the console_on_rootfs() is called before
async_synchronize_full(), the console initialization
could be still in process in theory due to async
probe, etc. Make it after the async_synchronize_full()
to make sure the initialization work is done.

Log the error code as well if we failed to open the console.

Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
---
 init/main.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/init/main.c b/init/main.c
index b84818ad9685..c37ba5f89b96 100644
--- a/init/main.c
+++ b/init/main.c
@@ -1578,6 +1578,7 @@ static int __ref kernel_init(void *unused)
 	kernel_init_freeable();
 	/* need to finish all async __init code before freeing the memory */
 	async_synchronize_full();
+	console_on_rootfs();
 
 	system_state = SYSTEM_FREEING_INITMEM;
 	kprobe_free_init_mem();
@@ -1647,7 +1648,7 @@ void __init console_on_rootfs(void)
 	struct file *file = filp_open("/dev/console", O_RDWR, 0);
 
 	if (IS_ERR(file)) {
-		pr_err("Warning: unable to open an initial console.\n");
+		pr_err("Warning: unable to open an initial console, err = %ld\n", PTR_ERR(file));
 		return;
 	}
 	init_dup(file);
@@ -1690,7 +1691,6 @@ static noinline void __init kernel_init_freeable(void)
 	kunit_run_all_tests();
 
 	wait_for_initramfs();
-	console_on_rootfs();
 
 	/*
 	 * check if there is an early userspace init.  If yes, let it do all
-- 
2.34.1

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* Re: [PATCH 2/2] init: Move console_on_rootfs after async_synchronize_full
  2026-01-22  7:34   ` Yicong Yang
@ 2026-01-22 10:27     ` Greg KH
  -1 siblings, 0 replies; 28+ messages in thread
From: Greg KH @ 2026-01-22 10:27 UTC (permalink / raw)
  To: Yicong Yang
  Cc: rafael, lenb, tglx, dakr, akpm, apatel, pjw, palmer, aou, alex,
	geshijian, weidong.wd, linux-acpi, linux-kernel, linux-riscv

On Thu, Jan 22, 2026 at 03:34:46PM +0800, Yicong Yang wrote:
> Currently the console_on_rootfs() is called before
> async_synchronize_full(), the console initialization
> could be still in process in theory due to async
> probe, etc. Make it after the async_synchronize_full()
> to make sure the initialization work is done.

Please wrap at 72 columns.

> 
> Log the error code as well if we failed to open the console.
> 
> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
> ---
>  init/main.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/init/main.c b/init/main.c
> index b84818ad9685..c37ba5f89b96 100644
> --- a/init/main.c
> +++ b/init/main.c
> @@ -1578,6 +1578,7 @@ static int __ref kernel_init(void *unused)
>  	kernel_init_freeable();
>  	/* need to finish all async __init code before freeing the memory */
>  	async_synchronize_full();
> +	console_on_rootfs();

Are you sure this is ok?  Messing around with init levels and order is
_VERY_ tricky.

Your console should NOT be on an async probe path, if you really need
it, then do not do that at all.  Make it sync, and then it should be ok.

>  
>  	system_state = SYSTEM_FREEING_INITMEM;
>  	kprobe_free_init_mem();
> @@ -1647,7 +1648,7 @@ void __init console_on_rootfs(void)
>  	struct file *file = filp_open("/dev/console", O_RDWR, 0);
>  
>  	if (IS_ERR(file)) {
> -		pr_err("Warning: unable to open an initial console.\n");
> +		pr_err("Warning: unable to open an initial console, err = %ld\n", PTR_ERR(file));

Why is this changed?

>  		return;
>  	}
>  	init_dup(file);
> @@ -1690,7 +1691,6 @@ static noinline void __init kernel_init_freeable(void)
>  	kunit_run_all_tests();
>  
>  	wait_for_initramfs();
> -	console_on_rootfs();

You just delayed the console output for many (i.e. most) systems out
there, are you sure that is acceptable to them?

thanks,

greg k-h

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

* Re: [PATCH 2/2] init: Move console_on_rootfs after async_synchronize_full
@ 2026-01-22 10:27     ` Greg KH
  0 siblings, 0 replies; 28+ messages in thread
From: Greg KH @ 2026-01-22 10:27 UTC (permalink / raw)
  To: Yicong Yang
  Cc: rafael, lenb, tglx, dakr, akpm, apatel, pjw, palmer, aou, alex,
	geshijian, weidong.wd, linux-acpi, linux-kernel, linux-riscv

On Thu, Jan 22, 2026 at 03:34:46PM +0800, Yicong Yang wrote:
> Currently the console_on_rootfs() is called before
> async_synchronize_full(), the console initialization
> could be still in process in theory due to async
> probe, etc. Make it after the async_synchronize_full()
> to make sure the initialization work is done.

Please wrap at 72 columns.

> 
> Log the error code as well if we failed to open the console.
> 
> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
> ---
>  init/main.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/init/main.c b/init/main.c
> index b84818ad9685..c37ba5f89b96 100644
> --- a/init/main.c
> +++ b/init/main.c
> @@ -1578,6 +1578,7 @@ static int __ref kernel_init(void *unused)
>  	kernel_init_freeable();
>  	/* need to finish all async __init code before freeing the memory */
>  	async_synchronize_full();
> +	console_on_rootfs();

Are you sure this is ok?  Messing around with init levels and order is
_VERY_ tricky.

Your console should NOT be on an async probe path, if you really need
it, then do not do that at all.  Make it sync, and then it should be ok.

>  
>  	system_state = SYSTEM_FREEING_INITMEM;
>  	kprobe_free_init_mem();
> @@ -1647,7 +1648,7 @@ void __init console_on_rootfs(void)
>  	struct file *file = filp_open("/dev/console", O_RDWR, 0);
>  
>  	if (IS_ERR(file)) {
> -		pr_err("Warning: unable to open an initial console.\n");
> +		pr_err("Warning: unable to open an initial console, err = %ld\n", PTR_ERR(file));

Why is this changed?

>  		return;
>  	}
>  	init_dup(file);
> @@ -1690,7 +1691,6 @@ static noinline void __init kernel_init_freeable(void)
>  	kunit_run_all_tests();
>  
>  	wait_for_initramfs();
> -	console_on_rootfs();

You just delayed the console output for many (i.e. most) systems out
there, are you sure that is acceptable to them?

thanks,

greg k-h

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* Re: [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
  2026-01-22  7:34   ` Yicong Yang
@ 2026-01-22 10:29     ` Greg KH
  -1 siblings, 0 replies; 28+ messages in thread
From: Greg KH @ 2026-01-22 10:29 UTC (permalink / raw)
  To: Yicong Yang
  Cc: rafael, lenb, tglx, dakr, akpm, apatel, pjw, palmer, aou, alex,
	geshijian, weidong.wd, linux-acpi, linux-kernel, linux-riscv

On Thu, Jan 22, 2026 at 03:34:45PM +0800, Yicong Yang wrote:
> The device object rescan in acpi_scan_clear_dep_fn is scheduled
> in the system workqueue which is not guaranteed to be finished
> before entering userspace. This will cause the problem that
> some key devices are missed when the init task try to find them,
> e.g. console devices and root devices (PCIe nvme, etc).
> This issues is more possbile to happen on RISCV since these
> devices using GSI interrupt may depend on APLIC and will be
> scanned in acpi_scan_clear_dep_queue() after APLIC initialized.
> 
> Fix this by scheduling the acpi_scan_clear_dep_queue() using async
> schedule function rather than the system workqueue. The deferred
> works will be synchronized by async_synchronize_full() before
> entering init task.
> 
> Update the comment as well.
> 
> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
> ---
>  drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
>  1 file changed, 16 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> index 416d87f9bd10..bf0d8ba9ba19 100644
> --- a/drivers/acpi/scan.c
> +++ b/drivers/acpi/scan.c
> @@ -5,6 +5,7 @@
>  
>  #define pr_fmt(fmt) "ACPI: " fmt
>  
> +#include <linux/async.h>
>  #include <linux/module.h>
>  #include <linux/init.h>
>  #include <linux/slab.h>
> @@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
>  	struct acpi_device *adev;
>  };
>  
> -static void acpi_scan_clear_dep_fn(struct work_struct *work)
> +static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
>  {
> -	struct acpi_scan_clear_dep_work *cdw;
> -
> -	cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
> +	struct acpi_device *adev = to_acpi_device(dev);
>  
>  	acpi_scan_lock_acquire();
> -	acpi_bus_attach(cdw->adev, (void *)true);
> +	acpi_bus_attach(adev, (void *)true);
>  	acpi_scan_lock_release();
>  
> -	acpi_dev_put(cdw->adev);
> -	kfree(cdw);
> +	acpi_dev_put(adev);
>  }
>  
>  static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
>  {
> -	struct acpi_scan_clear_dep_work *cdw;
> -
>  	if (adev->dep_unmet)
>  		return false;
>  
> -	cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
> -	if (!cdw)
> -		return false;
> -
> -	cdw->adev = adev;
> -	INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
>  	/*
> -	 * Since the work function may block on the lock until the entire
> -	 * initial enumeration of devices is complete, put it into the unbound
> -	 * workqueue.
> +	 * Async schedule the deferred acpi_scan_clear_dep_fn() since:
> +	 * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
> +	 *   be acquired under acpi_dep_list_lock (held here)
> +	 * - the deferred work at boot stage is ensured to be finished
> +	 *   before entering init task by the async_synchronize_full()
> +	 *   barrier
> +	 *
> +	 * Use _nocall variant since it'll return on failure instead of
> +	 * run the function synchronously.
>  	 */
> -	queue_work(system_dfl_wq, &cdw->work);
> +	if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))
> +		return false;

This really feels wrong to me, you are taking a code path that has been
working for quite a while and changing it.  Perhaps your system ACPI
tables are the thing that is incorrect here?

What exactly is the problem that you are seeing?  Why not start with
that and then we can work out how to solve that issue?

thanks,

greg k-h

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

* Re: [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
@ 2026-01-22 10:29     ` Greg KH
  0 siblings, 0 replies; 28+ messages in thread
From: Greg KH @ 2026-01-22 10:29 UTC (permalink / raw)
  To: Yicong Yang
  Cc: rafael, lenb, tglx, dakr, akpm, apatel, pjw, palmer, aou, alex,
	geshijian, weidong.wd, linux-acpi, linux-kernel, linux-riscv

On Thu, Jan 22, 2026 at 03:34:45PM +0800, Yicong Yang wrote:
> The device object rescan in acpi_scan_clear_dep_fn is scheduled
> in the system workqueue which is not guaranteed to be finished
> before entering userspace. This will cause the problem that
> some key devices are missed when the init task try to find them,
> e.g. console devices and root devices (PCIe nvme, etc).
> This issues is more possbile to happen on RISCV since these
> devices using GSI interrupt may depend on APLIC and will be
> scanned in acpi_scan_clear_dep_queue() after APLIC initialized.
> 
> Fix this by scheduling the acpi_scan_clear_dep_queue() using async
> schedule function rather than the system workqueue. The deferred
> works will be synchronized by async_synchronize_full() before
> entering init task.
> 
> Update the comment as well.
> 
> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
> ---
>  drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
>  1 file changed, 16 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> index 416d87f9bd10..bf0d8ba9ba19 100644
> --- a/drivers/acpi/scan.c
> +++ b/drivers/acpi/scan.c
> @@ -5,6 +5,7 @@
>  
>  #define pr_fmt(fmt) "ACPI: " fmt
>  
> +#include <linux/async.h>
>  #include <linux/module.h>
>  #include <linux/init.h>
>  #include <linux/slab.h>
> @@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
>  	struct acpi_device *adev;
>  };
>  
> -static void acpi_scan_clear_dep_fn(struct work_struct *work)
> +static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
>  {
> -	struct acpi_scan_clear_dep_work *cdw;
> -
> -	cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
> +	struct acpi_device *adev = to_acpi_device(dev);
>  
>  	acpi_scan_lock_acquire();
> -	acpi_bus_attach(cdw->adev, (void *)true);
> +	acpi_bus_attach(adev, (void *)true);
>  	acpi_scan_lock_release();
>  
> -	acpi_dev_put(cdw->adev);
> -	kfree(cdw);
> +	acpi_dev_put(adev);
>  }
>  
>  static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
>  {
> -	struct acpi_scan_clear_dep_work *cdw;
> -
>  	if (adev->dep_unmet)
>  		return false;
>  
> -	cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
> -	if (!cdw)
> -		return false;
> -
> -	cdw->adev = adev;
> -	INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
>  	/*
> -	 * Since the work function may block on the lock until the entire
> -	 * initial enumeration of devices is complete, put it into the unbound
> -	 * workqueue.
> +	 * Async schedule the deferred acpi_scan_clear_dep_fn() since:
> +	 * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
> +	 *   be acquired under acpi_dep_list_lock (held here)
> +	 * - the deferred work at boot stage is ensured to be finished
> +	 *   before entering init task by the async_synchronize_full()
> +	 *   barrier
> +	 *
> +	 * Use _nocall variant since it'll return on failure instead of
> +	 * run the function synchronously.
>  	 */
> -	queue_work(system_dfl_wq, &cdw->work);
> +	if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))
> +		return false;

This really feels wrong to me, you are taking a code path that has been
working for quite a while and changing it.  Perhaps your system ACPI
tables are the thing that is incorrect here?

What exactly is the problem that you are seeing?  Why not start with
that and then we can work out how to solve that issue?

thanks,

greg k-h

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* Re: [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
  2026-01-22  7:34   ` Yicong Yang
@ 2026-01-22 11:19     ` Rafael J. Wysocki
  -1 siblings, 0 replies; 28+ messages in thread
From: Rafael J. Wysocki @ 2026-01-22 11:19 UTC (permalink / raw)
  To: Yicong Yang
  Cc: rafael, lenb, tglx, gregkh, dakr, akpm, apatel, pjw, palmer, aou,
	alex, geshijian, weidong.wd, linux-acpi, linux-kernel,
	linux-riscv

On Thu, Jan 22, 2026 at 8:35 AM Yicong Yang <yang.yicong@picoheart.com> wrote:
>
> The device object rescan in acpi_scan_clear_dep_fn is scheduled
> in the system workqueue which is not guaranteed to be finished
> before entering userspace. This will cause the problem that
> some key devices are missed when the init task try to find them,
> e.g. console devices and root devices (PCIe nvme, etc).
> This issues is more possbile to happen on RISCV since these
> devices using GSI interrupt may depend on APLIC and will be
> scanned in acpi_scan_clear_dep_queue() after APLIC initialized.
>
> Fix this by scheduling the acpi_scan_clear_dep_queue() using async
> schedule function rather than the system workqueue. The deferred
> works will be synchronized by async_synchronize_full() before
> entering init task.
>
> Update the comment as well.
>
> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
> ---
>  drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
>  1 file changed, 16 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> index 416d87f9bd10..bf0d8ba9ba19 100644
> --- a/drivers/acpi/scan.c
> +++ b/drivers/acpi/scan.c
> @@ -5,6 +5,7 @@
>
>  #define pr_fmt(fmt) "ACPI: " fmt
>
> +#include <linux/async.h>
>  #include <linux/module.h>
>  #include <linux/init.h>
>  #include <linux/slab.h>
> @@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
>         struct acpi_device *adev;
>  };
>
> -static void acpi_scan_clear_dep_fn(struct work_struct *work)
> +static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
>  {
> -       struct acpi_scan_clear_dep_work *cdw;
> -
> -       cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
> +       struct acpi_device *adev = to_acpi_device(dev);
>
>         acpi_scan_lock_acquire();
> -       acpi_bus_attach(cdw->adev, (void *)true);
> +       acpi_bus_attach(adev, (void *)true);
>         acpi_scan_lock_release();
>
> -       acpi_dev_put(cdw->adev);
> -       kfree(cdw);
> +       acpi_dev_put(adev);
>  }
>
>  static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
>  {
> -       struct acpi_scan_clear_dep_work *cdw;
> -
>         if (adev->dep_unmet)
>                 return false;
>
> -       cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
> -       if (!cdw)
> -               return false;
> -
> -       cdw->adev = adev;
> -       INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
>         /*
> -        * Since the work function may block on the lock until the entire
> -        * initial enumeration of devices is complete, put it into the unbound
> -        * workqueue.
> +        * Async schedule the deferred acpi_scan_clear_dep_fn() since:
> +        * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
> +        *   be acquired under acpi_dep_list_lock (held here)
> +        * - the deferred work at boot stage is ensured to be finished
> +        *   before entering init task by the async_synchronize_full()
> +        *   barrier
> +        *
> +        * Use _nocall variant since it'll return on failure instead of
> +        * run the function synchronously.
>          */
> -       queue_work(system_dfl_wq, &cdw->work);
> +       if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))

If the problem is that system_dfl_wq is too slow, why don't you just
try a dedicated workqueue for this?

There's no need to modify all of this code.

> +               return false;
>
>         return true;
>  }
> --

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

* Re: [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
@ 2026-01-22 11:19     ` Rafael J. Wysocki
  0 siblings, 0 replies; 28+ messages in thread
From: Rafael J. Wysocki @ 2026-01-22 11:19 UTC (permalink / raw)
  To: Yicong Yang
  Cc: rafael, lenb, tglx, gregkh, dakr, akpm, apatel, pjw, palmer, aou,
	alex, geshijian, weidong.wd, linux-acpi, linux-kernel,
	linux-riscv

On Thu, Jan 22, 2026 at 8:35 AM Yicong Yang <yang.yicong@picoheart.com> wrote:
>
> The device object rescan in acpi_scan_clear_dep_fn is scheduled
> in the system workqueue which is not guaranteed to be finished
> before entering userspace. This will cause the problem that
> some key devices are missed when the init task try to find them,
> e.g. console devices and root devices (PCIe nvme, etc).
> This issues is more possbile to happen on RISCV since these
> devices using GSI interrupt may depend on APLIC and will be
> scanned in acpi_scan_clear_dep_queue() after APLIC initialized.
>
> Fix this by scheduling the acpi_scan_clear_dep_queue() using async
> schedule function rather than the system workqueue. The deferred
> works will be synchronized by async_synchronize_full() before
> entering init task.
>
> Update the comment as well.
>
> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
> ---
>  drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
>  1 file changed, 16 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> index 416d87f9bd10..bf0d8ba9ba19 100644
> --- a/drivers/acpi/scan.c
> +++ b/drivers/acpi/scan.c
> @@ -5,6 +5,7 @@
>
>  #define pr_fmt(fmt) "ACPI: " fmt
>
> +#include <linux/async.h>
>  #include <linux/module.h>
>  #include <linux/init.h>
>  #include <linux/slab.h>
> @@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
>         struct acpi_device *adev;
>  };
>
> -static void acpi_scan_clear_dep_fn(struct work_struct *work)
> +static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
>  {
> -       struct acpi_scan_clear_dep_work *cdw;
> -
> -       cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
> +       struct acpi_device *adev = to_acpi_device(dev);
>
>         acpi_scan_lock_acquire();
> -       acpi_bus_attach(cdw->adev, (void *)true);
> +       acpi_bus_attach(adev, (void *)true);
>         acpi_scan_lock_release();
>
> -       acpi_dev_put(cdw->adev);
> -       kfree(cdw);
> +       acpi_dev_put(adev);
>  }
>
>  static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
>  {
> -       struct acpi_scan_clear_dep_work *cdw;
> -
>         if (adev->dep_unmet)
>                 return false;
>
> -       cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
> -       if (!cdw)
> -               return false;
> -
> -       cdw->adev = adev;
> -       INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
>         /*
> -        * Since the work function may block on the lock until the entire
> -        * initial enumeration of devices is complete, put it into the unbound
> -        * workqueue.
> +        * Async schedule the deferred acpi_scan_clear_dep_fn() since:
> +        * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
> +        *   be acquired under acpi_dep_list_lock (held here)
> +        * - the deferred work at boot stage is ensured to be finished
> +        *   before entering init task by the async_synchronize_full()
> +        *   barrier
> +        *
> +        * Use _nocall variant since it'll return on failure instead of
> +        * run the function synchronously.
>          */
> -       queue_work(system_dfl_wq, &cdw->work);
> +       if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))

If the problem is that system_dfl_wq is too slow, why don't you just
try a dedicated workqueue for this?

There's no need to modify all of this code.

> +               return false;
>
>         return true;
>  }
> --

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* Re: [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
  2026-01-22 10:29     ` Greg KH
@ 2026-01-22 12:43       ` Yicong Yang
  -1 siblings, 0 replies; 28+ messages in thread
From: Yicong Yang @ 2026-01-22 12:43 UTC (permalink / raw)
  To: Greg KH
  Cc: yang.yicong, rafael, lenb, tglx, dakr, akpm, apatel, pjw, palmer,
	aou, alex, geshijian, weidong.wd, linux-acpi, linux-kernel,
	linux-riscv

On 1/22/26 6:29 PM, Greg KH wrote:
> On Thu, Jan 22, 2026 at 03:34:45PM +0800, Yicong Yang wrote:
>> The device object rescan in acpi_scan_clear_dep_fn is scheduled
>> in the system workqueue which is not guaranteed to be finished
>> before entering userspace. This will cause the problem that
>> some key devices are missed when the init task try to find them,
>> e.g. console devices and root devices (PCIe nvme, etc).
>> This issues is more possbile to happen on RISCV since these
>> devices using GSI interrupt may depend on APLIC and will be
>> scanned in acpi_scan_clear_dep_queue() after APLIC initialized.
>>
>> Fix this by scheduling the acpi_scan_clear_dep_queue() using async
>> schedule function rather than the system workqueue. The deferred
>> works will be synchronized by async_synchronize_full() before
>> entering init task.
>>
>> Update the comment as well.
>>
>> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
>> ---
>>  drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
>>  1 file changed, 16 insertions(+), 19 deletions(-)
>>
>> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
>> index 416d87f9bd10..bf0d8ba9ba19 100644
>> --- a/drivers/acpi/scan.c
>> +++ b/drivers/acpi/scan.c
>> @@ -5,6 +5,7 @@
>>  
>>  #define pr_fmt(fmt) "ACPI: " fmt
>>  
>> +#include <linux/async.h>
>>  #include <linux/module.h>
>>  #include <linux/init.h>
>>  #include <linux/slab.h>
>> @@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
>>  	struct acpi_device *adev;
>>  };
>>  
>> -static void acpi_scan_clear_dep_fn(struct work_struct *work)
>> +static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
>>  {
>> -	struct acpi_scan_clear_dep_work *cdw;
>> -
>> -	cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
>> +	struct acpi_device *adev = to_acpi_device(dev);
>>  
>>  	acpi_scan_lock_acquire();
>> -	acpi_bus_attach(cdw->adev, (void *)true);
>> +	acpi_bus_attach(adev, (void *)true);
>>  	acpi_scan_lock_release();
>>  
>> -	acpi_dev_put(cdw->adev);
>> -	kfree(cdw);
>> +	acpi_dev_put(adev);
>>  }
>>  
>>  static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
>>  {
>> -	struct acpi_scan_clear_dep_work *cdw;
>> -
>>  	if (adev->dep_unmet)
>>  		return false;
>>  
>> -	cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
>> -	if (!cdw)
>> -		return false;
>> -
>> -	cdw->adev = adev;
>> -	INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
>>  	/*
>> -	 * Since the work function may block on the lock until the entire
>> -	 * initial enumeration of devices is complete, put it into the unbound
>> -	 * workqueue.
>> +	 * Async schedule the deferred acpi_scan_clear_dep_fn() since:
>> +	 * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
>> +	 *   be acquired under acpi_dep_list_lock (held here)
>> +	 * - the deferred work at boot stage is ensured to be finished
>> +	 *   before entering init task by the async_synchronize_full()
>> +	 *   barrier
>> +	 *
>> +	 * Use _nocall variant since it'll return on failure instead of
>> +	 * run the function synchronously.
>>  	 */
>> -	queue_work(system_dfl_wq, &cdw->work);
>> +	if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))
>> +		return false;
> 
> This really feels wrong to me, you are taking a code path that has been
> working for quite a while and changing it.  Perhaps your system ACPI
> tables are the thing that is incorrect here?
> 
> What exactly is the problem that you are seeing?  Why not start with
> that and then we can work out how to solve that issue?
> 

two issues here we met (as briefly mentioned in the commit and cover letter):
1. kernel panic due to userspace init cannot have an opened console. the
   console device scanning is queued in the system_dfl_wq in above code
   and not finished by the time userspace init process running, thus by
   the time userspace init running, no console is created
2. entering rescue shell due to no root devices (PCIe nvme in our case)
   found. same reason as above, the PCIe host bridge scanning is queued
   in above and finished after init process running.

The reason why these devices are created here is because they both depend
on riscv-aplic irqchip to serve their interrupts (console's wired
interrupt and PCI's INTx interrupts) and in order to keep the dependency
these devices are scanned and created after riscv-aplic initialized. The
riscv-aplic is initialized in device_initcall and invoke above codes for
the scan/creation of these devices, it's close to the time running
userspace init process. Since system_dfl_wq is used here and no synchronized
mechanism, the issues will happen if userspace init runs before these devices
are ready.

Previous solution [1] is to advance the initialization of riscv-aplic
earlier but the order still cannot be guaranteed conceptually.
With async_schedule_dev_nocal() the work queued is finished
before entering userspace init since we'll wait for completion at
async_synchronize_full() before executing userspace init process.

To solve the issue I think we should make these devices ready before
entering userspace and async schedule is one way to make it. It's also
using an unbound workqueue but have additional synchronization. Any
corrections or suggestions?

[1] https://lore.kernel.org/linux-riscv/20260114063730.78009-1-yang.yicong@picoheart.com/

Thanks.

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

* Re: [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
@ 2026-01-22 12:43       ` Yicong Yang
  0 siblings, 0 replies; 28+ messages in thread
From: Yicong Yang @ 2026-01-22 12:43 UTC (permalink / raw)
  To: Greg KH
  Cc: yang.yicong, rafael, lenb, tglx, dakr, akpm, apatel, pjw, palmer,
	aou, alex, geshijian, weidong.wd, linux-acpi, linux-kernel,
	linux-riscv

On 1/22/26 6:29 PM, Greg KH wrote:
> On Thu, Jan 22, 2026 at 03:34:45PM +0800, Yicong Yang wrote:
>> The device object rescan in acpi_scan_clear_dep_fn is scheduled
>> in the system workqueue which is not guaranteed to be finished
>> before entering userspace. This will cause the problem that
>> some key devices are missed when the init task try to find them,
>> e.g. console devices and root devices (PCIe nvme, etc).
>> This issues is more possbile to happen on RISCV since these
>> devices using GSI interrupt may depend on APLIC and will be
>> scanned in acpi_scan_clear_dep_queue() after APLIC initialized.
>>
>> Fix this by scheduling the acpi_scan_clear_dep_queue() using async
>> schedule function rather than the system workqueue. The deferred
>> works will be synchronized by async_synchronize_full() before
>> entering init task.
>>
>> Update the comment as well.
>>
>> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
>> ---
>>  drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
>>  1 file changed, 16 insertions(+), 19 deletions(-)
>>
>> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
>> index 416d87f9bd10..bf0d8ba9ba19 100644
>> --- a/drivers/acpi/scan.c
>> +++ b/drivers/acpi/scan.c
>> @@ -5,6 +5,7 @@
>>  
>>  #define pr_fmt(fmt) "ACPI: " fmt
>>  
>> +#include <linux/async.h>
>>  #include <linux/module.h>
>>  #include <linux/init.h>
>>  #include <linux/slab.h>
>> @@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
>>  	struct acpi_device *adev;
>>  };
>>  
>> -static void acpi_scan_clear_dep_fn(struct work_struct *work)
>> +static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
>>  {
>> -	struct acpi_scan_clear_dep_work *cdw;
>> -
>> -	cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
>> +	struct acpi_device *adev = to_acpi_device(dev);
>>  
>>  	acpi_scan_lock_acquire();
>> -	acpi_bus_attach(cdw->adev, (void *)true);
>> +	acpi_bus_attach(adev, (void *)true);
>>  	acpi_scan_lock_release();
>>  
>> -	acpi_dev_put(cdw->adev);
>> -	kfree(cdw);
>> +	acpi_dev_put(adev);
>>  }
>>  
>>  static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
>>  {
>> -	struct acpi_scan_clear_dep_work *cdw;
>> -
>>  	if (adev->dep_unmet)
>>  		return false;
>>  
>> -	cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
>> -	if (!cdw)
>> -		return false;
>> -
>> -	cdw->adev = adev;
>> -	INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
>>  	/*
>> -	 * Since the work function may block on the lock until the entire
>> -	 * initial enumeration of devices is complete, put it into the unbound
>> -	 * workqueue.
>> +	 * Async schedule the deferred acpi_scan_clear_dep_fn() since:
>> +	 * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
>> +	 *   be acquired under acpi_dep_list_lock (held here)
>> +	 * - the deferred work at boot stage is ensured to be finished
>> +	 *   before entering init task by the async_synchronize_full()
>> +	 *   barrier
>> +	 *
>> +	 * Use _nocall variant since it'll return on failure instead of
>> +	 * run the function synchronously.
>>  	 */
>> -	queue_work(system_dfl_wq, &cdw->work);
>> +	if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))
>> +		return false;
> 
> This really feels wrong to me, you are taking a code path that has been
> working for quite a while and changing it.  Perhaps your system ACPI
> tables are the thing that is incorrect here?
> 
> What exactly is the problem that you are seeing?  Why not start with
> that and then we can work out how to solve that issue?
> 

two issues here we met (as briefly mentioned in the commit and cover letter):
1. kernel panic due to userspace init cannot have an opened console. the
   console device scanning is queued in the system_dfl_wq in above code
   and not finished by the time userspace init process running, thus by
   the time userspace init running, no console is created
2. entering rescue shell due to no root devices (PCIe nvme in our case)
   found. same reason as above, the PCIe host bridge scanning is queued
   in above and finished after init process running.

The reason why these devices are created here is because they both depend
on riscv-aplic irqchip to serve their interrupts (console's wired
interrupt and PCI's INTx interrupts) and in order to keep the dependency
these devices are scanned and created after riscv-aplic initialized. The
riscv-aplic is initialized in device_initcall and invoke above codes for
the scan/creation of these devices, it's close to the time running
userspace init process. Since system_dfl_wq is used here and no synchronized
mechanism, the issues will happen if userspace init runs before these devices
are ready.

Previous solution [1] is to advance the initialization of riscv-aplic
earlier but the order still cannot be guaranteed conceptually.
With async_schedule_dev_nocal() the work queued is finished
before entering userspace init since we'll wait for completion at
async_synchronize_full() before executing userspace init process.

To solve the issue I think we should make these devices ready before
entering userspace and async schedule is one way to make it. It's also
using an unbound workqueue but have additional synchronization. Any
corrections or suggestions?

[1] https://lore.kernel.org/linux-riscv/20260114063730.78009-1-yang.yicong@picoheart.com/

Thanks.

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* Re: [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
  2026-01-22 11:19     ` Rafael J. Wysocki
@ 2026-01-22 12:50       ` Yicong Yang
  -1 siblings, 0 replies; 28+ messages in thread
From: Yicong Yang @ 2026-01-22 12:50 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: yang.yicong, lenb, tglx, gregkh, dakr, akpm, apatel, pjw, palmer,
	aou, alex, geshijian, weidong.wd, linux-acpi, linux-kernel,
	linux-riscv

On 1/22/26 7:19 PM, Rafael J. Wysocki wrote:
> On Thu, Jan 22, 2026 at 8:35 AM Yicong Yang <yang.yicong@picoheart.com> wrote:
>>
>> The device object rescan in acpi_scan_clear_dep_fn is scheduled
>> in the system workqueue which is not guaranteed to be finished
>> before entering userspace. This will cause the problem that
>> some key devices are missed when the init task try to find them,
>> e.g. console devices and root devices (PCIe nvme, etc).
>> This issues is more possbile to happen on RISCV since these
>> devices using GSI interrupt may depend on APLIC and will be
>> scanned in acpi_scan_clear_dep_queue() after APLIC initialized.
>>
>> Fix this by scheduling the acpi_scan_clear_dep_queue() using async
>> schedule function rather than the system workqueue. The deferred
>> works will be synchronized by async_synchronize_full() before
>> entering init task.
>>
>> Update the comment as well.
>>
>> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
>> ---
>>  drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
>>  1 file changed, 16 insertions(+), 19 deletions(-)
>>
>> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
>> index 416d87f9bd10..bf0d8ba9ba19 100644
>> --- a/drivers/acpi/scan.c
>> +++ b/drivers/acpi/scan.c
>> @@ -5,6 +5,7 @@
>>
>>  #define pr_fmt(fmt) "ACPI: " fmt
>>
>> +#include <linux/async.h>
>>  #include <linux/module.h>
>>  #include <linux/init.h>
>>  #include <linux/slab.h>
>> @@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
>>         struct acpi_device *adev;
>>  };
>>
>> -static void acpi_scan_clear_dep_fn(struct work_struct *work)
>> +static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
>>  {
>> -       struct acpi_scan_clear_dep_work *cdw;
>> -
>> -       cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
>> +       struct acpi_device *adev = to_acpi_device(dev);
>>
>>         acpi_scan_lock_acquire();
>> -       acpi_bus_attach(cdw->adev, (void *)true);
>> +       acpi_bus_attach(adev, (void *)true);
>>         acpi_scan_lock_release();
>>
>> -       acpi_dev_put(cdw->adev);
>> -       kfree(cdw);
>> +       acpi_dev_put(adev);
>>  }
>>
>>  static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
>>  {
>> -       struct acpi_scan_clear_dep_work *cdw;
>> -
>>         if (adev->dep_unmet)
>>                 return false;
>>
>> -       cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
>> -       if (!cdw)
>> -               return false;
>> -
>> -       cdw->adev = adev;
>> -       INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
>>         /*
>> -        * Since the work function may block on the lock until the entire
>> -        * initial enumeration of devices is complete, put it into the unbound
>> -        * workqueue.
>> +        * Async schedule the deferred acpi_scan_clear_dep_fn() since:
>> +        * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
>> +        *   be acquired under acpi_dep_list_lock (held here)
>> +        * - the deferred work at boot stage is ensured to be finished
>> +        *   before entering init task by the async_synchronize_full()
>> +        *   barrier
>> +        *
>> +        * Use _nocall variant since it'll return on failure instead of
>> +        * run the function synchronously.
>>          */
>> -       queue_work(system_dfl_wq, &cdw->work);
>> +       if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))
> 
> If the problem is that system_dfl_wq is too slow, why don't you just
> try a dedicated workqueue for this?
> 
> There's no need to modify all of this code.
> 

The problem is that these works are not finished before entering userspace,
so some key devices like console or PCIe nvme (for root device) is not ready
in time userspace init running.

If we use a dedicated workqueue we still need to do the synchronization
somewhere before entering the userspace to solve the problem. But that's just
what async_schedule* does: queue the function in async_wq (also an unbound one)
and wait finish before execute init process by async_synchronize_full(). Does
it make sense?

Thanks.

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

* Re: [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
@ 2026-01-22 12:50       ` Yicong Yang
  0 siblings, 0 replies; 28+ messages in thread
From: Yicong Yang @ 2026-01-22 12:50 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: yang.yicong, lenb, tglx, gregkh, dakr, akpm, apatel, pjw, palmer,
	aou, alex, geshijian, weidong.wd, linux-acpi, linux-kernel,
	linux-riscv

On 1/22/26 7:19 PM, Rafael J. Wysocki wrote:
> On Thu, Jan 22, 2026 at 8:35 AM Yicong Yang <yang.yicong@picoheart.com> wrote:
>>
>> The device object rescan in acpi_scan_clear_dep_fn is scheduled
>> in the system workqueue which is not guaranteed to be finished
>> before entering userspace. This will cause the problem that
>> some key devices are missed when the init task try to find them,
>> e.g. console devices and root devices (PCIe nvme, etc).
>> This issues is more possbile to happen on RISCV since these
>> devices using GSI interrupt may depend on APLIC and will be
>> scanned in acpi_scan_clear_dep_queue() after APLIC initialized.
>>
>> Fix this by scheduling the acpi_scan_clear_dep_queue() using async
>> schedule function rather than the system workqueue. The deferred
>> works will be synchronized by async_synchronize_full() before
>> entering init task.
>>
>> Update the comment as well.
>>
>> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
>> ---
>>  drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
>>  1 file changed, 16 insertions(+), 19 deletions(-)
>>
>> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
>> index 416d87f9bd10..bf0d8ba9ba19 100644
>> --- a/drivers/acpi/scan.c
>> +++ b/drivers/acpi/scan.c
>> @@ -5,6 +5,7 @@
>>
>>  #define pr_fmt(fmt) "ACPI: " fmt
>>
>> +#include <linux/async.h>
>>  #include <linux/module.h>
>>  #include <linux/init.h>
>>  #include <linux/slab.h>
>> @@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
>>         struct acpi_device *adev;
>>  };
>>
>> -static void acpi_scan_clear_dep_fn(struct work_struct *work)
>> +static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
>>  {
>> -       struct acpi_scan_clear_dep_work *cdw;
>> -
>> -       cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
>> +       struct acpi_device *adev = to_acpi_device(dev);
>>
>>         acpi_scan_lock_acquire();
>> -       acpi_bus_attach(cdw->adev, (void *)true);
>> +       acpi_bus_attach(adev, (void *)true);
>>         acpi_scan_lock_release();
>>
>> -       acpi_dev_put(cdw->adev);
>> -       kfree(cdw);
>> +       acpi_dev_put(adev);
>>  }
>>
>>  static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
>>  {
>> -       struct acpi_scan_clear_dep_work *cdw;
>> -
>>         if (adev->dep_unmet)
>>                 return false;
>>
>> -       cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
>> -       if (!cdw)
>> -               return false;
>> -
>> -       cdw->adev = adev;
>> -       INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
>>         /*
>> -        * Since the work function may block on the lock until the entire
>> -        * initial enumeration of devices is complete, put it into the unbound
>> -        * workqueue.
>> +        * Async schedule the deferred acpi_scan_clear_dep_fn() since:
>> +        * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
>> +        *   be acquired under acpi_dep_list_lock (held here)
>> +        * - the deferred work at boot stage is ensured to be finished
>> +        *   before entering init task by the async_synchronize_full()
>> +        *   barrier
>> +        *
>> +        * Use _nocall variant since it'll return on failure instead of
>> +        * run the function synchronously.
>>          */
>> -       queue_work(system_dfl_wq, &cdw->work);
>> +       if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))
> 
> If the problem is that system_dfl_wq is too slow, why don't you just
> try a dedicated workqueue for this?
> 
> There's no need to modify all of this code.
> 

The problem is that these works are not finished before entering userspace,
so some key devices like console or PCIe nvme (for root device) is not ready
in time userspace init running.

If we use a dedicated workqueue we still need to do the synchronization
somewhere before entering the userspace to solve the problem. But that's just
what async_schedule* does: queue the function in async_wq (also an unbound one)
and wait finish before execute init process by async_synchronize_full(). Does
it make sense?

Thanks.

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* Re: [PATCH 2/2] init: Move console_on_rootfs after async_synchronize_full
  2026-01-22 10:27     ` Greg KH
@ 2026-01-22 13:12       ` Yicong Yang
  -1 siblings, 0 replies; 28+ messages in thread
From: Yicong Yang @ 2026-01-22 13:12 UTC (permalink / raw)
  To: Greg KH
  Cc: yang.yicong, rafael, lenb, tglx, dakr, akpm, apatel, pjw, palmer,
	aou, alex, geshijian, weidong.wd, linux-acpi, linux-kernel,
	linux-riscv

On 1/22/26 6:27 PM, Greg KH wrote:
> On Thu, Jan 22, 2026 at 03:34:46PM +0800, Yicong Yang wrote:
>> Currently the console_on_rootfs() is called before
>> async_synchronize_full(), the console initialization
>> could be still in process in theory due to async
>> probe, etc. Make it after the async_synchronize_full()
>> to make sure the initialization work is done.
> 
> Please wrap at 72 columns.
> 
>>
>> Log the error code as well if we failed to open the console.
>>
>> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
>> ---
>>  init/main.c | 4 ++--
>>  1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/init/main.c b/init/main.c
>> index b84818ad9685..c37ba5f89b96 100644
>> --- a/init/main.c
>> +++ b/init/main.c
>> @@ -1578,6 +1578,7 @@ static int __ref kernel_init(void *unused)
>>  	kernel_init_freeable();
>>  	/* need to finish all async __init code before freeing the memory */
>>  	async_synchronize_full();
>> +	console_on_rootfs();
> 
> Are you sure this is ok?  Messing around with init levels and order is
> _VERY_ tricky.
> 

It's previously in kernel_init_freeable() after do_basic_setup() (where
initcalls invoked). So moving it here the init levels and order is
unchanged (still after the do_basic_setup).

Tested with initrd (ramdisk) and initramfs made by busybox and works fine
(hope no other scenarios missed).


> Your console should NOT be on an async probe path, if you really need
> it, then do not do that at all.  Make it sync, and then it should be ok.
> 

not for my console. it's a theoretical issue during the last discussion but
I did try to make this happened (by make the probe async and add some delay
in the probe to simulate a slow initialization).

since indeed no real problem I met and if consider it should never happen in
real case, should we just leave it as is?

>>  
>>  	system_state = SYSTEM_FREEING_INITMEM;
>>  	kprobe_free_init_mem();
>> @@ -1647,7 +1648,7 @@ void __init console_on_rootfs(void)
>>  	struct file *file = filp_open("/dev/console", O_RDWR, 0);
>>  
>>  	if (IS_ERR(file)) {
>> -		pr_err("Warning: unable to open an initial console.\n");
>> +		pr_err("Warning: unable to open an initial console, err = %ld\n", PTR_ERR(file));
> 
> Why is this changed?
> 

This is a trivial change so I didn't make a separate patch. I suppose it's
useful since I did see different errors (ENOENT, ENODEV) when make cases
for testing this patch and we've already have the err code returned here.

>>  		return;
>>  	}
>>  	init_dup(file);
>> @@ -1690,7 +1691,6 @@ static noinline void __init kernel_init_freeable(void)
>>  	kunit_run_all_tests();
>>  
>>  	wait_for_initramfs();
>> -	console_on_rootfs();
> 
> You just delayed the console output for many (i.e. most) systems out
> there, are you sure that is acceptable to them?
> 

IIUC, console_on_rootfs() will open /dev/console for userspace's
stdout/stdin/stderr and kernel log (printk, etc) won't be affected
by its order.

Thanks.

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

* Re: [PATCH 2/2] init: Move console_on_rootfs after async_synchronize_full
@ 2026-01-22 13:12       ` Yicong Yang
  0 siblings, 0 replies; 28+ messages in thread
From: Yicong Yang @ 2026-01-22 13:12 UTC (permalink / raw)
  To: Greg KH
  Cc: yang.yicong, rafael, lenb, tglx, dakr, akpm, apatel, pjw, palmer,
	aou, alex, geshijian, weidong.wd, linux-acpi, linux-kernel,
	linux-riscv

On 1/22/26 6:27 PM, Greg KH wrote:
> On Thu, Jan 22, 2026 at 03:34:46PM +0800, Yicong Yang wrote:
>> Currently the console_on_rootfs() is called before
>> async_synchronize_full(), the console initialization
>> could be still in process in theory due to async
>> probe, etc. Make it after the async_synchronize_full()
>> to make sure the initialization work is done.
> 
> Please wrap at 72 columns.
> 
>>
>> Log the error code as well if we failed to open the console.
>>
>> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
>> ---
>>  init/main.c | 4 ++--
>>  1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/init/main.c b/init/main.c
>> index b84818ad9685..c37ba5f89b96 100644
>> --- a/init/main.c
>> +++ b/init/main.c
>> @@ -1578,6 +1578,7 @@ static int __ref kernel_init(void *unused)
>>  	kernel_init_freeable();
>>  	/* need to finish all async __init code before freeing the memory */
>>  	async_synchronize_full();
>> +	console_on_rootfs();
> 
> Are you sure this is ok?  Messing around with init levels and order is
> _VERY_ tricky.
> 

It's previously in kernel_init_freeable() after do_basic_setup() (where
initcalls invoked). So moving it here the init levels and order is
unchanged (still after the do_basic_setup).

Tested with initrd (ramdisk) and initramfs made by busybox and works fine
(hope no other scenarios missed).


> Your console should NOT be on an async probe path, if you really need
> it, then do not do that at all.  Make it sync, and then it should be ok.
> 

not for my console. it's a theoretical issue during the last discussion but
I did try to make this happened (by make the probe async and add some delay
in the probe to simulate a slow initialization).

since indeed no real problem I met and if consider it should never happen in
real case, should we just leave it as is?

>>  
>>  	system_state = SYSTEM_FREEING_INITMEM;
>>  	kprobe_free_init_mem();
>> @@ -1647,7 +1648,7 @@ void __init console_on_rootfs(void)
>>  	struct file *file = filp_open("/dev/console", O_RDWR, 0);
>>  
>>  	if (IS_ERR(file)) {
>> -		pr_err("Warning: unable to open an initial console.\n");
>> +		pr_err("Warning: unable to open an initial console, err = %ld\n", PTR_ERR(file));
> 
> Why is this changed?
> 

This is a trivial change so I didn't make a separate patch. I suppose it's
useful since I did see different errors (ENOENT, ENODEV) when make cases
for testing this patch and we've already have the err code returned here.

>>  		return;
>>  	}
>>  	init_dup(file);
>> @@ -1690,7 +1691,6 @@ static noinline void __init kernel_init_freeable(void)
>>  	kunit_run_all_tests();
>>  
>>  	wait_for_initramfs();
>> -	console_on_rootfs();
> 
> You just delayed the console output for many (i.e. most) systems out
> there, are you sure that is acceptable to them?
> 

IIUC, console_on_rootfs() will open /dev/console for userspace's
stdout/stdin/stderr and kernel log (printk, etc) won't be affected
by its order.

Thanks.

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* Re: [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
  2026-01-22 12:43       ` Yicong Yang
@ 2026-01-22 13:21         ` Rafael J. Wysocki
  -1 siblings, 0 replies; 28+ messages in thread
From: Rafael J. Wysocki @ 2026-01-22 13:21 UTC (permalink / raw)
  To: Yicong Yang
  Cc: Greg KH, rafael, lenb, tglx, dakr, akpm, apatel, pjw, palmer, aou,
	alex, geshijian, weidong.wd, linux-acpi, linux-kernel,
	linux-riscv

On Thu, Jan 22, 2026 at 1:43 PM Yicong Yang <yang.yicong@picoheart.com> wrote:
>
> On 1/22/26 6:29 PM, Greg KH wrote:
> > On Thu, Jan 22, 2026 at 03:34:45PM +0800, Yicong Yang wrote:
> >> The device object rescan in acpi_scan_clear_dep_fn is scheduled
> >> in the system workqueue which is not guaranteed to be finished
> >> before entering userspace. This will cause the problem that
> >> some key devices are missed when the init task try to find them,
> >> e.g. console devices and root devices (PCIe nvme, etc).
> >> This issues is more possbile to happen on RISCV since these
> >> devices using GSI interrupt may depend on APLIC and will be
> >> scanned in acpi_scan_clear_dep_queue() after APLIC initialized.
> >>
> >> Fix this by scheduling the acpi_scan_clear_dep_queue() using async
> >> schedule function rather than the system workqueue. The deferred
> >> works will be synchronized by async_synchronize_full() before
> >> entering init task.
> >>
> >> Update the comment as well.
> >>
> >> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
> >> ---
> >>  drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
> >>  1 file changed, 16 insertions(+), 19 deletions(-)
> >>
> >> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> >> index 416d87f9bd10..bf0d8ba9ba19 100644
> >> --- a/drivers/acpi/scan.c
> >> +++ b/drivers/acpi/scan.c
> >> @@ -5,6 +5,7 @@
> >>
> >>  #define pr_fmt(fmt) "ACPI: " fmt
> >>
> >> +#include <linux/async.h>
> >>  #include <linux/module.h>
> >>  #include <linux/init.h>
> >>  #include <linux/slab.h>
> >> @@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
> >>      struct acpi_device *adev;
> >>  };
> >>
> >> -static void acpi_scan_clear_dep_fn(struct work_struct *work)
> >> +static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
> >>  {
> >> -    struct acpi_scan_clear_dep_work *cdw;
> >> -
> >> -    cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
> >> +    struct acpi_device *adev = to_acpi_device(dev);
> >>
> >>      acpi_scan_lock_acquire();
> >> -    acpi_bus_attach(cdw->adev, (void *)true);
> >> +    acpi_bus_attach(adev, (void *)true);
> >>      acpi_scan_lock_release();
> >>
> >> -    acpi_dev_put(cdw->adev);
> >> -    kfree(cdw);
> >> +    acpi_dev_put(adev);
> >>  }
> >>
> >>  static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
> >>  {
> >> -    struct acpi_scan_clear_dep_work *cdw;
> >> -
> >>      if (adev->dep_unmet)
> >>              return false;
> >>
> >> -    cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
> >> -    if (!cdw)
> >> -            return false;
> >> -
> >> -    cdw->adev = adev;
> >> -    INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
> >>      /*
> >> -     * Since the work function may block on the lock until the entire
> >> -     * initial enumeration of devices is complete, put it into the unbound
> >> -     * workqueue.
> >> +     * Async schedule the deferred acpi_scan_clear_dep_fn() since:
> >> +     * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
> >> +     *   be acquired under acpi_dep_list_lock (held here)
> >> +     * - the deferred work at boot stage is ensured to be finished
> >> +     *   before entering init task by the async_synchronize_full()
> >> +     *   barrier
> >> +     *
> >> +     * Use _nocall variant since it'll return on failure instead of
> >> +     * run the function synchronously.
> >>       */
> >> -    queue_work(system_dfl_wq, &cdw->work);
> >> +    if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))
> >> +            return false;
> >
> > This really feels wrong to me, you are taking a code path that has been
> > working for quite a while and changing it.  Perhaps your system ACPI
> > tables are the thing that is incorrect here?
> >
> > What exactly is the problem that you are seeing?  Why not start with
> > that and then we can work out how to solve that issue?
> >
>
> two issues here we met (as briefly mentioned in the commit and cover letter):
> 1. kernel panic due to userspace init cannot have an opened console. the
>    console device scanning is queued in the system_dfl_wq in above code
>    and not finished by the time userspace init process running, thus by
>    the time userspace init running, no console is created
> 2. entering rescue shell due to no root devices (PCIe nvme in our case)
>    found. same reason as above, the PCIe host bridge scanning is queued
>    in above and finished after init process running.
>
> The reason why these devices are created here is because they both depend
> on riscv-aplic irqchip to serve their interrupts (console's wired
> interrupt and PCI's INTx interrupts) and in order to keep the dependency
> these devices are scanned and created after riscv-aplic initialized. The
> riscv-aplic is initialized in device_initcall and invoke above codes for
> the scan/creation of these devices, it's close to the time running
> userspace init process. Since system_dfl_wq is used here and no synchronized
> mechanism, the issues will happen if userspace init runs before these devices
> are ready.

Well, there is flush_workqueue(), isn't it there?

> Previous solution [1] is to advance the initialization of riscv-aplic
> earlier but the order still cannot be guaranteed conceptually.
> With async_schedule_dev_nocal() the work queued is finished
> before entering userspace init since we'll wait for completion at
> async_synchronize_full() before executing userspace init process.
>
> To solve the issue I think we should make these devices ready before
> entering userspace and async schedule is one way to make it. It's also
> using an unbound workqueue but have additional synchronization. Any
> corrections or suggestions?

You can flush the dedicated workqueue at the same spot where you do
async_synchronize_full(), can't you?

> [1] https://lore.kernel.org/linux-riscv/20260114063730.78009-1-yang.yicong@picoheart.com/

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

* Re: [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
@ 2026-01-22 13:21         ` Rafael J. Wysocki
  0 siblings, 0 replies; 28+ messages in thread
From: Rafael J. Wysocki @ 2026-01-22 13:21 UTC (permalink / raw)
  To: Yicong Yang
  Cc: Greg KH, rafael, lenb, tglx, dakr, akpm, apatel, pjw, palmer, aou,
	alex, geshijian, weidong.wd, linux-acpi, linux-kernel,
	linux-riscv

On Thu, Jan 22, 2026 at 1:43 PM Yicong Yang <yang.yicong@picoheart.com> wrote:
>
> On 1/22/26 6:29 PM, Greg KH wrote:
> > On Thu, Jan 22, 2026 at 03:34:45PM +0800, Yicong Yang wrote:
> >> The device object rescan in acpi_scan_clear_dep_fn is scheduled
> >> in the system workqueue which is not guaranteed to be finished
> >> before entering userspace. This will cause the problem that
> >> some key devices are missed when the init task try to find them,
> >> e.g. console devices and root devices (PCIe nvme, etc).
> >> This issues is more possbile to happen on RISCV since these
> >> devices using GSI interrupt may depend on APLIC and will be
> >> scanned in acpi_scan_clear_dep_queue() after APLIC initialized.
> >>
> >> Fix this by scheduling the acpi_scan_clear_dep_queue() using async
> >> schedule function rather than the system workqueue. The deferred
> >> works will be synchronized by async_synchronize_full() before
> >> entering init task.
> >>
> >> Update the comment as well.
> >>
> >> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
> >> ---
> >>  drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
> >>  1 file changed, 16 insertions(+), 19 deletions(-)
> >>
> >> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> >> index 416d87f9bd10..bf0d8ba9ba19 100644
> >> --- a/drivers/acpi/scan.c
> >> +++ b/drivers/acpi/scan.c
> >> @@ -5,6 +5,7 @@
> >>
> >>  #define pr_fmt(fmt) "ACPI: " fmt
> >>
> >> +#include <linux/async.h>
> >>  #include <linux/module.h>
> >>  #include <linux/init.h>
> >>  #include <linux/slab.h>
> >> @@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
> >>      struct acpi_device *adev;
> >>  };
> >>
> >> -static void acpi_scan_clear_dep_fn(struct work_struct *work)
> >> +static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
> >>  {
> >> -    struct acpi_scan_clear_dep_work *cdw;
> >> -
> >> -    cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
> >> +    struct acpi_device *adev = to_acpi_device(dev);
> >>
> >>      acpi_scan_lock_acquire();
> >> -    acpi_bus_attach(cdw->adev, (void *)true);
> >> +    acpi_bus_attach(adev, (void *)true);
> >>      acpi_scan_lock_release();
> >>
> >> -    acpi_dev_put(cdw->adev);
> >> -    kfree(cdw);
> >> +    acpi_dev_put(adev);
> >>  }
> >>
> >>  static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
> >>  {
> >> -    struct acpi_scan_clear_dep_work *cdw;
> >> -
> >>      if (adev->dep_unmet)
> >>              return false;
> >>
> >> -    cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
> >> -    if (!cdw)
> >> -            return false;
> >> -
> >> -    cdw->adev = adev;
> >> -    INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
> >>      /*
> >> -     * Since the work function may block on the lock until the entire
> >> -     * initial enumeration of devices is complete, put it into the unbound
> >> -     * workqueue.
> >> +     * Async schedule the deferred acpi_scan_clear_dep_fn() since:
> >> +     * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
> >> +     *   be acquired under acpi_dep_list_lock (held here)
> >> +     * - the deferred work at boot stage is ensured to be finished
> >> +     *   before entering init task by the async_synchronize_full()
> >> +     *   barrier
> >> +     *
> >> +     * Use _nocall variant since it'll return on failure instead of
> >> +     * run the function synchronously.
> >>       */
> >> -    queue_work(system_dfl_wq, &cdw->work);
> >> +    if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))
> >> +            return false;
> >
> > This really feels wrong to me, you are taking a code path that has been
> > working for quite a while and changing it.  Perhaps your system ACPI
> > tables are the thing that is incorrect here?
> >
> > What exactly is the problem that you are seeing?  Why not start with
> > that and then we can work out how to solve that issue?
> >
>
> two issues here we met (as briefly mentioned in the commit and cover letter):
> 1. kernel panic due to userspace init cannot have an opened console. the
>    console device scanning is queued in the system_dfl_wq in above code
>    and not finished by the time userspace init process running, thus by
>    the time userspace init running, no console is created
> 2. entering rescue shell due to no root devices (PCIe nvme in our case)
>    found. same reason as above, the PCIe host bridge scanning is queued
>    in above and finished after init process running.
>
> The reason why these devices are created here is because they both depend
> on riscv-aplic irqchip to serve their interrupts (console's wired
> interrupt and PCI's INTx interrupts) and in order to keep the dependency
> these devices are scanned and created after riscv-aplic initialized. The
> riscv-aplic is initialized in device_initcall and invoke above codes for
> the scan/creation of these devices, it's close to the time running
> userspace init process. Since system_dfl_wq is used here and no synchronized
> mechanism, the issues will happen if userspace init runs before these devices
> are ready.

Well, there is flush_workqueue(), isn't it there?

> Previous solution [1] is to advance the initialization of riscv-aplic
> earlier but the order still cannot be guaranteed conceptually.
> With async_schedule_dev_nocal() the work queued is finished
> before entering userspace init since we'll wait for completion at
> async_synchronize_full() before executing userspace init process.
>
> To solve the issue I think we should make these devices ready before
> entering userspace and async schedule is one way to make it. It's also
> using an unbound workqueue but have additional synchronization. Any
> corrections or suggestions?

You can flush the dedicated workqueue at the same spot where you do
async_synchronize_full(), can't you?

> [1] https://lore.kernel.org/linux-riscv/20260114063730.78009-1-yang.yicong@picoheart.com/

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* Re: [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
  2026-01-22 12:50       ` Yicong Yang
@ 2026-01-22 13:22         ` Rafael J. Wysocki
  -1 siblings, 0 replies; 28+ messages in thread
From: Rafael J. Wysocki @ 2026-01-22 13:22 UTC (permalink / raw)
  To: Yicong Yang
  Cc: Rafael J. Wysocki, lenb, tglx, gregkh, dakr, akpm, apatel, pjw,
	palmer, aou, alex, geshijian, weidong.wd, linux-acpi,
	linux-kernel, linux-riscv

On Thu, Jan 22, 2026 at 1:50 PM Yicong Yang <yang.yicong@picoheart.com> wrote:
>
> On 1/22/26 7:19 PM, Rafael J. Wysocki wrote:
> > On Thu, Jan 22, 2026 at 8:35 AM Yicong Yang <yang.yicong@picoheart.com> wrote:
> >>
> >> The device object rescan in acpi_scan_clear_dep_fn is scheduled
> >> in the system workqueue which is not guaranteed to be finished
> >> before entering userspace. This will cause the problem that
> >> some key devices are missed when the init task try to find them,
> >> e.g. console devices and root devices (PCIe nvme, etc).
> >> This issues is more possbile to happen on RISCV since these
> >> devices using GSI interrupt may depend on APLIC and will be
> >> scanned in acpi_scan_clear_dep_queue() after APLIC initialized.
> >>
> >> Fix this by scheduling the acpi_scan_clear_dep_queue() using async
> >> schedule function rather than the system workqueue. The deferred
> >> works will be synchronized by async_synchronize_full() before
> >> entering init task.
> >>
> >> Update the comment as well.
> >>
> >> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
> >> ---
> >>  drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
> >>  1 file changed, 16 insertions(+), 19 deletions(-)
> >>
> >> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> >> index 416d87f9bd10..bf0d8ba9ba19 100644
> >> --- a/drivers/acpi/scan.c
> >> +++ b/drivers/acpi/scan.c
> >> @@ -5,6 +5,7 @@
> >>
> >>  #define pr_fmt(fmt) "ACPI: " fmt
> >>
> >> +#include <linux/async.h>
> >>  #include <linux/module.h>
> >>  #include <linux/init.h>
> >>  #include <linux/slab.h>
> >> @@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
> >>         struct acpi_device *adev;
> >>  };
> >>
> >> -static void acpi_scan_clear_dep_fn(struct work_struct *work)
> >> +static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
> >>  {
> >> -       struct acpi_scan_clear_dep_work *cdw;
> >> -
> >> -       cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
> >> +       struct acpi_device *adev = to_acpi_device(dev);
> >>
> >>         acpi_scan_lock_acquire();
> >> -       acpi_bus_attach(cdw->adev, (void *)true);
> >> +       acpi_bus_attach(adev, (void *)true);
> >>         acpi_scan_lock_release();
> >>
> >> -       acpi_dev_put(cdw->adev);
> >> -       kfree(cdw);
> >> +       acpi_dev_put(adev);
> >>  }
> >>
> >>  static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
> >>  {
> >> -       struct acpi_scan_clear_dep_work *cdw;
> >> -
> >>         if (adev->dep_unmet)
> >>                 return false;
> >>
> >> -       cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
> >> -       if (!cdw)
> >> -               return false;
> >> -
> >> -       cdw->adev = adev;
> >> -       INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
> >>         /*
> >> -        * Since the work function may block on the lock until the entire
> >> -        * initial enumeration of devices is complete, put it into the unbound
> >> -        * workqueue.
> >> +        * Async schedule the deferred acpi_scan_clear_dep_fn() since:
> >> +        * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
> >> +        *   be acquired under acpi_dep_list_lock (held here)
> >> +        * - the deferred work at boot stage is ensured to be finished
> >> +        *   before entering init task by the async_synchronize_full()
> >> +        *   barrier
> >> +        *
> >> +        * Use _nocall variant since it'll return on failure instead of
> >> +        * run the function synchronously.
> >>          */
> >> -       queue_work(system_dfl_wq, &cdw->work);
> >> +       if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))
> >
> > If the problem is that system_dfl_wq is too slow, why don't you just
> > try a dedicated workqueue for this?
> >
> > There's no need to modify all of this code.
> >
>
> The problem is that these works are not finished before entering userspace,
> so some key devices like console or PCIe nvme (for root device) is not ready
> in time userspace init running.
>
> If we use a dedicated workqueue we still need to do the synchronization
> somewhere before entering the userspace to solve the problem. But that's just
> what async_schedule* does: queue the function in async_wq (also an unbound one)
> and wait finish before execute init process by async_synchronize_full(). Does
> it make sense?

Well, please see my reply to the other message.

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

* Re: [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
@ 2026-01-22 13:22         ` Rafael J. Wysocki
  0 siblings, 0 replies; 28+ messages in thread
From: Rafael J. Wysocki @ 2026-01-22 13:22 UTC (permalink / raw)
  To: Yicong Yang
  Cc: Rafael J. Wysocki, lenb, tglx, gregkh, dakr, akpm, apatel, pjw,
	palmer, aou, alex, geshijian, weidong.wd, linux-acpi,
	linux-kernel, linux-riscv

On Thu, Jan 22, 2026 at 1:50 PM Yicong Yang <yang.yicong@picoheart.com> wrote:
>
> On 1/22/26 7:19 PM, Rafael J. Wysocki wrote:
> > On Thu, Jan 22, 2026 at 8:35 AM Yicong Yang <yang.yicong@picoheart.com> wrote:
> >>
> >> The device object rescan in acpi_scan_clear_dep_fn is scheduled
> >> in the system workqueue which is not guaranteed to be finished
> >> before entering userspace. This will cause the problem that
> >> some key devices are missed when the init task try to find them,
> >> e.g. console devices and root devices (PCIe nvme, etc).
> >> This issues is more possbile to happen on RISCV since these
> >> devices using GSI interrupt may depend on APLIC and will be
> >> scanned in acpi_scan_clear_dep_queue() after APLIC initialized.
> >>
> >> Fix this by scheduling the acpi_scan_clear_dep_queue() using async
> >> schedule function rather than the system workqueue. The deferred
> >> works will be synchronized by async_synchronize_full() before
> >> entering init task.
> >>
> >> Update the comment as well.
> >>
> >> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
> >> ---
> >>  drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
> >>  1 file changed, 16 insertions(+), 19 deletions(-)
> >>
> >> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> >> index 416d87f9bd10..bf0d8ba9ba19 100644
> >> --- a/drivers/acpi/scan.c
> >> +++ b/drivers/acpi/scan.c
> >> @@ -5,6 +5,7 @@
> >>
> >>  #define pr_fmt(fmt) "ACPI: " fmt
> >>
> >> +#include <linux/async.h>
> >>  #include <linux/module.h>
> >>  #include <linux/init.h>
> >>  #include <linux/slab.h>
> >> @@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
> >>         struct acpi_device *adev;
> >>  };
> >>
> >> -static void acpi_scan_clear_dep_fn(struct work_struct *work)
> >> +static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
> >>  {
> >> -       struct acpi_scan_clear_dep_work *cdw;
> >> -
> >> -       cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
> >> +       struct acpi_device *adev = to_acpi_device(dev);
> >>
> >>         acpi_scan_lock_acquire();
> >> -       acpi_bus_attach(cdw->adev, (void *)true);
> >> +       acpi_bus_attach(adev, (void *)true);
> >>         acpi_scan_lock_release();
> >>
> >> -       acpi_dev_put(cdw->adev);
> >> -       kfree(cdw);
> >> +       acpi_dev_put(adev);
> >>  }
> >>
> >>  static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
> >>  {
> >> -       struct acpi_scan_clear_dep_work *cdw;
> >> -
> >>         if (adev->dep_unmet)
> >>                 return false;
> >>
> >> -       cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
> >> -       if (!cdw)
> >> -               return false;
> >> -
> >> -       cdw->adev = adev;
> >> -       INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
> >>         /*
> >> -        * Since the work function may block on the lock until the entire
> >> -        * initial enumeration of devices is complete, put it into the unbound
> >> -        * workqueue.
> >> +        * Async schedule the deferred acpi_scan_clear_dep_fn() since:
> >> +        * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
> >> +        *   be acquired under acpi_dep_list_lock (held here)
> >> +        * - the deferred work at boot stage is ensured to be finished
> >> +        *   before entering init task by the async_synchronize_full()
> >> +        *   barrier
> >> +        *
> >> +        * Use _nocall variant since it'll return on failure instead of
> >> +        * run the function synchronously.
> >>          */
> >> -       queue_work(system_dfl_wq, &cdw->work);
> >> +       if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))
> >
> > If the problem is that system_dfl_wq is too slow, why don't you just
> > try a dedicated workqueue for this?
> >
> > There's no need to modify all of this code.
> >
>
> The problem is that these works are not finished before entering userspace,
> so some key devices like console or PCIe nvme (for root device) is not ready
> in time userspace init running.
>
> If we use a dedicated workqueue we still need to do the synchronization
> somewhere before entering the userspace to solve the problem. But that's just
> what async_schedule* does: queue the function in async_wq (also an unbound one)
> and wait finish before execute init process by async_synchronize_full(). Does
> it make sense?

Well, please see my reply to the other message.

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* Re: [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
  2026-01-22 13:21         ` Rafael J. Wysocki
@ 2026-01-22 13:48           ` Yicong Yang
  -1 siblings, 0 replies; 28+ messages in thread
From: Yicong Yang @ 2026-01-22 13:48 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: yang.yicong, Greg KH, lenb, tglx, dakr, akpm, apatel, pjw, palmer,
	aou, alex, geshijian, weidong.wd, linux-acpi, linux-kernel,
	linux-riscv

On 1/22/26 9:21 PM, Rafael J. Wysocki wrote:
> On Thu, Jan 22, 2026 at 1:43 PM Yicong Yang <yang.yicong@picoheart.com> wrote:
>>
>> On 1/22/26 6:29 PM, Greg KH wrote:
>>> On Thu, Jan 22, 2026 at 03:34:45PM +0800, Yicong Yang wrote:
>>>> The device object rescan in acpi_scan_clear_dep_fn is scheduled
>>>> in the system workqueue which is not guaranteed to be finished
>>>> before entering userspace. This will cause the problem that
>>>> some key devices are missed when the init task try to find them,
>>>> e.g. console devices and root devices (PCIe nvme, etc).
>>>> This issues is more possbile to happen on RISCV since these
>>>> devices using GSI interrupt may depend on APLIC and will be
>>>> scanned in acpi_scan_clear_dep_queue() after APLIC initialized.
>>>>
>>>> Fix this by scheduling the acpi_scan_clear_dep_queue() using async
>>>> schedule function rather than the system workqueue. The deferred
>>>> works will be synchronized by async_synchronize_full() before
>>>> entering init task.
>>>>
>>>> Update the comment as well.
>>>>
>>>> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
>>>> ---
>>>>  drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
>>>>  1 file changed, 16 insertions(+), 19 deletions(-)
>>>>
>>>> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
>>>> index 416d87f9bd10..bf0d8ba9ba19 100644
>>>> --- a/drivers/acpi/scan.c
>>>> +++ b/drivers/acpi/scan.c
>>>> @@ -5,6 +5,7 @@
>>>>
>>>>  #define pr_fmt(fmt) "ACPI: " fmt
>>>>
>>>> +#include <linux/async.h>
>>>>  #include <linux/module.h>
>>>>  #include <linux/init.h>
>>>>  #include <linux/slab.h>
>>>> @@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
>>>>      struct acpi_device *adev;
>>>>  };
>>>>
>>>> -static void acpi_scan_clear_dep_fn(struct work_struct *work)
>>>> +static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
>>>>  {
>>>> -    struct acpi_scan_clear_dep_work *cdw;
>>>> -
>>>> -    cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
>>>> +    struct acpi_device *adev = to_acpi_device(dev);
>>>>
>>>>      acpi_scan_lock_acquire();
>>>> -    acpi_bus_attach(cdw->adev, (void *)true);
>>>> +    acpi_bus_attach(adev, (void *)true);
>>>>      acpi_scan_lock_release();
>>>>
>>>> -    acpi_dev_put(cdw->adev);
>>>> -    kfree(cdw);
>>>> +    acpi_dev_put(adev);
>>>>  }
>>>>
>>>>  static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
>>>>  {
>>>> -    struct acpi_scan_clear_dep_work *cdw;
>>>> -
>>>>      if (adev->dep_unmet)
>>>>              return false;
>>>>
>>>> -    cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
>>>> -    if (!cdw)
>>>> -            return false;
>>>> -
>>>> -    cdw->adev = adev;
>>>> -    INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
>>>>      /*
>>>> -     * Since the work function may block on the lock until the entire
>>>> -     * initial enumeration of devices is complete, put it into the unbound
>>>> -     * workqueue.
>>>> +     * Async schedule the deferred acpi_scan_clear_dep_fn() since:
>>>> +     * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
>>>> +     *   be acquired under acpi_dep_list_lock (held here)
>>>> +     * - the deferred work at boot stage is ensured to be finished
>>>> +     *   before entering init task by the async_synchronize_full()
>>>> +     *   barrier
>>>> +     *
>>>> +     * Use _nocall variant since it'll return on failure instead of
>>>> +     * run the function synchronously.
>>>>       */
>>>> -    queue_work(system_dfl_wq, &cdw->work);
>>>> +    if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))
>>>> +            return false;
>>>
>>> This really feels wrong to me, you are taking a code path that has been
>>> working for quite a while and changing it.  Perhaps your system ACPI
>>> tables are the thing that is incorrect here?
>>>
>>> What exactly is the problem that you are seeing?  Why not start with
>>> that and then we can work out how to solve that issue?
>>>
>>
>> two issues here we met (as briefly mentioned in the commit and cover letter):
>> 1. kernel panic due to userspace init cannot have an opened console. the
>>    console device scanning is queued in the system_dfl_wq in above code
>>    and not finished by the time userspace init process running, thus by
>>    the time userspace init running, no console is created
>> 2. entering rescue shell due to no root devices (PCIe nvme in our case)
>>    found. same reason as above, the PCIe host bridge scanning is queued
>>    in above and finished after init process running.
>>
>> The reason why these devices are created here is because they both depend
>> on riscv-aplic irqchip to serve their interrupts (console's wired
>> interrupt and PCI's INTx interrupts) and in order to keep the dependency
>> these devices are scanned and created after riscv-aplic initialized. The
>> riscv-aplic is initialized in device_initcall and invoke above codes for
>> the scan/creation of these devices, it's close to the time running
>> userspace init process. Since system_dfl_wq is used here and no synchronized
>> mechanism, the issues will happen if userspace init runs before these devices
>> are ready.
> 
> Well, there is flush_workqueue(), isn't it there?
> 

sure, of course. I implement it using async schedule but open to any
better ones. but..

>> Previous solution [1] is to advance the initialization of riscv-aplic
>> earlier but the order still cannot be guaranteed conceptually.
>> With async_schedule_dev_nocal() the work queued is finished
>> before entering userspace init since we'll wait for completion at
>> async_synchronize_full() before executing userspace init process.
>>
>> To solve the issue I think we should make these devices ready before
>> entering userspace and async schedule is one way to make it. It's also
>> using an unbound workqueue but have additional synchronization. Any
>> corrections or suggestions?
> 
> You can flush the dedicated workqueue at the same spot where you do
> async_synchronize_full(), can't you?
> 

the async_synchronize_full() is already there in the init code right
before entering usersapce [1] so if we use async schedule we don't
need to add synchronize spot ourselves. For a dedicated workqueue we
need to call flush_workqueue() explicitly somewhere (I suppose to be
the last level initcall like late_initcall_sync). Furthermore we need
to allocate it and I think not all the platforms need this piece of
code.

It seems no need to have a dedicated workqueue for this since async
schedule can satisfy the needs already (from my view). Except less
modifications can be made for this piece of code if we use a dedicated
workqueue, is this the consideration and mandatory?

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/init/main.c?h=v6.19-rc6#n1580

thanks.

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

* Re: [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
@ 2026-01-22 13:48           ` Yicong Yang
  0 siblings, 0 replies; 28+ messages in thread
From: Yicong Yang @ 2026-01-22 13:48 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: yang.yicong, Greg KH, lenb, tglx, dakr, akpm, apatel, pjw, palmer,
	aou, alex, geshijian, weidong.wd, linux-acpi, linux-kernel,
	linux-riscv

On 1/22/26 9:21 PM, Rafael J. Wysocki wrote:
> On Thu, Jan 22, 2026 at 1:43 PM Yicong Yang <yang.yicong@picoheart.com> wrote:
>>
>> On 1/22/26 6:29 PM, Greg KH wrote:
>>> On Thu, Jan 22, 2026 at 03:34:45PM +0800, Yicong Yang wrote:
>>>> The device object rescan in acpi_scan_clear_dep_fn is scheduled
>>>> in the system workqueue which is not guaranteed to be finished
>>>> before entering userspace. This will cause the problem that
>>>> some key devices are missed when the init task try to find them,
>>>> e.g. console devices and root devices (PCIe nvme, etc).
>>>> This issues is more possbile to happen on RISCV since these
>>>> devices using GSI interrupt may depend on APLIC and will be
>>>> scanned in acpi_scan_clear_dep_queue() after APLIC initialized.
>>>>
>>>> Fix this by scheduling the acpi_scan_clear_dep_queue() using async
>>>> schedule function rather than the system workqueue. The deferred
>>>> works will be synchronized by async_synchronize_full() before
>>>> entering init task.
>>>>
>>>> Update the comment as well.
>>>>
>>>> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
>>>> ---
>>>>  drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
>>>>  1 file changed, 16 insertions(+), 19 deletions(-)
>>>>
>>>> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
>>>> index 416d87f9bd10..bf0d8ba9ba19 100644
>>>> --- a/drivers/acpi/scan.c
>>>> +++ b/drivers/acpi/scan.c
>>>> @@ -5,6 +5,7 @@
>>>>
>>>>  #define pr_fmt(fmt) "ACPI: " fmt
>>>>
>>>> +#include <linux/async.h>
>>>>  #include <linux/module.h>
>>>>  #include <linux/init.h>
>>>>  #include <linux/slab.h>
>>>> @@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
>>>>      struct acpi_device *adev;
>>>>  };
>>>>
>>>> -static void acpi_scan_clear_dep_fn(struct work_struct *work)
>>>> +static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
>>>>  {
>>>> -    struct acpi_scan_clear_dep_work *cdw;
>>>> -
>>>> -    cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
>>>> +    struct acpi_device *adev = to_acpi_device(dev);
>>>>
>>>>      acpi_scan_lock_acquire();
>>>> -    acpi_bus_attach(cdw->adev, (void *)true);
>>>> +    acpi_bus_attach(adev, (void *)true);
>>>>      acpi_scan_lock_release();
>>>>
>>>> -    acpi_dev_put(cdw->adev);
>>>> -    kfree(cdw);
>>>> +    acpi_dev_put(adev);
>>>>  }
>>>>
>>>>  static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
>>>>  {
>>>> -    struct acpi_scan_clear_dep_work *cdw;
>>>> -
>>>>      if (adev->dep_unmet)
>>>>              return false;
>>>>
>>>> -    cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
>>>> -    if (!cdw)
>>>> -            return false;
>>>> -
>>>> -    cdw->adev = adev;
>>>> -    INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
>>>>      /*
>>>> -     * Since the work function may block on the lock until the entire
>>>> -     * initial enumeration of devices is complete, put it into the unbound
>>>> -     * workqueue.
>>>> +     * Async schedule the deferred acpi_scan_clear_dep_fn() since:
>>>> +     * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
>>>> +     *   be acquired under acpi_dep_list_lock (held here)
>>>> +     * - the deferred work at boot stage is ensured to be finished
>>>> +     *   before entering init task by the async_synchronize_full()
>>>> +     *   barrier
>>>> +     *
>>>> +     * Use _nocall variant since it'll return on failure instead of
>>>> +     * run the function synchronously.
>>>>       */
>>>> -    queue_work(system_dfl_wq, &cdw->work);
>>>> +    if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))
>>>> +            return false;
>>>
>>> This really feels wrong to me, you are taking a code path that has been
>>> working for quite a while and changing it.  Perhaps your system ACPI
>>> tables are the thing that is incorrect here?
>>>
>>> What exactly is the problem that you are seeing?  Why not start with
>>> that and then we can work out how to solve that issue?
>>>
>>
>> two issues here we met (as briefly mentioned in the commit and cover letter):
>> 1. kernel panic due to userspace init cannot have an opened console. the
>>    console device scanning is queued in the system_dfl_wq in above code
>>    and not finished by the time userspace init process running, thus by
>>    the time userspace init running, no console is created
>> 2. entering rescue shell due to no root devices (PCIe nvme in our case)
>>    found. same reason as above, the PCIe host bridge scanning is queued
>>    in above and finished after init process running.
>>
>> The reason why these devices are created here is because they both depend
>> on riscv-aplic irqchip to serve their interrupts (console's wired
>> interrupt and PCI's INTx interrupts) and in order to keep the dependency
>> these devices are scanned and created after riscv-aplic initialized. The
>> riscv-aplic is initialized in device_initcall and invoke above codes for
>> the scan/creation of these devices, it's close to the time running
>> userspace init process. Since system_dfl_wq is used here and no synchronized
>> mechanism, the issues will happen if userspace init runs before these devices
>> are ready.
> 
> Well, there is flush_workqueue(), isn't it there?
> 

sure, of course. I implement it using async schedule but open to any
better ones. but..

>> Previous solution [1] is to advance the initialization of riscv-aplic
>> earlier but the order still cannot be guaranteed conceptually.
>> With async_schedule_dev_nocal() the work queued is finished
>> before entering userspace init since we'll wait for completion at
>> async_synchronize_full() before executing userspace init process.
>>
>> To solve the issue I think we should make these devices ready before
>> entering userspace and async schedule is one way to make it. It's also
>> using an unbound workqueue but have additional synchronization. Any
>> corrections or suggestions?
> 
> You can flush the dedicated workqueue at the same spot where you do
> async_synchronize_full(), can't you?
> 

the async_synchronize_full() is already there in the init code right
before entering usersapce [1] so if we use async schedule we don't
need to add synchronize spot ourselves. For a dedicated workqueue we
need to call flush_workqueue() explicitly somewhere (I suppose to be
the last level initcall like late_initcall_sync). Furthermore we need
to allocate it and I think not all the platforms need this piece of
code.

It seems no need to have a dedicated workqueue for this since async
schedule can satisfy the needs already (from my view). Except less
modifications can be made for this piece of code if we use a dedicated
workqueue, is this the consideration and mandatory?

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/init/main.c?h=v6.19-rc6#n1580

thanks.

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* Re: [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
  2026-01-22 13:48           ` Yicong Yang
@ 2026-01-22 13:57             ` Rafael J. Wysocki
  -1 siblings, 0 replies; 28+ messages in thread
From: Rafael J. Wysocki @ 2026-01-22 13:57 UTC (permalink / raw)
  To: Yicong Yang
  Cc: Rafael J. Wysocki, Greg KH, lenb, tglx, dakr, akpm, apatel, pjw,
	palmer, aou, alex, geshijian, weidong.wd, linux-acpi,
	linux-kernel, linux-riscv

On Thu, Jan 22, 2026 at 2:48 PM Yicong Yang <yang.yicong@picoheart.com> wrote:
>
> On 1/22/26 9:21 PM, Rafael J. Wysocki wrote:
> > On Thu, Jan 22, 2026 at 1:43 PM Yicong Yang <yang.yicong@picoheart.com> wrote:
> >>
> >> On 1/22/26 6:29 PM, Greg KH wrote:
> >>> On Thu, Jan 22, 2026 at 03:34:45PM +0800, Yicong Yang wrote:
> >>>> The device object rescan in acpi_scan_clear_dep_fn is scheduled
> >>>> in the system workqueue which is not guaranteed to be finished
> >>>> before entering userspace. This will cause the problem that
> >>>> some key devices are missed when the init task try to find them,
> >>>> e.g. console devices and root devices (PCIe nvme, etc).
> >>>> This issues is more possbile to happen on RISCV since these
> >>>> devices using GSI interrupt may depend on APLIC and will be
> >>>> scanned in acpi_scan_clear_dep_queue() after APLIC initialized.
> >>>>
> >>>> Fix this by scheduling the acpi_scan_clear_dep_queue() using async
> >>>> schedule function rather than the system workqueue. The deferred
> >>>> works will be synchronized by async_synchronize_full() before
> >>>> entering init task.
> >>>>
> >>>> Update the comment as well.
> >>>>
> >>>> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
> >>>> ---
> >>>>  drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
> >>>>  1 file changed, 16 insertions(+), 19 deletions(-)
> >>>>
> >>>> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> >>>> index 416d87f9bd10..bf0d8ba9ba19 100644
> >>>> --- a/drivers/acpi/scan.c
> >>>> +++ b/drivers/acpi/scan.c
> >>>> @@ -5,6 +5,7 @@
> >>>>
> >>>>  #define pr_fmt(fmt) "ACPI: " fmt
> >>>>
> >>>> +#include <linux/async.h>
> >>>>  #include <linux/module.h>
> >>>>  #include <linux/init.h>
> >>>>  #include <linux/slab.h>
> >>>> @@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
> >>>>      struct acpi_device *adev;
> >>>>  };
> >>>>
> >>>> -static void acpi_scan_clear_dep_fn(struct work_struct *work)
> >>>> +static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
> >>>>  {
> >>>> -    struct acpi_scan_clear_dep_work *cdw;
> >>>> -
> >>>> -    cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
> >>>> +    struct acpi_device *adev = to_acpi_device(dev);
> >>>>
> >>>>      acpi_scan_lock_acquire();
> >>>> -    acpi_bus_attach(cdw->adev, (void *)true);
> >>>> +    acpi_bus_attach(adev, (void *)true);
> >>>>      acpi_scan_lock_release();
> >>>>
> >>>> -    acpi_dev_put(cdw->adev);
> >>>> -    kfree(cdw);
> >>>> +    acpi_dev_put(adev);
> >>>>  }
> >>>>
> >>>>  static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
> >>>>  {
> >>>> -    struct acpi_scan_clear_dep_work *cdw;
> >>>> -
> >>>>      if (adev->dep_unmet)
> >>>>              return false;
> >>>>
> >>>> -    cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
> >>>> -    if (!cdw)
> >>>> -            return false;
> >>>> -
> >>>> -    cdw->adev = adev;
> >>>> -    INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
> >>>>      /*
> >>>> -     * Since the work function may block on the lock until the entire
> >>>> -     * initial enumeration of devices is complete, put it into the unbound
> >>>> -     * workqueue.
> >>>> +     * Async schedule the deferred acpi_scan_clear_dep_fn() since:
> >>>> +     * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
> >>>> +     *   be acquired under acpi_dep_list_lock (held here)
> >>>> +     * - the deferred work at boot stage is ensured to be finished
> >>>> +     *   before entering init task by the async_synchronize_full()
> >>>> +     *   barrier
> >>>> +     *
> >>>> +     * Use _nocall variant since it'll return on failure instead of
> >>>> +     * run the function synchronously.
> >>>>       */
> >>>> -    queue_work(system_dfl_wq, &cdw->work);
> >>>> +    if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))
> >>>> +            return false;
> >>>
> >>> This really feels wrong to me, you are taking a code path that has been
> >>> working for quite a while and changing it.  Perhaps your system ACPI
> >>> tables are the thing that is incorrect here?
> >>>
> >>> What exactly is the problem that you are seeing?  Why not start with
> >>> that and then we can work out how to solve that issue?
> >>>
> >>
> >> two issues here we met (as briefly mentioned in the commit and cover letter):
> >> 1. kernel panic due to userspace init cannot have an opened console. the
> >>    console device scanning is queued in the system_dfl_wq in above code
> >>    and not finished by the time userspace init process running, thus by
> >>    the time userspace init running, no console is created
> >> 2. entering rescue shell due to no root devices (PCIe nvme in our case)
> >>    found. same reason as above, the PCIe host bridge scanning is queued
> >>    in above and finished after init process running.
> >>
> >> The reason why these devices are created here is because they both depend
> >> on riscv-aplic irqchip to serve their interrupts (console's wired
> >> interrupt and PCI's INTx interrupts) and in order to keep the dependency
> >> these devices are scanned and created after riscv-aplic initialized. The
> >> riscv-aplic is initialized in device_initcall and invoke above codes for
> >> the scan/creation of these devices, it's close to the time running
> >> userspace init process. Since system_dfl_wq is used here and no synchronized
> >> mechanism, the issues will happen if userspace init runs before these devices
> >> are ready.
> >
> > Well, there is flush_workqueue(), isn't it there?
> >
>
> sure, of course. I implement it using async schedule but open to any
> better ones. but..
>
> >> Previous solution [1] is to advance the initialization of riscv-aplic
> >> earlier but the order still cannot be guaranteed conceptually.
> >> With async_schedule_dev_nocal() the work queued is finished
> >> before entering userspace init since we'll wait for completion at
> >> async_synchronize_full() before executing userspace init process.
> >>
> >> To solve the issue I think we should make these devices ready before
> >> entering userspace and async schedule is one way to make it. It's also
> >> using an unbound workqueue but have additional synchronization. Any
> >> corrections or suggestions?
> >
> > You can flush the dedicated workqueue at the same spot where you do
> > async_synchronize_full(), can't you?
> >
>
> the async_synchronize_full() is already there in the init code right
> before entering usersapce [1] so if we use async schedule we don't
> need to add synchronize spot ourselves. For a dedicated workqueue we
> need to call flush_workqueue() explicitly somewhere (I suppose to be
> the last level initcall like late_initcall_sync). Furthermore we need
> to allocate it and I think not all the platforms need this piece of
> code.
>
> It seems no need to have a dedicated workqueue for this since async
> schedule can satisfy the needs already (from my view). Except less
> modifications can be made for this piece of code if we use a dedicated
> workqueue, is this the consideration and mandatory?
>
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/init/main.c?h=v6.19-rc6#n1580

So please add the above information to the changelog of your patch
(that is, why it is better to use async for this than to use a
dedicated workqueue in your view) because it is kind of relevant.

And how does the second patch in the series depend on this one?

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

* Re: [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
@ 2026-01-22 13:57             ` Rafael J. Wysocki
  0 siblings, 0 replies; 28+ messages in thread
From: Rafael J. Wysocki @ 2026-01-22 13:57 UTC (permalink / raw)
  To: Yicong Yang
  Cc: Rafael J. Wysocki, Greg KH, lenb, tglx, dakr, akpm, apatel, pjw,
	palmer, aou, alex, geshijian, weidong.wd, linux-acpi,
	linux-kernel, linux-riscv

On Thu, Jan 22, 2026 at 2:48 PM Yicong Yang <yang.yicong@picoheart.com> wrote:
>
> On 1/22/26 9:21 PM, Rafael J. Wysocki wrote:
> > On Thu, Jan 22, 2026 at 1:43 PM Yicong Yang <yang.yicong@picoheart.com> wrote:
> >>
> >> On 1/22/26 6:29 PM, Greg KH wrote:
> >>> On Thu, Jan 22, 2026 at 03:34:45PM +0800, Yicong Yang wrote:
> >>>> The device object rescan in acpi_scan_clear_dep_fn is scheduled
> >>>> in the system workqueue which is not guaranteed to be finished
> >>>> before entering userspace. This will cause the problem that
> >>>> some key devices are missed when the init task try to find them,
> >>>> e.g. console devices and root devices (PCIe nvme, etc).
> >>>> This issues is more possbile to happen on RISCV since these
> >>>> devices using GSI interrupt may depend on APLIC and will be
> >>>> scanned in acpi_scan_clear_dep_queue() after APLIC initialized.
> >>>>
> >>>> Fix this by scheduling the acpi_scan_clear_dep_queue() using async
> >>>> schedule function rather than the system workqueue. The deferred
> >>>> works will be synchronized by async_synchronize_full() before
> >>>> entering init task.
> >>>>
> >>>> Update the comment as well.
> >>>>
> >>>> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
> >>>> ---
> >>>>  drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
> >>>>  1 file changed, 16 insertions(+), 19 deletions(-)
> >>>>
> >>>> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> >>>> index 416d87f9bd10..bf0d8ba9ba19 100644
> >>>> --- a/drivers/acpi/scan.c
> >>>> +++ b/drivers/acpi/scan.c
> >>>> @@ -5,6 +5,7 @@
> >>>>
> >>>>  #define pr_fmt(fmt) "ACPI: " fmt
> >>>>
> >>>> +#include <linux/async.h>
> >>>>  #include <linux/module.h>
> >>>>  #include <linux/init.h>
> >>>>  #include <linux/slab.h>
> >>>> @@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
> >>>>      struct acpi_device *adev;
> >>>>  };
> >>>>
> >>>> -static void acpi_scan_clear_dep_fn(struct work_struct *work)
> >>>> +static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
> >>>>  {
> >>>> -    struct acpi_scan_clear_dep_work *cdw;
> >>>> -
> >>>> -    cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
> >>>> +    struct acpi_device *adev = to_acpi_device(dev);
> >>>>
> >>>>      acpi_scan_lock_acquire();
> >>>> -    acpi_bus_attach(cdw->adev, (void *)true);
> >>>> +    acpi_bus_attach(adev, (void *)true);
> >>>>      acpi_scan_lock_release();
> >>>>
> >>>> -    acpi_dev_put(cdw->adev);
> >>>> -    kfree(cdw);
> >>>> +    acpi_dev_put(adev);
> >>>>  }
> >>>>
> >>>>  static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
> >>>>  {
> >>>> -    struct acpi_scan_clear_dep_work *cdw;
> >>>> -
> >>>>      if (adev->dep_unmet)
> >>>>              return false;
> >>>>
> >>>> -    cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
> >>>> -    if (!cdw)
> >>>> -            return false;
> >>>> -
> >>>> -    cdw->adev = adev;
> >>>> -    INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
> >>>>      /*
> >>>> -     * Since the work function may block on the lock until the entire
> >>>> -     * initial enumeration of devices is complete, put it into the unbound
> >>>> -     * workqueue.
> >>>> +     * Async schedule the deferred acpi_scan_clear_dep_fn() since:
> >>>> +     * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
> >>>> +     *   be acquired under acpi_dep_list_lock (held here)
> >>>> +     * - the deferred work at boot stage is ensured to be finished
> >>>> +     *   before entering init task by the async_synchronize_full()
> >>>> +     *   barrier
> >>>> +     *
> >>>> +     * Use _nocall variant since it'll return on failure instead of
> >>>> +     * run the function synchronously.
> >>>>       */
> >>>> -    queue_work(system_dfl_wq, &cdw->work);
> >>>> +    if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))
> >>>> +            return false;
> >>>
> >>> This really feels wrong to me, you are taking a code path that has been
> >>> working for quite a while and changing it.  Perhaps your system ACPI
> >>> tables are the thing that is incorrect here?
> >>>
> >>> What exactly is the problem that you are seeing?  Why not start with
> >>> that and then we can work out how to solve that issue?
> >>>
> >>
> >> two issues here we met (as briefly mentioned in the commit and cover letter):
> >> 1. kernel panic due to userspace init cannot have an opened console. the
> >>    console device scanning is queued in the system_dfl_wq in above code
> >>    and not finished by the time userspace init process running, thus by
> >>    the time userspace init running, no console is created
> >> 2. entering rescue shell due to no root devices (PCIe nvme in our case)
> >>    found. same reason as above, the PCIe host bridge scanning is queued
> >>    in above and finished after init process running.
> >>
> >> The reason why these devices are created here is because they both depend
> >> on riscv-aplic irqchip to serve their interrupts (console's wired
> >> interrupt and PCI's INTx interrupts) and in order to keep the dependency
> >> these devices are scanned and created after riscv-aplic initialized. The
> >> riscv-aplic is initialized in device_initcall and invoke above codes for
> >> the scan/creation of these devices, it's close to the time running
> >> userspace init process. Since system_dfl_wq is used here and no synchronized
> >> mechanism, the issues will happen if userspace init runs before these devices
> >> are ready.
> >
> > Well, there is flush_workqueue(), isn't it there?
> >
>
> sure, of course. I implement it using async schedule but open to any
> better ones. but..
>
> >> Previous solution [1] is to advance the initialization of riscv-aplic
> >> earlier but the order still cannot be guaranteed conceptually.
> >> With async_schedule_dev_nocal() the work queued is finished
> >> before entering userspace init since we'll wait for completion at
> >> async_synchronize_full() before executing userspace init process.
> >>
> >> To solve the issue I think we should make these devices ready before
> >> entering userspace and async schedule is one way to make it. It's also
> >> using an unbound workqueue but have additional synchronization. Any
> >> corrections or suggestions?
> >
> > You can flush the dedicated workqueue at the same spot where you do
> > async_synchronize_full(), can't you?
> >
>
> the async_synchronize_full() is already there in the init code right
> before entering usersapce [1] so if we use async schedule we don't
> need to add synchronize spot ourselves. For a dedicated workqueue we
> need to call flush_workqueue() explicitly somewhere (I suppose to be
> the last level initcall like late_initcall_sync). Furthermore we need
> to allocate it and I think not all the platforms need this piece of
> code.
>
> It seems no need to have a dedicated workqueue for this since async
> schedule can satisfy the needs already (from my view). Except less
> modifications can be made for this piece of code if we use a dedicated
> workqueue, is this the consideration and mandatory?
>
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/init/main.c?h=v6.19-rc6#n1580

So please add the above information to the changelog of your patch
(that is, why it is better to use async for this than to use a
dedicated workqueue in your view) because it is kind of relevant.

And how does the second patch in the series depend on this one?

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* Re: [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
  2026-01-22 13:57             ` Rafael J. Wysocki
@ 2026-01-22 16:27               ` Yicong Yang
  -1 siblings, 0 replies; 28+ messages in thread
From: Yicong Yang @ 2026-01-22 16:27 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: yang.yicong, Greg KH, lenb, tglx, dakr, akpm, apatel, pjw, palmer,
	aou, alex, geshijian, weidong.wd, linux-acpi, linux-kernel,
	linux-riscv

On 1/22/26 9:57 PM, Rafael J. Wysocki wrote:
> On Thu, Jan 22, 2026 at 2:48 PM Yicong Yang <yang.yicong@picoheart.com> wrote:
>>
>> On 1/22/26 9:21 PM, Rafael J. Wysocki wrote:
>>> On Thu, Jan 22, 2026 at 1:43 PM Yicong Yang <yang.yicong@picoheart.com> wrote:
>>>>
>>>> On 1/22/26 6:29 PM, Greg KH wrote:
>>>>> On Thu, Jan 22, 2026 at 03:34:45PM +0800, Yicong Yang wrote:
>>>>>> The device object rescan in acpi_scan_clear_dep_fn is scheduled
>>>>>> in the system workqueue which is not guaranteed to be finished
>>>>>> before entering userspace. This will cause the problem that
>>>>>> some key devices are missed when the init task try to find them,
>>>>>> e.g. console devices and root devices (PCIe nvme, etc).
>>>>>> This issues is more possbile to happen on RISCV since these
>>>>>> devices using GSI interrupt may depend on APLIC and will be
>>>>>> scanned in acpi_scan_clear_dep_queue() after APLIC initialized.
>>>>>>
>>>>>> Fix this by scheduling the acpi_scan_clear_dep_queue() using async
>>>>>> schedule function rather than the system workqueue. The deferred
>>>>>> works will be synchronized by async_synchronize_full() before
>>>>>> entering init task.
>>>>>>
>>>>>> Update the comment as well.
>>>>>>
>>>>>> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
>>>>>> ---
>>>>>>  drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
>>>>>>  1 file changed, 16 insertions(+), 19 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
>>>>>> index 416d87f9bd10..bf0d8ba9ba19 100644
>>>>>> --- a/drivers/acpi/scan.c
>>>>>> +++ b/drivers/acpi/scan.c
>>>>>> @@ -5,6 +5,7 @@
>>>>>>
>>>>>>  #define pr_fmt(fmt) "ACPI: " fmt
>>>>>>
>>>>>> +#include <linux/async.h>
>>>>>>  #include <linux/module.h>
>>>>>>  #include <linux/init.h>
>>>>>>  #include <linux/slab.h>
>>>>>> @@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
>>>>>>      struct acpi_device *adev;
>>>>>>  };
>>>>>>
>>>>>> -static void acpi_scan_clear_dep_fn(struct work_struct *work)
>>>>>> +static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
>>>>>>  {
>>>>>> -    struct acpi_scan_clear_dep_work *cdw;
>>>>>> -
>>>>>> -    cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
>>>>>> +    struct acpi_device *adev = to_acpi_device(dev);
>>>>>>
>>>>>>      acpi_scan_lock_acquire();
>>>>>> -    acpi_bus_attach(cdw->adev, (void *)true);
>>>>>> +    acpi_bus_attach(adev, (void *)true);
>>>>>>      acpi_scan_lock_release();
>>>>>>
>>>>>> -    acpi_dev_put(cdw->adev);
>>>>>> -    kfree(cdw);
>>>>>> +    acpi_dev_put(adev);
>>>>>>  }
>>>>>>
>>>>>>  static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
>>>>>>  {
>>>>>> -    struct acpi_scan_clear_dep_work *cdw;
>>>>>> -
>>>>>>      if (adev->dep_unmet)
>>>>>>              return false;
>>>>>>
>>>>>> -    cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
>>>>>> -    if (!cdw)
>>>>>> -            return false;
>>>>>> -
>>>>>> -    cdw->adev = adev;
>>>>>> -    INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
>>>>>>      /*
>>>>>> -     * Since the work function may block on the lock until the entire
>>>>>> -     * initial enumeration of devices is complete, put it into the unbound
>>>>>> -     * workqueue.
>>>>>> +     * Async schedule the deferred acpi_scan_clear_dep_fn() since:
>>>>>> +     * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
>>>>>> +     *   be acquired under acpi_dep_list_lock (held here)
>>>>>> +     * - the deferred work at boot stage is ensured to be finished
>>>>>> +     *   before entering init task by the async_synchronize_full()
>>>>>> +     *   barrier
>>>>>> +     *
>>>>>> +     * Use _nocall variant since it'll return on failure instead of
>>>>>> +     * run the function synchronously.
>>>>>>       */
>>>>>> -    queue_work(system_dfl_wq, &cdw->work);
>>>>>> +    if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))
>>>>>> +            return false;
>>>>>
>>>>> This really feels wrong to me, you are taking a code path that has been
>>>>> working for quite a while and changing it.  Perhaps your system ACPI
>>>>> tables are the thing that is incorrect here?
>>>>>
>>>>> What exactly is the problem that you are seeing?  Why not start with
>>>>> that and then we can work out how to solve that issue?
>>>>>
>>>>
>>>> two issues here we met (as briefly mentioned in the commit and cover letter):
>>>> 1. kernel panic due to userspace init cannot have an opened console. the
>>>>    console device scanning is queued in the system_dfl_wq in above code
>>>>    and not finished by the time userspace init process running, thus by
>>>>    the time userspace init running, no console is created
>>>> 2. entering rescue shell due to no root devices (PCIe nvme in our case)
>>>>    found. same reason as above, the PCIe host bridge scanning is queued
>>>>    in above and finished after init process running.
>>>>
>>>> The reason why these devices are created here is because they both depend
>>>> on riscv-aplic irqchip to serve their interrupts (console's wired
>>>> interrupt and PCI's INTx interrupts) and in order to keep the dependency
>>>> these devices are scanned and created after riscv-aplic initialized. The
>>>> riscv-aplic is initialized in device_initcall and invoke above codes for
>>>> the scan/creation of these devices, it's close to the time running
>>>> userspace init process. Since system_dfl_wq is used here and no synchronized
>>>> mechanism, the issues will happen if userspace init runs before these devices
>>>> are ready.
>>>
>>> Well, there is flush_workqueue(), isn't it there?
>>>
>>
>> sure, of course. I implement it using async schedule but open to any
>> better ones. but..
>>
>>>> Previous solution [1] is to advance the initialization of riscv-aplic
>>>> earlier but the order still cannot be guaranteed conceptually.
>>>> With async_schedule_dev_nocal() the work queued is finished
>>>> before entering userspace init since we'll wait for completion at
>>>> async_synchronize_full() before executing userspace init process.
>>>>
>>>> To solve the issue I think we should make these devices ready before
>>>> entering userspace and async schedule is one way to make it. It's also
>>>> using an unbound workqueue but have additional synchronization. Any
>>>> corrections or suggestions?
>>>
>>> You can flush the dedicated workqueue at the same spot where you do
>>> async_synchronize_full(), can't you?
>>>
>>
>> the async_synchronize_full() is already there in the init code right
>> before entering usersapce [1] so if we use async schedule we don't
>> need to add synchronize spot ourselves. For a dedicated workqueue we
>> need to call flush_workqueue() explicitly somewhere (I suppose to be
>> the last level initcall like late_initcall_sync). Furthermore we need
>> to allocate it and I think not all the platforms need this piece of
>> code.
>>
>> It seems no need to have a dedicated workqueue for this since async
>> schedule can satisfy the needs already (from my view). Except less
>> modifications can be made for this piece of code if we use a dedicated
>> workqueue, is this the consideration and mandatory?
>>
>> [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/init/main.c?h=v6.19-rc6#n1580
> 
> So please add the above information to the changelog of your patch
> (that is, why it is better to use async for this than to use a
> dedicated workqueue in your view) because it is kind of relevant.

sure. will add these in the commit in next version.

> 
> And how does the second patch in the series depend on this one?

these two are independent patches but to fix the same class of issue.
this one is for the real issue we met and the second one is a theoretical
possible issue found during discussion on my previous solution. I may
send them separately since the second one maybe not a problem in real case,
will wait for more feedback.

thanks.

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

* Re: [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn
@ 2026-01-22 16:27               ` Yicong Yang
  0 siblings, 0 replies; 28+ messages in thread
From: Yicong Yang @ 2026-01-22 16:27 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: yang.yicong, Greg KH, lenb, tglx, dakr, akpm, apatel, pjw, palmer,
	aou, alex, geshijian, weidong.wd, linux-acpi, linux-kernel,
	linux-riscv

On 1/22/26 9:57 PM, Rafael J. Wysocki wrote:
> On Thu, Jan 22, 2026 at 2:48 PM Yicong Yang <yang.yicong@picoheart.com> wrote:
>>
>> On 1/22/26 9:21 PM, Rafael J. Wysocki wrote:
>>> On Thu, Jan 22, 2026 at 1:43 PM Yicong Yang <yang.yicong@picoheart.com> wrote:
>>>>
>>>> On 1/22/26 6:29 PM, Greg KH wrote:
>>>>> On Thu, Jan 22, 2026 at 03:34:45PM +0800, Yicong Yang wrote:
>>>>>> The device object rescan in acpi_scan_clear_dep_fn is scheduled
>>>>>> in the system workqueue which is not guaranteed to be finished
>>>>>> before entering userspace. This will cause the problem that
>>>>>> some key devices are missed when the init task try to find them,
>>>>>> e.g. console devices and root devices (PCIe nvme, etc).
>>>>>> This issues is more possbile to happen on RISCV since these
>>>>>> devices using GSI interrupt may depend on APLIC and will be
>>>>>> scanned in acpi_scan_clear_dep_queue() after APLIC initialized.
>>>>>>
>>>>>> Fix this by scheduling the acpi_scan_clear_dep_queue() using async
>>>>>> schedule function rather than the system workqueue. The deferred
>>>>>> works will be synchronized by async_synchronize_full() before
>>>>>> entering init task.
>>>>>>
>>>>>> Update the comment as well.
>>>>>>
>>>>>> Signed-off-by: Yicong Yang <yang.yicong@picoheart.com>
>>>>>> ---
>>>>>>  drivers/acpi/scan.c | 35 ++++++++++++++++-------------------
>>>>>>  1 file changed, 16 insertions(+), 19 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
>>>>>> index 416d87f9bd10..bf0d8ba9ba19 100644
>>>>>> --- a/drivers/acpi/scan.c
>>>>>> +++ b/drivers/acpi/scan.c
>>>>>> @@ -5,6 +5,7 @@
>>>>>>
>>>>>>  #define pr_fmt(fmt) "ACPI: " fmt
>>>>>>
>>>>>> +#include <linux/async.h>
>>>>>>  #include <linux/module.h>
>>>>>>  #include <linux/init.h>
>>>>>>  #include <linux/slab.h>
>>>>>> @@ -2365,39 +2366,35 @@ struct acpi_scan_clear_dep_work {
>>>>>>      struct acpi_device *adev;
>>>>>>  };
>>>>>>
>>>>>> -static void acpi_scan_clear_dep_fn(struct work_struct *work)
>>>>>> +static void acpi_scan_clear_dep_fn(void *dev, async_cookie_t cookie)
>>>>>>  {
>>>>>> -    struct acpi_scan_clear_dep_work *cdw;
>>>>>> -
>>>>>> -    cdw = container_of(work, struct acpi_scan_clear_dep_work, work);
>>>>>> +    struct acpi_device *adev = to_acpi_device(dev);
>>>>>>
>>>>>>      acpi_scan_lock_acquire();
>>>>>> -    acpi_bus_attach(cdw->adev, (void *)true);
>>>>>> +    acpi_bus_attach(adev, (void *)true);
>>>>>>      acpi_scan_lock_release();
>>>>>>
>>>>>> -    acpi_dev_put(cdw->adev);
>>>>>> -    kfree(cdw);
>>>>>> +    acpi_dev_put(adev);
>>>>>>  }
>>>>>>
>>>>>>  static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
>>>>>>  {
>>>>>> -    struct acpi_scan_clear_dep_work *cdw;
>>>>>> -
>>>>>>      if (adev->dep_unmet)
>>>>>>              return false;
>>>>>>
>>>>>> -    cdw = kmalloc(sizeof(*cdw), GFP_KERNEL);
>>>>>> -    if (!cdw)
>>>>>> -            return false;
>>>>>> -
>>>>>> -    cdw->adev = adev;
>>>>>> -    INIT_WORK(&cdw->work, acpi_scan_clear_dep_fn);
>>>>>>      /*
>>>>>> -     * Since the work function may block on the lock until the entire
>>>>>> -     * initial enumeration of devices is complete, put it into the unbound
>>>>>> -     * workqueue.
>>>>>> +     * Async schedule the deferred acpi_scan_clear_dep_fn() since:
>>>>>> +     * - acpi_bus_attach() needs to hold acpi_scan_lock which cannot
>>>>>> +     *   be acquired under acpi_dep_list_lock (held here)
>>>>>> +     * - the deferred work at boot stage is ensured to be finished
>>>>>> +     *   before entering init task by the async_synchronize_full()
>>>>>> +     *   barrier
>>>>>> +     *
>>>>>> +     * Use _nocall variant since it'll return on failure instead of
>>>>>> +     * run the function synchronously.
>>>>>>       */
>>>>>> -    queue_work(system_dfl_wq, &cdw->work);
>>>>>> +    if (!async_schedule_dev_nocall(acpi_scan_clear_dep_fn, &adev->dev))
>>>>>> +            return false;
>>>>>
>>>>> This really feels wrong to me, you are taking a code path that has been
>>>>> working for quite a while and changing it.  Perhaps your system ACPI
>>>>> tables are the thing that is incorrect here?
>>>>>
>>>>> What exactly is the problem that you are seeing?  Why not start with
>>>>> that and then we can work out how to solve that issue?
>>>>>
>>>>
>>>> two issues here we met (as briefly mentioned in the commit and cover letter):
>>>> 1. kernel panic due to userspace init cannot have an opened console. the
>>>>    console device scanning is queued in the system_dfl_wq in above code
>>>>    and not finished by the time userspace init process running, thus by
>>>>    the time userspace init running, no console is created
>>>> 2. entering rescue shell due to no root devices (PCIe nvme in our case)
>>>>    found. same reason as above, the PCIe host bridge scanning is queued
>>>>    in above and finished after init process running.
>>>>
>>>> The reason why these devices are created here is because they both depend
>>>> on riscv-aplic irqchip to serve their interrupts (console's wired
>>>> interrupt and PCI's INTx interrupts) and in order to keep the dependency
>>>> these devices are scanned and created after riscv-aplic initialized. The
>>>> riscv-aplic is initialized in device_initcall and invoke above codes for
>>>> the scan/creation of these devices, it's close to the time running
>>>> userspace init process. Since system_dfl_wq is used here and no synchronized
>>>> mechanism, the issues will happen if userspace init runs before these devices
>>>> are ready.
>>>
>>> Well, there is flush_workqueue(), isn't it there?
>>>
>>
>> sure, of course. I implement it using async schedule but open to any
>> better ones. but..
>>
>>>> Previous solution [1] is to advance the initialization of riscv-aplic
>>>> earlier but the order still cannot be guaranteed conceptually.
>>>> With async_schedule_dev_nocal() the work queued is finished
>>>> before entering userspace init since we'll wait for completion at
>>>> async_synchronize_full() before executing userspace init process.
>>>>
>>>> To solve the issue I think we should make these devices ready before
>>>> entering userspace and async schedule is one way to make it. It's also
>>>> using an unbound workqueue but have additional synchronization. Any
>>>> corrections or suggestions?
>>>
>>> You can flush the dedicated workqueue at the same spot where you do
>>> async_synchronize_full(), can't you?
>>>
>>
>> the async_synchronize_full() is already there in the init code right
>> before entering usersapce [1] so if we use async schedule we don't
>> need to add synchronize spot ourselves. For a dedicated workqueue we
>> need to call flush_workqueue() explicitly somewhere (I suppose to be
>> the last level initcall like late_initcall_sync). Furthermore we need
>> to allocate it and I think not all the platforms need this piece of
>> code.
>>
>> It seems no need to have a dedicated workqueue for this since async
>> schedule can satisfy the needs already (from my view). Except less
>> modifications can be made for this piece of code if we use a dedicated
>> workqueue, is this the consideration and mandatory?
>>
>> [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/init/main.c?h=v6.19-rc6#n1580
> 
> So please add the above information to the changelog of your patch
> (that is, why it is better to use async for this than to use a
> dedicated workqueue in your view) because it is kind of relevant.

sure. will add these in the commit in next version.

> 
> And how does the second patch in the series depend on this one?

these two are independent patches but to fix the same class of issue.
this one is for the real issue we met and the second one is a theoretical
possible issue found during discussion on my previous solution. I may
send them separately since the second one maybe not a problem in real case,
will wait for more feedback.

thanks.

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

end of thread, other threads:[~2026-01-22 16:27 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-22  7:34 [PATCH 0/2] Ensure some device initialization before init task Yicong Yang
2026-01-22  7:34 ` Yicong Yang
2026-01-22  7:34 ` [PATCH 1/2] ACPI: scan: Use async schedule function for acpi_scan_clear_dep_fn Yicong Yang
2026-01-22  7:34   ` Yicong Yang
2026-01-22 10:29   ` Greg KH
2026-01-22 10:29     ` Greg KH
2026-01-22 12:43     ` Yicong Yang
2026-01-22 12:43       ` Yicong Yang
2026-01-22 13:21       ` Rafael J. Wysocki
2026-01-22 13:21         ` Rafael J. Wysocki
2026-01-22 13:48         ` Yicong Yang
2026-01-22 13:48           ` Yicong Yang
2026-01-22 13:57           ` Rafael J. Wysocki
2026-01-22 13:57             ` Rafael J. Wysocki
2026-01-22 16:27             ` Yicong Yang
2026-01-22 16:27               ` Yicong Yang
2026-01-22 11:19   ` Rafael J. Wysocki
2026-01-22 11:19     ` Rafael J. Wysocki
2026-01-22 12:50     ` Yicong Yang
2026-01-22 12:50       ` Yicong Yang
2026-01-22 13:22       ` Rafael J. Wysocki
2026-01-22 13:22         ` Rafael J. Wysocki
2026-01-22  7:34 ` [PATCH 2/2] init: Move console_on_rootfs after async_synchronize_full Yicong Yang
2026-01-22  7:34   ` Yicong Yang
2026-01-22 10:27   ` Greg KH
2026-01-22 10:27     ` Greg KH
2026-01-22 13:12     ` Yicong Yang
2026-01-22 13:12       ` Yicong Yang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.