Team LiB
Previous Section Next Section

Getting Pages

Now with an understanding of how the kernel manages memoryvia pages, zones, and so onlet's look at the interfaces the kernel implements to allow you to allocate and free memory within the kernel.

The kernel provides one low-level mechanism for requesting memory, along with several interfaces to access it. All these interfaces allocate memory with page-sized granularity and are declared in <linux/gfp.h>. The core function is

struct page * alloc_pages(unsigned int gfp_mask, unsigned int order)

This allocates 2order (that is, 1 << order) contiguous physical pages and returns a pointer to the first page's page structure; on error it returns NULL. We will look at the gfp_mask parameter in a later section. You can convert a given page to its logical address with the function

void * page_address(struct page *page)

This returns a pointer to the logical address where the given physical page currently resides. If you have no need for the actual struct page, you can call

unsigned long __get_free_pages(unsigned int gfp_mask, unsigned int order)

This function works the same as alloc_pages(), except that it directly returns the logical address of the first requested page. Because the pages are contiguous, the other pages simply follow from the first.

If you need only one page, two functions are implemented as wrappers to save you a bit of typing:

struct page * alloc_page(unsigned int gfp_mask)

unsigned long __get_free_page(unsigned int gfp_mask) 

These functions work the same as their brethren but pass zero for the order (20 = one page).

Getting Zeroed Pages

If you need the returned page filled with zeros, use the function

unsigned long get_zeroed_page(unsigned int gfp_mask)

This function works the same as __get_free_page(), except that the allocated page is then zero-filled. This is useful for pages given to user-space because the random garbage in an allocated page is not so randomit might "randomly" contain sensitive data. All data must be zeroed or otherwise cleaned before it is returned to user-space, to ensure system security is not compromised. Table 11.2 is a listing of all the low-level page allocation methods.

Table 11.2. Low-Level Page Allocations Methods

Flag

Description

alloc_page(gfp_mask)

Allocate a single page and return a pointer to its page structure

alloc_pages(gfp_mask, order)

Allocate 2order pages and return a pointer to the first page's page structure

__get_free_page(gfp_mask)

Allocate a single page and return a pointer to its logical address

__get_free_pages(gfp_mask, order)

Allocate 2order pages and return a pointer to the first page's logical address

get_zeroed_page(gfp_mask)

Allocate a single page, zero its contents, and return a pointer to its logical address


Freeing pages

A family of functions allows you to free allocated pages when you no longer need them:

void __free_pages(struct page *page, unsigned int order)
void free_pages(unsigned long addr, unsigned int order)
void free_page(unsigned long addr)

You must be careful to free only pages you allocate. Passing the wrong struct page or address, or the incorrect order, can result in corruption. Remember, the kernel trusts itself. Unlike user-space, the kernel happily hangs itself if you ask it.

Let's look at an example. Here, we want to allocate eight pages:

unsigned long page;

page = __get_free_pages(GFP_KERNEL, 3);
if (!page) {
        /* insufficient memory: you must handle this error! */
        return ENOMEM;
}

/* 'page' is now the address of the first of eight contiguous pages ... */

free_pages(page, 3);

/*
 * our pages are now freed and we should no
 * longer access the address stored in 'page'
 */

The GFP_KERNEL parameter is an example of a gfp_mask flag. It is discussed shortly.

Make note of the error checking after the call to __get_free_pages(). A kernel allocation can fail and your code must check for and handle such errors. This might mean unwinding everything you have done thus far. It therefore often makes sense to allocate your memory at the start of the routine, to make handling the error easier. Otherwise, by the time you attempt to allocate memory, it may be rather hard to bail out.

These low-level page functions are useful when you need page-sized chunks of physically contiguous pages, especially if you need exactly a single page or two. For more general byte-sized allocations, the kernel provides kmalloc().

    Team LiB
    Previous Section Next Section