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