Quicklist in the kernel

The kernel needs to do a lot of things when allocating and releasing page frames, which will consume more clock cycles. For this reason, we can cache the pages to be released through a linked list, that is, do not actually release them, but put them On a linked list, the next time the page is allocated, it is directly taken from the linked list, which can greatly reduce the workload of page frame release and allocation, thereby improving performance. In the kernel, there is such a linked list—quicklist, which is a per cpu variable. Each cpu corresponds to a structure variable of the struct quicklist type. The management of the cache page frame is realized through this structure. The definition of struct quicklist is as follows:

struct quicklist {
    void *page;
    int nr_pages;
};

At the beginning, I might be a little confused when looking at the operation of this structure. Why doesn't this linked list structure have a next pointer? It turns out that the next pointer is written to the top of the page frame. This may be done to save space.
1) First look at the release operation of the page frame

static inline void __quicklist_free(int nr, void (*dtor)(void *), void *p,
    struct page *page)
{
    struct quicklist *q;

    q = &get_cpu_var(quicklist)[nr];
    *(void **)p = q->page;
    q->page = p;
    q->nr_pages++;
    put_cpu_var(quicklist);
}

In the first call, the value of q->page is NULL. If this function is called multiple times, the following linked list will be formed:

2) Looking at the allocation code of the page frame again, combined with the above figure, it can be found that when the page frame is allocated, the node that has been added to the linked list last time is selected:

static inline void *quicklist_alloc(int nr, gfp_t flags, void (*ctor)(void *))
{     
    struct quicklist *q;
    void **p = NULL;
      
    q =&get_cpu_var(quicklist)[nr];
    p = q->page;
    if (likely(p)) {
        q->page = p[0];
        p[0] = NULL;
        q->nr_pages--;
    } 
    put_cpu_var(quicklist);
    if (likely(p))
        return p;
      
    p = (void *)__get_free_page(flags | __GFP_ZERO);
    if (ctor && p)
        ctor(p);
    return p;
}

 

Guess you like

Origin blog.csdn.net/choumin/article/details/114544690