Creating Regions

Before a new memory region can be inserted into the data structures, the kernel must establish where there is enough free space in virtual address space for a region of a given size. This job is assigned to the get_unmapped_area helper function.

7If there is no predecessor region because the new region is the new start region or because no regions are defined for the address space, the information in the red-black tree is used to set the pointers correctly.

mm/mmap.c unsigned long get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)

The arguments are self-explanatory. The implementation of the function is of no further interest as the actual work is delegated to the architecture-specific helper function stored in the mm_struct instance of the current process.8

Recall from Section 4.2 that different mapping functions are used depending on the layout of the virtual process address space. Here I consider the standard function arch_get_unmapped_area that is employed on most systems.

arch_get_unmapped_area first has to check whether the MAP_FIXED flag is set, indicating that the mapping is to be created at a fixed address. If so, the kernel ensures only that the address satisfies alignment requirements (page-by-page) and that the interval is fully within the available address space.

If no desired area was specified, the kernel tries to find a suitable section in the virtual memory area of the process by invoking arch_get_unmapped_area. If a particular preferred (as opposed to a fixed) address is specified, the kernel checks whether the region overlaps with an existing region. If not, the address can be returned as the target.

mm/mmap.c unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)

struct mm_struct *mm = current->mm;

addr = PAGE_ALIGN(addr);

(!vma || addr + len <= vma->vm_start)) return addr;

Otherwise, the kernel must try to find a free area of the right size by iterating over the available regions of the process. In doing so, it checks whether a cached area from previous scans could be used.

start_addr = addr = TASK_UNMAPPED_BASE; mm->cached_hole_size = 0;

8Files can also be equipped with a special-purpose mapping function. This is, for instance, used by the frame-buffer code to allow direct manipulation of the video memory when a frame-buffer device file is mapped into memory. However, because the kernel generally uses the standard implementation, I won't bother to discuss other more specific routines.

The actual iteration begins either at the address of the last ''hole'' in the virtual address space or at the global start address task_unmapped_base.

mm/mmap.c full_search:

for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {

/* At this point: (!vma || addr < vma->vm_end). */ if (TASK_SIZE - len < addr) {

* Start a new search - just in case we missed

* some holes.

if (start_addr != TASK_UNMAPPED_BASE) { addr = TASK_UNMAPPED_BASE; start_addr = addr; mm->cached_hole_size = 0; goto full_search;

return -ENOMEM;

* Remember the place where we stopped the search:

if (addr + mm->cached_hole_size < vma->vm_start)

mm->cached_hole_size = vma->vm_start - addr; addr = vma->vm_end;

If the search continues to the end of the user address space (task_size) and no suitable area is found, the kernel returns an -enomem error that must be forwarded to userspace for processing by the relevant application, as it indicates that insufficient virtual address space memory is available to satisfy the request. If memory is found, its virtual start address is returned.

The version for top-down allocation, arch_get_unmapped_area_topdown, progresses similarly, but the search direction is, of course, reversed. We need not bother with the details of implementation here.

Continue reading here: Address Spaces

Was this article helpful?

0 0