Mmvmscanc

while (!list_empty(&l_hold)) { cond_resched(); page = lru_to_page(&l_hold); list_del(&page->lru); if (page_mapped(page)) {

if (!reclaim_mapped |

(total_swap_pages == 0 && PageAnon(page)) | page_referenced(page, 0)) {

list_add(&page->lru, &l_active); continue;

The code becomes more complex since we are getting to the very heart of page reclaim. The basic action is represented by a loop that iterates over all elements of the l_hold list, which in the previous section was filled with pages regarded as active. These pages must now be reclassified and placed on the l_active and l_inactive lists.

page_mapped first checks whether the page is embedded in the pages tables of any process. This is easy to do using the reverse mapping data structures. Recall from Chapter 4 that the information as to whether the page is mapped in page tables is held in the _mapcount element of each page instance. If the page is mapped by a single process, the counter value is 0; for non-mapped pages, it is -1. Logically, page_mapped must therefore check whether page->_mapping is greater than or equal to 0.

If there is no mapping, the page is immediately placed on the list of inactive pages.

If page_mapped returns a true value indicating that the page is associated with at least one process, it is a little more difficult to decide whether the page is important for the system. One of the following three conditions must apply before the page can be moved back to the start of the list of active pages:

1. As discussed in Chapter 4.8.3, the reverse mapping mechanism provides the page_referenced function to check the number of processes that have used a page since the last check. This is done by referring to corresponding status bits of the hardware that are held in the individual page table entries. Although the function returns the number of processes, it is only necessary to know whether at least one process has accessed the page, that is, whether the value returned is greater than 0. The condition is satisfied if this is the case.

2. reclaim_mapped is equal to 0; that is, mapped pages are not to be reclaimed.

3. The system has no swap area and the page just examined is registered as an anonymous page (in this case, there is nowhere to swap the page out).

Recall that Section 18.6.3 discussed how the call to page_referenced and possibly moving the page to the inactivity list afterward fit into the big picture of deeming a page active or inactive.

The kernel enters the third and final phase of refill_inactive_zone once all pages have been redistributed from the zone-specific active list to the temporary local l_active and l_inactive lists. Again there is no need for a separate code flow diagram.

The last step entails not only copying the data in the temporary lists to the corresponding LRU lists of the processed zone, but also checking whether there are pages that are no longer used (their usage counters are equal to 0) and can be returned to the buddy system.

To do this, the kernel iterates sequentially over all the pages that have accumulated in the local l_active and l_inactive lists. It handles all the individual pages in the same way:

□ Pages taken from the tail of the local lists zone->active_list or inactive_list are added to the head of the zone-specific active or inactive LRU lists, respectively.

□ The page instance is added to a page vector. When this is full, all its pages are transferred collectively to_pagevec_release, which first decrements the usage counter by 1 and then returns the memory space to the buddy system when the counter reaches 0.

All the kernel need do after placing the processed pages back on the zone-specific lists is update a few variables relating to memory management statistics.

Continue reading here: Reclaiming Inactive Pages

Was this article helpful?

0 0