Where The Structure "Struct Page" Is Stored on The Linux Kernel

Where are struct page* initialized in Linux?

Maybe try mm_init, called by start_kernel() in /init/main.c/ and the corresponding mem_init in /arch/x86/mm/init_64.c :

void __init mem_init(void)
1286 {
1287 pci_iommu_alloc();
1288
1289 /* clear_bss() already clear the empty_zero_page */
1290
1291 /* this will put all memory onto the freelists */
1292 memblock_free_all();
1293 after_bootmem = 1;
1294 x86_init.hyper.init_after_bootmem();
1295
1296 /*
1297 * Must be done after boot memory is put on freelist, because here we
1298 * might set fields in deferred struct pages that have not yet been
1299 * initialized, and memblock_free_all() initializes all the reserved
1300 * deferred pages for us.
1301 */
1302 register_page_bootmem_info();

Details for PTE and struct page

when an userspace process accesses to some virtual address, the MMU tries to find the PTE for the requested virtual address

Yes, this is correct. The page table is walked down to the specific PTE (if any).

In the PTE there is the encoded struct page's PFN and some flags.

Not really. The PTE contains the PFN (Page Frame Number) of the actual physical memory page that the virtual address translates to. In other words, it points to the actual page in physical memory, not to the corresponding struct page.

if the translated address points to a struct page, how exactly is physical memory is accessed? I think struct page is just page descriptor, not a empty physical memory region.

The translated address does not point to a struct page, it points to physical memory. Indeed, the struct page is just a "descriptor" used by the system to keep track of the nature and state of a page, and is stored somewhere else.

All the struct page structures are stored in some specific memory area which depends on the underlying architecture. You can read more about it in Chapter 2: Describing Physical Memory of Mel Gorman's book "Understanding the Linux Virtual Memory Manager".

Once you have a PTE (pte_t), the pte_page() macro can be used to get the address of the corresponding struct page. This address is calculated using a set of macros (e.g. __pfn_to_page()) which basically end up indexing a mem_section which contains a pointer to an array of struct page (.section_mem_map). There is a global array of struct mem_section, and each PTE PFN has a section index encoded in it, which is used to select the correct section.

Where is the payload of a page struct

You could use page_address() to get virtual address of a page.
But the return address might be NULL due to the fact that not all pages have mapped virtual addresses.

void *page_address(const struct page *page);

You could use kmap to map a highmen page to a virtual address.
Also, remember to use kunmap to unmap this page when you don't need to access it.

struct page *page = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, 0);
if (page) {
void *addr = kmap(page);
if (addr) {
memset(addr, 0, PAGE_SIZE);
kunmap(addr);
}
}

How to get the physical address of the associated data from a struct page?

You need to map a page into the kernel memory as follows:

void * mapping = kmap_atomic(page, KM_USER0);
// work with mapping...
kunmap_atomic(mapping, KM_USER0);

This trick is required as there is a HighMemory concept in Linux (see this link for ex.).

UPD: You can use kmap instead of kmap_atomic in non-atomic contexts.

Can we access memory through a struct page structure

Yes we can access the page belonging to highmem through struct page's virtual field. But in your case you can't access as you mentioned that highmem page is not mapped into kernel virtual memory.

To access it you need to create mapping either permanent or temporary mappping.
To create permanent mapping map page through kmap.

 void *kmap(struct page *page)

This function works on either high or low memory. If the page structure belongs to a page in low memory, the page’s virtual address is simply returned. If the page resides in high memory, a permanent mapping is created and the address is returned.The function may sleep, so kmap() works only in process context. Because the number of permanent mappings are limited (if not, we would not be in this mess and could just permanently map all memory), high memory should be unmapped when no longer needed.This is done via the following function, which unmaps the given page:

void kunmap(struct page *page)

The temporary mapping can be created via:

void *kmap_atomic(struct page *page, enum km_type type)

This is an atomic function so you can't sleep and can be called in interrupt context. It is called temporary because next call to kmap_atomic will overwrite the previous mapping.

How can I get contents of page with page structure?

Not sure but perhaps safer approach is using kmap() from linux/highmem.h which will return associated virtual address if the page is already mapped, or else will create a mapping for the given page and return the address for the same that you can dereference from your module.



Related Topics



Leave a reply



Submit