diff mbox series

init: Initialize noop_backing_dev_info early

Message ID 20220615214815.6901-1-jack@suse.cz (mailing list archive)
State New
Headers show
Series init: Initialize noop_backing_dev_info early | expand

Commit Message

Jan Kara June 15, 2022, 9:48 p.m. UTC
noop_backing_dev_info is used by superblocks of various
pseudofilesystems such as kdevtmpfs. After commit 10e14073107d
("writeback: Fix inode->i_io_list not be protected by inode->i_lock
error") this broke because __mark_inode_dirty() started to access more
fields from noop_backing_dev_info and this led to crashes inside
locked_inode_to_wb_and_lock_list() called from __mark_inode_dirty().
Fix the problem by initializing noop_backing_dev_info before the
filesystems get mounted.

Fixes: 10e14073107d ("writeback: Fix inode->i_io_list not be protected by inode->i_lock error")
Reported-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Reported-and-tested-by: Alexandru Elisei <alexandru.elisei@arm.com>
Reported-and-tested-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Jan Kara <jack@suse.cz>
---
 drivers/base/init.c         |  2 ++
 include/linux/backing-dev.h |  2 ++
 mm/backing-dev.c            | 11 ++---------
 3 files changed, 6 insertions(+), 9 deletions(-)

Since this bug prevents some machines from booting, I plan to push this patch
to Linus unless someone objects soon... Review is welcome :).

Comments

Christoph Hellwig June 16, 2022, 6:08 a.m. UTC | #1
On Wed, Jun 15, 2022 at 11:48:15PM +0200, Jan Kara wrote:
> +extern int bdi_init(struct backing_dev_info *bdi);

No need for the extern.

Otherwise looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>

And this remind me that I really want to kill noop_backing_dev_info
and just use a NULL bdi for this case eventually..
Suzuki K Poulose June 16, 2022, 8:10 a.m. UTC | #2
On 15/06/2022 22:48, Jan Kara wrote:
> noop_backing_dev_info is used by superblocks of various
> pseudofilesystems such as kdevtmpfs. After commit 10e14073107d
> ("writeback: Fix inode->i_io_list not be protected by inode->i_lock
> error") this broke because __mark_inode_dirty() started to access more
> fields from noop_backing_dev_info and this led to crashes inside
> locked_inode_to_wb_and_lock_list() called from __mark_inode_dirty().
> Fix the problem by initializing noop_backing_dev_info before the
> filesystems get mounted.
> 
> Fixes: 10e14073107d ("writeback: Fix inode->i_io_list not be protected by inode->i_lock error")
> Reported-by: Suzuki K Poulose <suzuki.poulose@arm.com>
> Reported-and-tested-by: Alexandru Elisei <alexandru.elisei@arm.com>
> Reported-and-tested-by: Guenter Roeck <linux@roeck-us.net>
> Signed-off-by: Jan Kara <jack@suse.cz>

Works for me too. Thanks for the proper fix


Tested-by: Suzuki K Poulose <suzuki.poulose@arm.com>


> ---
>   drivers/base/init.c         |  2 ++
>   include/linux/backing-dev.h |  2 ++
>   mm/backing-dev.c            | 11 ++---------
>   3 files changed, 6 insertions(+), 9 deletions(-)
> 
> Since this bug prevents some machines from booting, I plan to push this patch
> to Linus unless someone objects soon... Review is welcome :).
> 
> diff --git a/drivers/base/init.c b/drivers/base/init.c
> index d8d0fe687111..397eb9880cec 100644
> --- a/drivers/base/init.c
> +++ b/drivers/base/init.c
> @@ -8,6 +8,7 @@
>   #include <linux/init.h>
>   #include <linux/memory.h>
>   #include <linux/of.h>
> +#include <linux/backing-dev.h>
>   
>   #include "base.h"
>   
> @@ -20,6 +21,7 @@
>   void __init driver_init(void)
>   {
>   	/* These are the core pieces */
> +	bdi_init(&noop_backing_dev_info);
>   	devtmpfs_init();
>   	devices_init();
>   	buses_init();
> diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
> index 2bd073fa6bb5..f0baef68f90f 100644
> --- a/include/linux/backing-dev.h
> +++ b/include/linux/backing-dev.h
> @@ -119,6 +119,8 @@ int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned int max_ratio);
>   
>   extern struct backing_dev_info noop_backing_dev_info;
>   
> +extern int bdi_init(struct backing_dev_info *bdi);
> +
>   /**
>    * writeback_in_progress - determine whether there is writeback in progress
>    * @wb: bdi_writeback of interest
> diff --git a/mm/backing-dev.c b/mm/backing-dev.c
> index ff60bd7d74e0..95550b8fa7fe 100644
> --- a/mm/backing-dev.c
> +++ b/mm/backing-dev.c
> @@ -231,20 +231,13 @@ static __init int bdi_class_init(void)
>   }
>   postcore_initcall(bdi_class_init);
>   
> -static int bdi_init(struct backing_dev_info *bdi);
> -
>   static int __init default_bdi_init(void)
>   {
> -	int err;
> -
>   	bdi_wq = alloc_workqueue("writeback", WQ_MEM_RECLAIM | WQ_UNBOUND |
>   				 WQ_SYSFS, 0);
>   	if (!bdi_wq)
>   		return -ENOMEM;
> -
> -	err = bdi_init(&noop_backing_dev_info);
> -
> -	return err;
> +	return 0;
>   }
>   subsys_initcall(default_bdi_init);
>   
> @@ -781,7 +774,7 @@ static void cgwb_remove_from_bdi_list(struct bdi_writeback *wb)
>   
>   #endif	/* CONFIG_CGROUP_WRITEBACK */
>   
> -static int bdi_init(struct backing_dev_info *bdi)
> +int bdi_init(struct backing_dev_info *bdi)
>   {
>   	int ret;
>
Jan Kara June 16, 2022, 9 a.m. UTC | #3
On Wed 15-06-22 23:08:22, Christoph Hellwig wrote:
> On Wed, Jun 15, 2022 at 11:48:15PM +0200, Jan Kara wrote:
> > +extern int bdi_init(struct backing_dev_info *bdi);
> 
> No need for the extern.

Yes, fixed up.

> Otherwise looks good:
> 
> Reviewed-by: Christoph Hellwig <hch@lst.de>

Thanks for review!

> And this remind me that I really want to kill noop_backing_dev_info
> and just use a NULL bdi for this case eventually..

Yes, I'm just not sure whether the checks for bdi / wb being NULL in lots
of places will not be too annoying... But maybe you'll be able to come up
with some wrappers that will make things bearable.

								Honza
diff mbox series

Patch

diff --git a/drivers/base/init.c b/drivers/base/init.c
index d8d0fe687111..397eb9880cec 100644
--- a/drivers/base/init.c
+++ b/drivers/base/init.c
@@ -8,6 +8,7 @@ 
 #include <linux/init.h>
 #include <linux/memory.h>
 #include <linux/of.h>
+#include <linux/backing-dev.h>
 
 #include "base.h"
 
@@ -20,6 +21,7 @@ 
 void __init driver_init(void)
 {
 	/* These are the core pieces */
+	bdi_init(&noop_backing_dev_info);
 	devtmpfs_init();
 	devices_init();
 	buses_init();
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index 2bd073fa6bb5..f0baef68f90f 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -119,6 +119,8 @@  int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned int max_ratio);
 
 extern struct backing_dev_info noop_backing_dev_info;
 
+extern int bdi_init(struct backing_dev_info *bdi);
+
 /**
  * writeback_in_progress - determine whether there is writeback in progress
  * @wb: bdi_writeback of interest
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index ff60bd7d74e0..95550b8fa7fe 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -231,20 +231,13 @@  static __init int bdi_class_init(void)
 }
 postcore_initcall(bdi_class_init);
 
-static int bdi_init(struct backing_dev_info *bdi);
-
 static int __init default_bdi_init(void)
 {
-	int err;
-
 	bdi_wq = alloc_workqueue("writeback", WQ_MEM_RECLAIM | WQ_UNBOUND |
 				 WQ_SYSFS, 0);
 	if (!bdi_wq)
 		return -ENOMEM;
-
-	err = bdi_init(&noop_backing_dev_info);
-
-	return err;
+	return 0;
 }
 subsys_initcall(default_bdi_init);
 
@@ -781,7 +774,7 @@  static void cgwb_remove_from_bdi_list(struct bdi_writeback *wb)
 
 #endif	/* CONFIG_CGROUP_WRITEBACK */
 
-static int bdi_init(struct backing_dev_info *bdi)
+int bdi_init(struct backing_dev_info *bdi)
 {
 	int ret;