我正在开发嵌入式 Linux 系统(kernel-5.10.24),我试图了解 kmemleak 是如何工作的。
根据文档,kmemleak扫描数据段,检查是否存在未引用的内存,内核代码如下,
kmemleak_scan()
/*
* Struct page scanning for each node.
*/
get_online_mems();
for_each_populated_zone(zone) {
unsigned long start_pfn = zone->zone_start_pfn;
unsigned long end_pfn = zone_end_pfn(zone);
unsigned long pfn;
for (pfn = start_pfn; pfn < end_pfn; pfn++) {
struct page *page = pfn_to_online_page(pfn);
if (!page)
continue;
/* only scan pages belonging to this zone */
if (page_zone(page) != zone)
continue;
/* only scan if page is in use */
if (page_count(page) == 0)
continue;
scan_block(page, page + 1, NULL);
if (!(pfn & 63))
cond_resched();
}
}
put_online_mems();
它获取指向每个 PFN 的指针struct page
,并将其传递给scan_block
。
还有scan_block()
/*
* Scan a memory block (exclusive range) for valid pointers and add those
* found to the gray list.
*/
static void scan_block(void *_start, void *_end,
struct kmemleak_object *scanned)
{
unsigned long *ptr;
unsigned long *start = PTR_ALIGN(_start, BYTES_PER_POINTER);
unsigned long *end = _end - (BYTES_PER_POINTER - 1);
unsigned long flags;
unsigned long untagged_ptr;
raw_spin_lock_irqsave(&kmemleak_lock, flags);
for (ptr = start; ptr < end; ptr++) {
struct kmemleak_object *object;
unsigned long pointer;
unsigned long excess_ref;
if (scan_should_stop())
break;
kasan_disable_current();
pointer = *ptr; ///// ?????
kasan_enable_current();
untagged_ptr = (unsigned long)kasan_reset_tag((void *)pointer);
if (untagged_ptr < min_addr || untagged_ptr >= max_addr)
continue;
/*
* No need for get_object() here since we hold kmemleak_lock.
* object->use_count cannot be dropped to 0 while the object
* is still present in object_tree_root and object_list
* (with updates protected by kmemleak_lock).
*/
object = lookup_object(pointer, 1);
指向的指针struct page
被转换为unsigned long *
,并取消引用 ,unsigned long *
以获取 来pointer
作为要检查的内存地址。
我的困惑来自于取消引用指向 的指针struct page
,它是描述 PFN 的结构。为什么解引用可以得到内存地址,而不是结构页呢?
在我的系统中, 的大小struct page
为 32 字节,因此page+1
仅page+0x20
而不是增加 page_size (0x1000)。
答案1
指向struct page的指针是一个内存地址。例如。 0x00a0000。page+1
是另一个地址,比如 0x00a0020。
然后这个函数只是扫描从 0x00a000 到 0x00a0020 的所有“潜在”内存指针。struct page
除了假设指针以某种方式对齐之外,它对 的格式一无所知。