Linux Kernel Architecture

(Jacob Rumans) #1

Chapter 18: Page Reclaim and Swapping


occupied by the page is returned to the buddy system. In contrast topagevec_release,this
function assumes that all pages in the vector are not on any LRU list.

All these functions expect apagevecstructure containing the pages to be processed as parameter. If the
vector is empty, all the functions return to the caller immediately.

There are also versions of the same functions with two preceding underscores (e.g.,_ _pagevec_release).
These donottest whether the vector passed contains pages or not.

What is still lacking is a function to add pages to a page vector:

<pagevec.h>
static inline unsigned pagevec_add(struct pagevec *pvec, struct page *page)

pagevec_addadds a new pagepageto a given page vectorpvec.

The implementation of the function is not considered in detail here as it is very straightforward and
reveals little of interest.

The LRU Cache


The kernel provides a further cache known as theLRU cacheto speed up the addition of pages to the
system’s LRU lists. It makes use of page vectors to collectpageinstances and place them block-by-block
on the system’sactiveandinactivelists. The list is a hotspot in the kernel, but must be protected by
a spinlock. To keep lock contention low, new pages are not immediately added to the list, but are first
buffered on a per-CPU list:

mm/swap.c
static DEFINE_PER_CPU(struct pagevec, lru_add_pvecs) = { 0, };

The function to add new elements via this buffer islru_cache_add. It provides a way of deferring the
addition of pages to the system’s LRU lists until a certain number of pages specified byPAGEVEC_SIZE
is reached:

mm/swap.c
void fastcall lru_cache_add(struct page *page)
{
struct pagevec *pvec = &get_cpu_var(lru_add_pvecs);

page_cache_get(page);
if (!pagevec_add(pvec, page))
__pagevec_lru_add(pvec);
put_cpu_var(lru_add_pvecs);
}

Since the function accesses a CPU-specific data structure, it must prevent the kernel from interrupting
execution and resuming later on another CPU. This form of protection is enabled implicitly by invoking
get_cpu_var, which not only disables preemption, but also returns the per-CPU variable.

lru_cache_addfirst increments thecountusage counter of thepageinstance as the page is now in the
page cache (and this is interpreted as usage). The page is then added to the CPU-specific page vector
usingpagevec_add.
Free download pdf