Matthew Wilcox <willy@xxxxxxxxxxxxx> 于2021年10月14日周四 下午7:26写道:
On Thu, Oct 14, 2021 at 04:24:33PM +0800, Zqiang wrote:
> 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;
> };
>Instead of growing struct backing_dev_info, it seems to me this rcu_head
>could be placed in a union with rb_node, since it will have been removed
>from the bdi_tree by this point and the tree is never walked under
>RCU protection?
Thanks for your advice, I find this bdi_tree is traversed under the protection of a spin lock, not under the protection of RCU.I find this modification does not avoid the problem described in patch, the flush_delayed_work() may be called in release_bdi()The same will cause problems.
may be we can replace queue_rcu_work() of call_rcu(&inode->i_rcu, i_callback) or do you have any better suggestions?
ThanksZqiang
diff --git a/fs/inode.c b/fs/inode.c
index a49695f57e1e..300beb19aed6 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -219,9 +219,9 @@ void free_inode_nonrcu(struct inode *inode)
}
EXPORT_SYMBOL(free_inode_nonrcu);
-static void i_callback(struct rcu_head *head)
+static void i_callback(struct work_struct *work)
{
- struct inode *inode = container_of(head, struct inode,
i_rcu);
+ struct inode *inode = container_of(to_rcu_work(work),
struct inode, rwork);
if (inode->free_inode)
inode->free_inode(inode);
else
@@ -248,7 +248,7 @@ static struct inode *alloc_inode(struct
super_block *sb)
return NULL;
}
inode->free_inode = ops->free_inode;
- i_callback(&inode->i_rcu);
+ i_callback(&inode->rwork.work);
return NULL;
}
@@ -289,7 +289,8 @@ static void destroy_inode(struct inode *inode)
return;
}
inode->free_inode = ops->free_inode;
- call_rcu(&inode->i_rcu, i_callback);
+ INIT_RCU_WORK(&inode->rwork, i_callback);
+ queue_rcu_work(system_wq, &inode->rwork);
}
/**
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 8903a95611a2..006d769791a8 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -686,7 +686,7 @@ struct inode {
struct list_head i_wb_list; /* backing dev
writeback list */
union {
struct hlist_head i_dentry;
- struct rcu_head i_rcu;
+ struct rcu_work rwork;
};
atomic64_t i_version;
atomic64_t i_sequence; /* see futex */