On Fri, May 10, 2019 at 4:32 AM <zhe...@windriver.com> wrote:

> From: Liu Haitao <haitao....@windriver.com>
>
> The following call trace would be triggered as kmemleak is running.
>
> BUG: sleeping function called from invalid context at
> kernel/locking/rtmutex.c:974
> in_atomic(): 1, irqs_disabled(): 1, pid: 2401, name: kmemleak
> Preemption disabled at:
> [<ffffffff905f6271>] scan_block+0x31/0x120
> CPU: 12 PID: 247 Comm: kmemleak Tainted: G W 4.18.20-rt8-yocto-preempt-rt
> #1
> Hardware name: Intel Corp. Harcuvar/Server, BIOS
> HAVLCRB1.X64.0015.D62.1708310404 08/31/2017
> Call Trace:
> dump_stack+0x4f/0x6a
> ? scan_block+0x31/0x120
> ___might_sleep.cold.18+0xca/0xdb
> rt_spin_lock+0x37/0x60
> scan_block+0x9d/0x120
> scan_gray_list+0x108/0x170
> kmemleak_scan+0x230/0x460
> kmemleak_scan_thread+0x9d/0xba
> kthread+0x12c/0x150
> ? kmemleak_scan.cold.19+0x1b/0x1b
> ? kthread_flush_work_fn+0x20/0x20
> ret_from_fork+0x35/0x40
>
> The commit(41cf9e5bb14fbbf782e4191b792d3b898c130469) changed the
> kmemleak_lock
> to raw spinlock. However the kmemleak_object->lock is held after the
> kmemleak_lock is held in scan_block().
>
> scan_block()
>     |
>     raw_spin_lock_irqsave(&kmemleak_lock, flags)
>        |
>        spin_lock_nested(&object->lock, SINGLE_DEPTH_NESTING);
>
> In this case, the object->lock is implemented by mutex in RT. It could
> casue a sleeping  problem.
>
> Fixes: 41cf9e5bb14f ("kmemleak: Turn kmemleak_lock to raw spinlock on RT")
>
> Signed-off-by: Liu Haitao <haitao....@windriver.com>
>
> Rebase on top of latest RT code
>
> Signed-off-by: He Zhe <zhe...@windriver.com>
> ---
> This is just for v5.0 preempt-rt branches.
>
> kmemleak_lock is going to be changed to rcu in upstream, which would get
> rid of
> this error at the same time. But it'll cost some time. So for this moment
> it's
> worthing merging this patch.
>
>
Sounds good. I've gone ahead and merged it to the 5.0-rt branches.

Bruce



