Skip to content

Commit f2f20b3

Browse files
Gu Bowenopsiff
authored andcommitted
mm: fix possible deadlock in kmemleak
commit c873ccb upstream. There are some AA deadlock issues in kmemleak, similar to the situation reported by Breno [1]. The deadlock path is as follows: mem_pool_alloc() -> raw_spin_lock_irqsave(&kmemleak_lock, flags); -> pr_warn() -> netconsole subsystem -> netpoll -> __alloc_skb -> __create_object -> raw_spin_lock_irqsave(&kmemleak_lock, flags); To solve this problem, switch to printk_safe mode before printing warning message, this will redirect all printk()-s to a special per-CPU buffer, which will be flushed later from a safe context (irq work), and this deadlock problem can be avoided. The proper API to use should be printk_deferred_enter()/printk_deferred_exit() [2]. Another way is to place the warn print after kmemleak is released. Link: https://lkml.kernel.org/r/[email protected] Link: https://lore.kernel.org/all/[email protected]/#t [1] Link: https://lore.kernel.org/all/[email protected]/ [2] Signed-off-by: Gu Bowen <[email protected]> Reviewed-by: Waiman Long <[email protected]> Reviewed-by: Catalin Marinas <[email protected]> Reviewed-by: Breno Leitao <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Cc: John Ogness <[email protected]> Cc: Lu Jialin <[email protected]> Cc: Petr Mladek <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]> (cherry picked from commit cd0236550cf80d47c8beeb2917a6aa7cf6a77b9a)
1 parent a22ef60 commit f2f20b3

File tree

1 file changed

+20
-7
lines changed

1 file changed

+20
-7
lines changed

mm/kmemleak.c

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -432,9 +432,15 @@ static struct kmemleak_object *__lookup_object(unsigned long ptr, int alias,
432432
else if (untagged_objp == untagged_ptr || alias)
433433
return object;
434434
else {
435+
/*
436+
* Printk deferring due to the kmemleak_lock held.
437+
* This is done to avoid deadlock.
438+
*/
439+
printk_deferred_enter();
435440
kmemleak_warn("Found object by alias at 0x%08lx\n",
436441
ptr);
437442
dump_object_info(object);
443+
printk_deferred_exit();
438444
break;
439445
}
440446
}
@@ -731,13 +737,19 @@ static int __link_object(struct kmemleak_object *object, unsigned long ptr,
731737
else if (untagged_objp + parent->size <= untagged_ptr)
732738
link = &parent->rb_node.rb_right;
733739
else {
740+
/*
741+
* Printk deferring due to the kmemleak_lock held.
742+
* This is done to avoid deadlock.
743+
*/
744+
printk_deferred_enter();
734745
kmemleak_stop("Cannot insert 0x%lx into the object search tree (overlaps existing)\n",
735746
ptr);
736747
/*
737748
* No need for parent->lock here since "parent" cannot
738749
* be freed while the kmemleak_lock is held.
739750
*/
740751
dump_object_info(parent);
752+
printk_deferred_exit();
741753
return -EEXIST;
742754
}
743755
}
@@ -851,13 +863,8 @@ static void delete_object_part(unsigned long ptr, size_t size,
851863

852864
raw_spin_lock_irqsave(&kmemleak_lock, flags);
853865
object = __find_and_remove_object(ptr, 1, objflags);
854-
if (!object) {
855-
#ifdef DEBUG
856-
kmemleak_warn("Partially freeing unknown object at 0x%08lx (size %zu)\n",
857-
ptr, size);
858-
#endif
866+
if (!object)
859867
goto unlock;
860-
}
861868

862869
/*
863870
* Create one or two objects that may result from the memory block
@@ -877,8 +884,14 @@ static void delete_object_part(unsigned long ptr, size_t size,
877884

878885
unlock:
879886
raw_spin_unlock_irqrestore(&kmemleak_lock, flags);
880-
if (object)
887+
if (object) {
881888
__delete_object(object);
889+
} else {
890+
#ifdef DEBUG
891+
kmemleak_warn("Partially freeing unknown object at 0x%08lx (size %zu)\n",
892+
ptr, size);
893+
#endif
894+
}
882895

883896
out:
884897
if (object_l)

0 commit comments

Comments
 (0)