Полезная информация

next up previous contents
Next: The page fault handlers Up: Linux Memory Management Previous: Processes and the Memory

Acquiring and Freeing Memory: Paging Policy

When any kernel routine wants memory it ends up calling get_free_page(). This is at a lower level than kmalloc() (in fact kmalloc() uses get_free_page() when it needs more memory).

get_free_page() takes one parameter, a priority. Possible values are GFP_BUFFER, GFP_KERNEL, and GFP_ATOMIC. It takes a page off of the free_page_list, updates mem_map, zeroes the page and returns the physical address of the page (note that kmalloc() returns a physical address. The logic of the mm depends on the identity map between logical and physical addresses).

That itself is simple enough. The problem, of course, is that the free_page_list may be empty. If you did not request an atomic operation, at this stage, you enter into the realm of page stealing which we'll go into in a moment. As a last resort (and for atomic requests) a page is torn off from the secondary_page_list (as you may have guessed, when pages are freed, the secondary_page_list gets filled up first).

The actual manipulation of the page_lists and mem_map occurs in this mysterious macro called REMOVE_FROM_MEM_QUEUE() which you probably never want to look into. Suffice it to say that interrupts are disabled. [I think that this should be explained here. It is not that hard...]

Now back to the page stealing bit. get_free_page() calls try_to_free_page() which repeatedly calls shrink_buffers() and swap_out() in that order until it is successful in freeing a page. The priority is increased on each successive iteration so that these two routines run through their page stealing loops more often.

Here's one run through swap_out():

Note that swap_out() (called by try_to_free_page()) maintains static variables so it may resume the search where it left off on the previous call.

try_to_swap_out() scans the page tables of all user processes and enforces the stealing policy:

  1. Do not fiddle with RESERVED pages.
  2. Age the page if it is marked accessed (1 bit).
  3. Don't tamper with recently acquired pages (last_free_pages[]).
  4. Leave dirty pages with map_counts > 1 alone.
  5. Decrement the map_count of clean pages.
  6. Free clean pages if they are unmapped.
  7. Swap dirty pages with a map_count of 1.

Of these actions, 6 and 7 will stop the process as they result in the actual freeing of a physical page. Action 5 results in one of the processes losing an unshared clean page that was not accessed recently (decrement Q->rss) which is not all that bad, but the cumulative effects of a few iterations can slow down a process considerably. At present, there are 6 iterations, so a page shared by 6 processes can get stolen if it is clean.

Page table entries are updated and the TLB invalidated. [Wonder about the latter. It seems unnecessary since accessed pages aren't offed and there is a walk through many page tables between iterations ...may be in case an interrupt came along and wanted the most recently axed page?]

The actual work of freeing the page is done by free_page(), the complement of get_free_page(). It ignores RESERVED pages, updates mem_map, then frees the page and updates the page_lists if it is unmapped. For swapping (in 6 above), write_swap_page() gets called and does nothing remarkable from the memory management perspective.

The details of shrink_buffers() would take us too far afield. Essentially it looks for free buffers, then writes out dirty buffers, then goes at busy buffers and calls free_page() when its able to free all the buffers on a page.

Note that page directories and page tables along with RESERVED pages do not get swapped, stolen or aged. They are mapped in the process page directory through reserved page tables. They are freed only on exit from the process.

next up previous contents
Next: The page fault handlers Up: Linux Memory Management Previous: Processes and the Memory

Converted on:
Mon Apr 1 10:20:16 EST 1996