저는 임베디드 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_size page+1
만 page+0x20
증가합니다(0x1000).
답변1
구조체 페이지에 대한 포인터는 메모리 주소입니다. 예를 들어. 0x00a0000. page+1
0x00a0020과 같은 다른 주소입니다.
그런 다음 이 함수는 0x00a000에서 0x00a0020까지 모든 "잠재적인" 메모리 포인터를 검색합니다. struct page
포인터가 특정 방식으로 정렬되어 있다고 가정하는 것 외에는 형식에 대해 아무것도 모릅니다.