Re: [PATCH] mm: backing-dev: use kfree_rcu() instead of synchronize_rcu_expedited()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On 2021/10/15 上午10:57, Qiang Zhang wrote:


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?

Thanks
Zqiang
 


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 */


[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux