Re: [PATCH] rcu: Drop vmalloc memory info dump when double call_rcu()

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

 



>
> On Thu, Aug 17, 2023 at 2:34 AM Zqiang <qiang.zhang1211@xxxxxxxxx> wrote:
> >
> > Currently, for double invoke call_rcu(), will dump rcu_head objects
> > memory info, if the objects is not allocated from the slab allocator,
> > the vmalloc_dump_obj() will be invoke and the vmap_area_lock spinlock
> > need to be held, since the call_rcu() can be invoked in interrupt context,
> > therefore, there is a possibility of spinlock deadlock scenarios.
> >
> > And in Preempt-RT kernel, the rcutorture test also trigger the following
> > lockdep warning:
> >
> > BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:48
> > in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 1, name: swapper/0
> [...]
> >
> > The statistics about the source of 'rhp', the kmem_valid_obj() accounts
> > for more than 97.5%, and vmalloc accounts for less than 1%, this statistic
> > comes from leizhen. this commit therefore drop vmalloc_dump_obj() from
> > mem_dump_obj() and only check whether is vmalloc address.
> > Signed-off-by: Zqiang <qiang.zhang1211@xxxxxxxxx>
> > ---
> >  include/linux/vmalloc.h |  5 -----
> >  mm/util.c               |  7 +++----
> >  mm/vmalloc.c            | 14 --------------
> >  3 files changed, 3 insertions(+), 23 deletions(-)
> >
> > diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
> > index c720be70c8dd..d7c4e112a4ad 100644
> > --- a/include/linux/vmalloc.h
> > +++ b/include/linux/vmalloc.h
> > @@ -289,10 +289,5 @@ pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms)
> >  int register_vmap_purge_notifier(struct notifier_block *nb);
> >  int unregister_vmap_purge_notifier(struct notifier_block *nb);
> >
> > -#if defined(CONFIG_MMU) && defined(CONFIG_PRINTK)
> > -bool vmalloc_dump_obj(void *object);
> > -#else
> > -static inline bool vmalloc_dump_obj(void *object) { return false; }
> > -#endif
> >
> >  #endif /* _LINUX_VMALLOC_H */
> > diff --git a/mm/util.c b/mm/util.c
> > index ddfbb22dc187..fbc007adc108 100644
> > --- a/mm/util.c
> > +++ b/mm/util.c
> > @@ -1066,10 +1066,9 @@ void mem_dump_obj(void *object)
> >         if (kmem_dump_obj(object))
> >                 return;
> >
> > -       if (vmalloc_dump_obj(object))
> > -               return;
> > -
> > -       if (virt_addr_valid(object))
> > +       if (is_vmalloc_addr(object))
> > +               type = "vmalloc memory";
> > +       else if (virt_addr_valid(object))
> >                 type = "non-slab/vmalloc memory";
> >         else if (object == NULL)
> >                 type = "NULL pointer";
> > diff --git a/mm/vmalloc.c b/mm/vmalloc.c
> > index 93cf99aba335..224af955bcb5 100644
> > --- a/mm/vmalloc.c
> > +++ b/mm/vmalloc.c
> > @@ -4271,20 +4271,6 @@ void pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms)
> >  }
> >  #endif /* CONFIG_SMP */
> >
> > -#ifdef CONFIG_PRINTK
> > -bool vmalloc_dump_obj(void *object)
> > -{
> > -       struct vm_struct *vm;
> > -       void *objp = (void *)PAGE_ALIGN((unsigned long)object);
> > -
> > -       vm = find_vm_area(objp);
>
> What about adding something like the following to vmalloc.c. Would it work?
>
> +static struct vmap_area *find_vmap_area_trylock(unsigned long addr)
> +{
> +       struct vmap_area *va;
> +
> +       if (!spin_trylock(&vmap_area_lock))
> +               return NULL;
> +       va = __find_vmap_area(addr);
> +       spin_unlock(&vmap_area_lock);
> +
> +       return va;
> +}
>
> and call it from vmalloc_dump_obj():
>
> vm = find_vm_area_trylock(objp);
>
> And then keep the rest of your patch as it is but add back the call to
> vmalloc_dump_obj() in mem_dump_obj():
>
>        if (vmalloc_dump_obj(object))
>                return;
>
>  -       if (virt_addr_valid(object))
>  +       if (is_vmalloc_addr(object))
>  +               type = "vmalloc memory";
>  +       else if (virt_addr_valid(object))
>                  type = "non-slab/vmalloc memory";
>
>
> If that still throws "sleeping function called" type warnings, then
> that is a preempt RT issue because spin_trylock() on conversion to a
> sleeping lock should not be sleeping as it is uncontended.
>

Hello, Joel

I did a test in the RT kernel with the following modifications, and
didn't trigger
sleeping function called warning.


diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 93cf99aba335..e07b0e34249b 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -4272,12 +4272,24 @@ void pcpu_free_vm_areas(struct vm_struct
**vms, int nr_vms)
 #endif /* CONFIG_SMP */

 #ifdef CONFIG_PRINTK
+static struct vm_struct *find_vmap_area_trylock(unsigned long addr)
+{
+       struct vmap_area *va;
+
+       if (!spin_trylock(&vmap_area_lock))
+               return NULL;
+       va = __find_vmap_area(addr, &vmap_area_root);
+       spin_unlock(&vmap_area_lock);
+
+       return va ? va->vm : NULL;
+}
+
 bool vmalloc_dump_obj(void *object)
 {
        struct vm_struct *vm;
        void *objp = (void *)PAGE_ALIGN((unsigned long)object);

-       vm = find_vm_area(objp);
+       vm = find_vmap_area_trylock((unsigned long)objp);
        if (!vm)
                return false;
        pr_cont(" %u-page vmalloc region starting at %#lx allocated at %pS\n",


If double call_rcu() appears in different threads at the same time,
It is possible to dump only one of the vmalloc information.


Thanks
Zqiang


>
> But I could be missing something and I'll look more later. But for now
> off to pick up a rental car here...
>
> thanks,
>
>   - Joel




[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux