<IRQ> __init_work+0x2d/0x50 synchronize_rcu_expedited+0x3af/0x650 bdi_remove_from_list [inline] bdi_unregister+0x17f/0x5c0 release_bdi+0xa1/0xc0 kref_put [inline] bdi_put+0x72/0xa0 bdev_free_inode+0x11e/0x220 i_callback+0x3f/0x70 rcu_do_batch [inline] rcu_core+0x76d/0x16c0 __do_softirq+0x1d7/0x93b invoke_softirq [inline] __irq_exit_rcu [inline] irq_exit_rcu+0xf2/0x130 sysvec_apic_timer_interrupt+0x93/0xc0 The bdi_remove_from_list() is called in RCU softirq, however the synchronize_rcu_expedited() will produce sleep action, use kfree_rcu() instead of it. Reported-by: Hao Sun <sunhao.th@xxxxxxxxx> Signed-off-by: Zqiang <qiang.zhang1211@xxxxxxxxx> --- include/linux/backing-dev-defs.h | 1 + mm/backing-dev.c | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h index 33207004cfde..35a093384518 100644 --- a/include/linux/backing-dev-defs.h +++ b/include/linux/backing-dev-defs.h @@ -202,6 +202,7 @@ struct backing_dev_info { #ifdef CONFIG_DEBUG_FS struct dentry *debug_dir; #endif + struct rcu_head rcu; }; enum { diff --git a/mm/backing-dev.c b/mm/backing-dev.c index c878d995af06..45d866a3a4a2 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -935,8 +935,6 @@ static void bdi_remove_from_list(struct backing_dev_info *bdi) rb_erase(&bdi->rb_node, &bdi_tree); list_del_rcu(&bdi->bdi_list); spin_unlock_bh(&bdi_lock); - - synchronize_rcu_expedited(); } void bdi_unregister(struct backing_dev_info *bdi) @@ -969,7 +967,7 @@ static void release_bdi(struct kref *ref) bdi_unregister(bdi); WARN_ON_ONCE(bdi->dev); wb_exit(&bdi->wb); - kfree(bdi); + kfree_rcu(bdi, rcu); } void bdi_put(struct backing_dev_info *bdi) -- 2.17.1