To get get everybody on the same page: AFAICS, the two main issues that a 'struct page' can solve are:
- Caching and swapping. The structs can be linked together to form a LRU list which is necessary to implement page caches.
- Memory locking. You can store a lock counter in the struct to quickly lock a page of memory in place (e.g., so that DMA can be performed without worrying about swapping).
In my current design, I have 'struct page's for all pages in the page cache, but not for non-swapable pages.
To map physical addresses to the structs, several approaches are possible:
- Do not have a global mapping. Instead, let individual memory objects (i.e., the objects managing the pages or the page cache) provide their own mappings.
- Map them contiguously somewhere in virtual memory and do an indexed lookup. This is the fastest options; however, it does not really allow you to allocate those structs selectively: they have to be allocated and mapped, otherwise you get page faults.
- Use a global radix tree to do the mapping. This has the advantage that it allows you even to determine if a 'struct page' exists for a certain physical page.
Right now, I am using the first approach. However, I contemplate switching to the third variant with a radix tree. This would make lookup faster (as it would not have to go through a virtual call anymore). Hence, it would also speed up memory locking. The latter needs to be performed quite often (as my microkernel frequently needs access to pages in other address spaces).