Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm/kmemleak: prevent soft lockup in first object iteration loop of kmemleak_scan()

The first RCU-based object iteration loop has to modify the object count.
So we cannot skip taking the object lock.

One way to avoid soft lockup is to insert occasional cond_resched() call
into the loop. This cannot be done while holding the RCU read lock which
is to protect objects from being freed. However, taking a reference to
the object will prevent it from being freed. We can then do a
cond_resched() call after every 64k objects safely.

Link: https://lkml.kernel.org/r/20220614220359.59282-4-longman@redhat.com
Signed-off-by: Waiman Long <longman@redhat.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Muchun Song <songmuchun@bytedance.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Waiman Long and committed by
akpm
6edda04c 64977918

+27 -1
+27 -1
mm/kmemleak.c
··· 1474 1474 struct zone *zone; 1475 1475 int __maybe_unused i; 1476 1476 int new_leaks = 0; 1477 + int loop1_cnt = 0; 1477 1478 1478 1479 jiffies_last_scan = jiffies; 1479 1480 1480 1481 /* prepare the kmemleak_object's */ 1481 1482 rcu_read_lock(); 1482 1483 list_for_each_entry_rcu(object, &object_list, object_list) { 1484 + bool obj_pinned = false; 1485 + 1486 + loop1_cnt++; 1483 1487 raw_spin_lock_irq(&object->lock); 1484 1488 #ifdef DEBUG 1485 1489 /* ··· 1509 1505 1510 1506 /* reset the reference count (whiten the object) */ 1511 1507 object->count = 0; 1512 - if (color_gray(object) && get_object(object)) 1508 + if (color_gray(object) && get_object(object)) { 1513 1509 list_add_tail(&object->gray_list, &gray_list); 1510 + obj_pinned = true; 1511 + } 1514 1512 1515 1513 raw_spin_unlock_irq(&object->lock); 1514 + 1515 + /* 1516 + * Do a cond_resched() to avoid soft lockup every 64k objects. 1517 + * Make sure a reference has been taken so that the object 1518 + * won't go away without RCU read lock. 1519 + */ 1520 + if (!(loop1_cnt & 0xffff)) { 1521 + if (!obj_pinned && !get_object(object)) { 1522 + /* Try the next object instead */ 1523 + loop1_cnt--; 1524 + continue; 1525 + } 1526 + 1527 + rcu_read_unlock(); 1528 + cond_resched(); 1529 + rcu_read_lock(); 1530 + 1531 + if (!obj_pinned) 1532 + put_object(object); 1533 + } 1516 1534 } 1517 1535 rcu_read_unlock(); 1518 1536