Allocating memory
Describes how memory is used in device drivers;
How best to utilize system memory resources.
Kmalloc function
The Kmalloc memory allocation engine is a powerful tool.
#include <linux/slab.h>
void *kmalloc (size_t size, int flags);
Parameter assignment means that flags can control the behavior of Kmalloc in a variety of ways.
The flag Gfp_kernel indicates that the memory allocation is performed on behalf of the process running in kernel space, which means that the function calling it is representing
A process executes a system call.
Using Gfp_kernel allows the Kmalloc to hibernate the current process when there is less free memory to wait for a page.
Functions that use Gfp_kernel to allocate memory must be reentrant. (Can be dormant)
When the process sleeps, the kernel brushes the contents of the buffer to the hard disk, or swap out the memory from a user process to obtain a
A memory page.
When called in interrupt processing routines, Tasklet, and kernel timers, the process should not hibernate and the driver should use the
Gfp_atomic logo.
The kernel usually reserves some free pages for atomic allocations.
When using the GFP_ATOMIC flag, Kmalloc can even use the last free page.
All logos are defined in <linux/gfp.h>, with individual flags prefixed with two underscores, such as __GFP_DMA.
Gfp_user Used to allocate memory for user space pages and may hibernate
Gfp_highuser Where high-end memory is allocated
Gfp_noio
Gfp_nofs
Similar to Gfp_kernel,
Allocations with the GFP_NOFS flag do not allow any file system calls to be performed;
Gfp_noio Disallow initialization of any I/O.
These two flags are primarily used in file system and virtual memory code.
The above assigned flag can be used with the following flag "or".
__gfp_dma
__gfp_highmem
__gfp_cold
__gfp_nowarn
__gfp_high
__gfp_repeat
__gfp_nofail
__gfp_noretry
The Linux kernel divides memory into three segments:
Available for DMA memory, conventional memory, high-end memory.
The usual memory allocations occur in the normal memory area.
Each computing platform must know how to classify its own specific memory range into these three segments.
The memory available for the dam refers to memory that exists within the special address range that the peripheral can use to perform DMA access.
On most sound systems, all memory is in this section.
On the x86 platform, the DMA segment is the top 16MB of RAM and the old ISA device can perform DMA,PCI devices on that segment without this limitation.
High-end memory is a mechanism that 32-bit platforms exist to access (relative) large amounts of memory.
If you do not complete some special mappings first, you will not be able to access the memory directly from the kernel.
If the driver uses a lot of memory, it can work better on large systems that can use high-end memory.
When a new page is allocated to meet the requirements of kmalloc, the kernel creates a list of memory segments to search for altogether.
If the __GFP_DMA flag is specified, only the DMA section will be searched;
If a specific flag is not specified, both the regular section and the DMA section are searched;
If the __GFP_HIGHMEM flag is set, all three extents will be searched for a free page.
(But Kmalloc cannot allocate high-end memory)
The kernel is responsible for managing the physical memory of the system, and physical memory can only be assigned by page.
There is a big difference in implementation between KMALLOC and the typical user-space malloc.
(Simple heap-based memory allocation technology)
The kernel uses special page-based allocation techniques to optimally utilize system RAM.
Linux handles memory allocations by creating a series of memory object pools in which the size of the memory blocks in each pool is consistent. Secretariat
When a request is assigned, a whole block is passed directly to the requestor in a pool that contains a sufficiently large chunk of memory.
The kernel can allocate only a few predefined, fixed-size byte arrays.
Device drivers often allocate many memory blocks of the same size over and over again.
The kernel implements a fallback cache (lookaside cache).
Device drivers typically do not involve this memory behavior using the back cache, but there are exceptions to the USB and Linux 2.6
This cache is used by the SCSI driver.
The Linux kernel's cache management is sometimes referred to as the "slab allocator".
Related functions and types are declared in <linxu/slab.h>.
The cache implemented by the slab allocator has a kmem_cache_t type, created by calling Kmem_cache_create:
kmem_cache_t *kmem_cache_create (const char *name, size_t size, size_t offset, unsigned
Long flags, Void (*constructor) (void *,kmem_cache_t *, unsigned long flags), void
(*destructor) (void *,kmem_cache_t *,unsigned long flags));
The parameter flags control how the assignment is done, and is a bitmask.
Slab_no_reap Slab_hwcache_alignSlab_cache_dma
After the cache is created, you can call Kmem_cache_alloc to allocate memory objects from:
void *kmem_cache_alloc (kmem_cache_t *cache, int flags);
Use Kmem_cache_free when releasing a Memory object:
void Kmem_cache_free (kmem_cache_t *cache, const void *obj);
Release the cache:
int Kmem_cache_destroy (kmem_cache_t *cache);
Memory pool
Memory allocations in some parts of the kernel are not allowed to fail.
The kernel creates an abstraction called a memory pool, which is actually some form of fallback cache, which always saves free memory.
For use in emergency situations.
The type of the memory pool object is mempool_t (defined in <linux/mempool.h>), and you can use Mempool_create to create an internal
The storage Pool object.
mempool_t *mempool_create (int min_nr, mempool_alloc_t *alloc_fn, mempool_free_t
*free_fn, void *pool_data);
The actual allocation and deallocation of objects is handled by the ALLOC_FN and FREE_FN functions:
typedef void * (mempool_alloc_t) (int gfp_mask, void *pool_data);
typedef void (mempool_free_t) (void *element, void *pool_data);
The last parameter of the mempool_create, the Pool_data, is passed in Alloc_fn and FREE_FN.
We can write a specific purpose function for Mempool to handle memory allocations.
Usually let the kernel's slab allocator handle this task for us.
There are two functions in the kernel (Mempool_alloc_slab and Mempool_free_slab) that can take advantage of kmem_cache_alloc and
Kmem_cache_free handles memory allocation and deallocation.
After the memory pool is established, the objects are allocated and disposed:
void *mempool_alloc (mempool_t *pool, int gfp_mask);
void Mempool_free (void *element, mempool_t *pool);
Resize the Mempool:
int Mempool_resize (mempool_t *pool, int new_min_nr, int gfp_mask);
If you do not need a memory pool, return it to the system:
void Mempool_destroy (mempool_t *pool);
Before destroying the Mempool, all allocated objects must be returned to the memory pool, or the kernel oops will be caused.
Mempool allocates some memory blocks that are idle and not really used. It's easy to waste a lot of memory using Mempool.
Get_free_page and related functions
The following functions can be used for assigning pages:
Get_zeroed_page (unsigned int flags);
__get_free_page (unsigned int flags);
__get_free_pages (unsigned int flags, unsigned int order);
The function of the parameter flags is the same as in Kmalloc;
The parameter order is the base 2 logarithm of the number of pages to be requested or freed.
The Get_order function returns an order value based on the size of the host platform.
void Free_page (unsigned long addr);
void Free_pages (unsigned long addr, unsigned long order);
As long as the same rules are met and Kmalloc, get_free_pages and other functions can be called at any time.
When Gfp_atomic is used, the function will fail in some cases when allocating memory.
The advantage of a page-based allocation strategy is that memory is used more efficiently, and allocation of pages does not waste memory space.
The Kmalloc function wastes a certain amount of memory because of the granularity of the allocation.
The biggest advantage of using the __get_free_page function is that these assigned pages belong to us entirely, and in theory we can
The Local adjustment page table merges them into a linear region.
For example, you can allow user processes to mmap the memory areas that are allocated to these single but unrelated pages.
Alloc_pages interface
A struct page is a data structure that the kernel uses to describe a single page of memory.
The page structure is needed in many parts of the kernel, especially where high-end memory is needed.
The core code of the Linux page allocator is a function called Alloc_pages_node:
struct page *alloc_pages_node (int nid, unsigned int flags, unsigned int order);
In most cases, use a macro:
struct page *alloc_pages (unsigned int flags, unsigned int order);
struct page *alloc_page (unsigned int flags);
The parameter NID is the ID number of the NUMA node that represents the memory to allocate.
void __free_page (struct page *page);
void __free_pages (struct page *page, unsigned int order);
void free_hot_page (struct page *page);
void free_cold_page (struct page *page);
Vmalloc and its auxiliary functions
Vmalloc a contiguous region that allocates a virtual address space.
This area may be physically discontinuous (the function Alloc_page must be called independently for each page to access),
The kernel thinks they are contiguous on the address.
Vmalloc returns a 0 (null address) When an error occurs, and returns a pointer to a linear, size-most
Less is the linear memory area of size.
Vmalloc is the basis of the Linux memory allocation mechanism.
(The use of vmalloc is discouraged in most cases)
#include <linxu/vmalloc.h>
void *vmalloc (unsigned long size);
void Vfree (void *addr);
void *ioremap (unsigned long offset, unsigned long size);
void Iounmap (void *addr);
The memory address returned by Kmalloc and __get_free_pages is also a virtual address, and its actual value must be handled by the MMU to be converted to the object
Memory address.
The (virtual) address range used by Kmalloc and __get_free_pages corresponds to one by one of the physical memory and may have a constant-based
An offset from the page_offset. You do not need to modify the page table for this address segment.
The address ranges used by Vmalloc and Ioremap are completely virtual, and each allocation is established by the appropriate setting of the page table (virtual
Memory area.
Vmalloc can obtain addresses in the range Vmalloc_start to Vmalloc_end, both of which are
Defined in <asm/pgtable.h>.
Addresses allocated with Vmalloc are not intended to be used outside the microprocessor, they are only intentional on the memory management unit of the processor
Yi.
An example function using the Vmalloc function is the create_module system call, which uses the Vmalloc function to get the load module
The required memory space.
After calling Insmod to reposition the module code, the Copy_from_user function is then called to copy the module code and data to the assigned
Within the space.
The memory space allocated with Vmalloc is freed with the Vfree function.
Ioremap also creates a new page table, but does not actually allocate memory.
The return value of the Ioremap is a special virtual address that can be used to access the specified physical memory area, and the virtual address is finally
Call Iounmap to release it.
Ioremap more for mapping (physical) PCI buffer addresses to (virtual) kernel space.
For example, a frame buffer that can be used to access a PCI video device that is mapped to a high physical address beyond the system initialization
The Set of page table address ranges.
The Ioremap and Vmalloc functions are page-oriented (they all modify the page table), so the relocated or allocated memory space is actually
will be raised to the nearest page boundary.
Ioremap method by lowering the remap address down to the page boundary and returning the offset in the first remap page
Simulates a mapping that is not aligned.
The Vmalloc function cannot be used in an atomic context because its internal implementation calls Kmalloc (Gfp_kernel) to fetch the page table
Storage space, so it may hibernate.
PER-CPU variable
Get a large buffer
The allocation of large, contiguous memory buffers is easy to stream to failures.
System memory is fragmented over time, resulting in the inability to get a real large memory area.
The best way to perform large I/O operations is through discrete/clustered operations.
If a contiguous chunk of memory is required to be used as a buffer, it is best to allocate it through request memory during system boot.
Assigning at boot time is the only way to get a large number of contiguous pages of memory.
Allocating a buffer at boot time is a bit "dirty" because it skips the kernel's memory management policy by reserving a private pool of memory.
Modules cannot allocate memory at boot time, only device drivers that are linked directly to the kernel can allocate memory at boot time.
This mechanism is available only for code that is linked to the kernel image.
When the kernel is booted, it can access all of the system's physical memory, and then invoke the initialization functions of each subsystem to initialize,
It allows the initialization code to allocate a private buffer while reducing the amount of RAM left for regular system operations.
You can complete the memory allocation at boot time by calling one of the following functions:
#include <linux/bootmem.h>
void *alloc_bootmem (unsigned long size);
void *alloc_bootmem_low (unsigned long size);
void *alloc_bootmem_pages (unsigned long size);
void *alloc_bootmem_low_pages (unsigned long size);
These functions either allocate the entire page (if ending in _pages), or allocate memory areas that are not aligned on the page boundary.
Unless you use a version with the _low suffix, the allocated memory may be high-end memory.
If you want to use it for DMA operations, and high-end memory does not always support DMA operations, a _low variant is required.
The kernel provides an interface to release this memory:
void Frdd_bootmem (unsigned long addr, unsigned long size);
allocating memory (Linux device drivers)