>  mm/kmemleak.c | 72
> +++++++++++++++++++++++++++++------------------------------
>  1 file changed, 36 insertions(+), 36 deletions(-)
>
> diff --git a/mm/kmemleak.c b/mm/kmemleak.c
> index b4036ff..00a7941 100644
> --- a/mm/kmemleak.c
> +++ b/mm/kmemleak.c
> @@ -148,7 +148,7 @@ struct kmemleak_scan_area {
>   * (use_count) and freed using the RCU mechanism.
>   */
>  struct kmemleak_object {
> -       spinlock_t lock;
> +       raw_spinlock_t lock;
>         unsigned int flags;             /* object status flags */
>         struct list_head object_list;
>         struct list_head gray_list;
> @@ -586,7 +586,7 @@ static struct kmemleak_object *create_object(unsigned
> long ptr, size_t size,
>         INIT_LIST_HEAD(&object->object_list);
>         INIT_LIST_HEAD(&object->gray_list);
>         INIT_HLIST_HEAD(&object->area_list);
> -       spin_lock_init(&object->lock);
> +       raw_spin_lock_init(&object->lock);
>         atomic_set(&object->use_count, 1);
>         object->flags = OBJECT_ALLOCATED;
>         object->pointer = ptr;
> @@ -668,9 +668,9 @@ static void __delete_object(struct kmemleak_object
> *object)
>          * Locking here also ensures that the corresponding memory block
>          * cannot be freed when it is being scanned.
>          */
> -       spin_lock_irqsave(&object->lock, flags);
> +       raw_spin_lock_irqsave(&object->lock, flags);
>         object->flags &= ~OBJECT_ALLOCATED;
> -       spin_unlock_irqrestore(&object->lock, flags);
> +       raw_spin_unlock_irqrestore(&object->lock, flags);
>         put_object(object);
>  }
>
> @@ -742,9 +742,9 @@ static void paint_it(struct kmemleak_object *object,
> int color)
>  {
>         unsigned long flags;
>
> -       spin_lock_irqsave(&object->lock, flags);
> +       raw_spin_lock_irqsave(&object->lock, flags);
>         __paint_it(object, color);
> -       spin_unlock_irqrestore(&object->lock, flags);
> +       raw_spin_unlock_irqrestore(&object->lock, flags);
>  }
>
>  static void paint_ptr(unsigned long ptr, int color)
> @@ -804,7 +804,7 @@ static void add_scan_area(unsigned long ptr, size_t
> size, gfp_t gfp)
>                 goto out;
>         }
>
> -       spin_lock_irqsave(&object->lock, flags);
> +       raw_spin_lock_irqsave(&object->lock, flags);
>         if (size == SIZE_MAX) {
>                 size = object->pointer + object->size - ptr;
>         } else if (ptr + size > object->pointer + object->size) {
> @@ -820,7 +820,7 @@ static void add_scan_area(unsigned long ptr, size_t
> size, gfp_t gfp)
>
>         hlist_add_head(&area->node, &object->area_list);
>  out_unlock:
> -       spin_unlock_irqrestore(&object->lock, flags);
> +       raw_spin_unlock_irqrestore(&object->lock, flags);
>  out:
>         put_object(object);
>  }
> @@ -843,9 +843,9 @@ static void object_set_excess_ref(unsigned long ptr,
> unsigned long excess_ref)
>                 return;
>         }
>
> -       spin_lock_irqsave(&object->lock, flags);
> +       raw_spin_lock_irqsave(&object->lock, flags);
>         object->excess_ref = excess_ref;
> -       spin_unlock_irqrestore(&object->lock, flags);
> +       raw_spin_unlock_irqrestore(&object->lock, flags);
>         put_object(object);
>  }
>
> @@ -865,9 +865,9 @@ static void object_no_scan(unsigned long ptr)
>                 return;
>         }
>
> -       spin_lock_irqsave(&object->lock, flags);
> +       raw_spin_lock_irqsave(&object->lock, flags);
>         object->flags |= OBJECT_NO_SCAN;
> -       spin_unlock_irqrestore(&object->lock, flags);
> +       raw_spin_unlock_irqrestore(&object->lock, flags);
>         put_object(object);
>  }
>
> @@ -928,11 +928,11 @@ static void early_alloc(struct early_log *log)
>                                log->min_count, GFP_ATOMIC);
>         if (!object)
>                 goto out;
> -       spin_lock_irqsave(&object->lock, flags);
> +       raw_spin_lock_irqsave(&object->lock, flags);
>         for (i = 0; i < log->trace_len; i++)
>                 object->trace[i] = log->trace[i];
>         object->trace_len = log->trace_len;
> -       spin_unlock_irqrestore(&object->lock, flags);
> +       raw_spin_unlock_irqrestore(&object->lock, flags);
>  out:
>         rcu_read_unlock();
>  }
> @@ -1122,9 +1122,9 @@ void __ref kmemleak_update_trace(const void *ptr)
>                 return;
>         }
>
> -       spin_lock_irqsave(&object->lock, flags);
> +       raw_spin_lock_irqsave(&object->lock, flags);
>         object->trace_len = __save_stack_trace(object->trace);
> -       spin_unlock_irqrestore(&object->lock, flags);
> +       raw_spin_unlock_irqrestore(&object->lock, flags);
>
>         put_object(object);
>  }
> @@ -1372,7 +1372,7 @@ static void scan_block(void *_start, void *_end,
>                  * previously acquired in scan_object(). These locks are
>                  * enclosed by scan_mutex.
>                  */
> -               spin_lock_nested(&object->lock, SINGLE_DEPTH_NESTING);
> +               raw_spin_lock_nested(&object->lock, SINGLE_DEPTH_NESTING);
>                 /* only pass surplus references (object already gray) */
>                 if (color_gray(object)) {
>                         excess_ref = object->excess_ref;
> @@ -1381,7 +1381,7 @@ static void scan_block(void *_start, void *_end,
>                         excess_ref = 0;
>                         update_refs(object);
>                 }
> -               spin_unlock(&object->lock);
> +               raw_spin_unlock(&object->lock);
>
>                 if (excess_ref) {
>                         object = lookup_object(excess_ref, 0);
> @@ -1390,9 +1390,9 @@ static void scan_block(void *_start, void *_end,
>                         if (object == scanned)
>                                 /* circular reference, ignore */
>                                 continue;
> -                       spin_lock_nested(&object->lock,
> SINGLE_DEPTH_NESTING);
> +                       raw_spin_lock_nested(&object->lock,
> SINGLE_DEPTH_NESTING);
>                         update_refs(object);
> -                       spin_unlock(&object->lock);
> +                       raw_spin_unlock(&object->lock);
>                 }
>         }
>         raw_spin_unlock_irqrestore(&kmemleak_lock, flags);
> @@ -1426,7 +1426,7 @@ static void scan_object(struct kmemleak_object
> *object)
>          * Once the object->lock is acquired, the corresponding memory
> block
>          * cannot be freed (the same lock is acquired in delete_object).
>          */
> -       spin_lock_irqsave(&object->lock, flags);
> +       raw_spin_lock_irqsave(&object->lock, flags);
>         if (object->flags & OBJECT_NO_SCAN)
>                 goto out;
>         if (!(object->flags & OBJECT_ALLOCATED))
> @@ -1445,9 +1445,9 @@ static void scan_object(struct kmemleak_object
> *object)
>                         if (start >= end)
>                                 break;
>
> -                       spin_unlock_irqrestore(&object->lock, flags);
> +                       raw_spin_unlock_irqrestore(&object->lock, flags);
>                         cond_resched();
> -                       spin_lock_irqsave(&object->lock, flags);
> +                       raw_spin_lock_irqsave(&object->lock, flags);
>                 } while (object->flags & OBJECT_ALLOCATED);
>         } else
>                 hlist_for_each_entry(area, &object->area_list, node)
> @@ -1455,7 +1455,7 @@ static void scan_object(struct kmemleak_object
> *object)
>                                    (void *)(area->start + area->size),
>                                    object);
>  out:
> -       spin_unlock_irqrestore(&object->lock, flags);
> +       raw_spin_unlock_irqrestore(&object->lock, flags);
>  }
>
>  /*
> @@ -1508,7 +1508,7 @@ static void kmemleak_scan(void)
>         /* prepare the kmemleak_object's */
>         rcu_read_lock();
>         list_for_each_entry_rcu(object, &object_list, object_list) {
> -               spin_lock_irqsave(&object->lock, flags);
> +               raw_spin_lock_irqsave(&object->lock, flags);
>  #ifdef DEBUG
>                 /*
>                  * With a few exceptions there should be a maximum of
> @@ -1525,7 +1525,7 @@ static void kmemleak_scan(void)
>                 if (color_gray(object) && get_object(object))
>                         list_add_tail(&object->gray_list, &gray_list);
>
> -               spin_unlock_irqrestore(&object->lock, flags);
> +               raw_spin_unlock_irqrestore(&object->lock, flags);
>         }
>         rcu_read_unlock();
>
> @@ -1598,14 +1598,14 @@ static void kmemleak_scan(void)
>          */
>         rcu_read_lock();
>         list_for_each_entry_rcu(object, &object_list, object_list) {
> -               spin_lock_irqsave(&object->lock, flags);
> +               raw_spin_lock_irqsave(&object->lock, flags);
>                 if (color_white(object) && (object->flags &
> OBJECT_ALLOCATED)
>                     && update_checksum(object) && get_object(object)) {
>                         /* color it gray temporarily */
>                         object->count = object->min_count;
>                         list_add_tail(&object->gray_list, &gray_list);
>                 }
> -               spin_unlock_irqrestore(&object->lock, flags);
> +               raw_spin_unlock_irqrestore(&object->lock, flags);
>         }
>         rcu_read_unlock();
>
> @@ -1625,7 +1625,7 @@ static void kmemleak_scan(void)
>          */
>         rcu_read_lock();
>         list_for_each_entry_rcu(object, &object_list, object_list) {
> -               spin_lock_irqsave(&object->lock, flags);
> +               raw_spin_lock_irqsave(&object->lock, flags);
>                 if (unreferenced_object(object) &&
>                     !(object->flags & OBJECT_REPORTED)) {
>                         object->flags |= OBJECT_REPORTED;
> @@ -1635,7 +1635,7 @@ static void kmemleak_scan(void)
>
>                         new_leaks++;
>                 }
> -               spin_unlock_irqrestore(&object->lock, flags);
> +               raw_spin_unlock_irqrestore(&object->lock, flags);
>         }
>         rcu_read_unlock();
>
> @@ -1787,10 +1787,10 @@ static int kmemleak_seq_show(struct seq_file *seq,
> void *v)
>         struct kmemleak_object *object = v;
>         unsigned long flags;
>
> -       spin_lock_irqsave(&object->lock, flags);
> +       raw_spin_lock_irqsave(&object->lock, flags);
>         if ((object->flags & OBJECT_REPORTED) &&
> unreferenced_object(object))
>                 print_unreferenced(seq, object);
> -       spin_unlock_irqrestore(&object->lock, flags);
> +       raw_spin_unlock_irqrestore(&object->lock, flags);
>         return 0;
>  }
>
> @@ -1820,9 +1820,9 @@ static int dump_str_object_info(const char *str)
>                 return -EINVAL;
>         }
>
> -       spin_lock_irqsave(&object->lock, flags);
> +       raw_spin_lock_irqsave(&object->lock, flags);
>         dump_object_info(object);
> -       spin_unlock_irqrestore(&object->lock, flags);
> +       raw_spin_unlock_irqrestore(&object->lock, flags);
>
>         put_object(object);
>         return 0;
> @@ -1841,11 +1841,11 @@ static void kmemleak_clear(void)
>
>         rcu_read_lock();
>         list_for_each_entry_rcu(object, &object_list, object_list) {
> -               spin_lock_irqsave(&object->lock, flags);
> +               raw_spin_lock_irqsave(&object->lock, flags);
>                 if ((object->flags & OBJECT_REPORTED) &&
>                     unreferenced_object(object))
>                         __paint_it(object, KMEMLEAK_GREY);
> -               spin_unlock_irqrestore(&object->lock, flags);
> +               raw_spin_unlock_irqrestore(&object->lock, flags);
>         }
>         rcu_read_unlock();
>
> --
> 2.7.4
>
> --
> _______________________________________________
> linux-yocto mailing list
> linux-yocto@yoctoproject.org
> https://lists.yoctoproject.org/listinfo/linux-yocto
>


-- 
- Thou shalt not follow the NULL pointer, for chaos and madness await thee
at its end
- "Use the force Harry" - Gandalf, Star Trek II
-- 
_______________________________________________
linux-yocto mailing list
linux-yocto@yoctoproject.org
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to