Article directory
In the [Linux Kernel Memory Management] Physical Allocation Page ② ( __alloc_pages_nodemask function parameter analysis | __alloc_pages_nodemask function allocation physical page process) blog, the __alloc_pages_nodemask
function as follows:
First , according to the gfp_t gfp_mask
allocation flag parameter, get the preferred "region type" and "migration type" of "memory node ";
Then , perform the "fast path" , the first allocation attempt uses a low watermark allocation;
If the above "fast path" assignment fails, then a "slow path" assignment is performed;
The above refers to "fast path" and "slow path" 2 22 physical page allocation methods;
Continue to the previous blog [Linux Kernel Memory Management] Physical Allocation Page ⑧ ( __alloc_pages_slowpath slow path call function source code analysis | get preferred memory area | asynchronously reclaim memory pages | lowest watermark also allocated | direct allocation) analysis __alloc_pages_slowpath
slow path memory Assign the subsequent part of the source code of the calling function;
1. Analysis of retry label code
Let's start to analyze the code under the label in the __alloc_pages_slowpath
slow path memory allocation calling function,retry
Call the wake_all_kswapds
function to ensure that the "page recycling thread" remains awake while traversing , and does not sleep accidentally;
retry:
/* Ensure kswapd doesn't accidentally go to sleep as long as we loop */
if (gfp_mask & __GFP_KSWAPD_RECLAIM)
wake_all_kswapds(order, ac);
Source code path: linux-4.12\mm\page_alloc.c #3794
Call the get_page_from_freelist
function , try to use the adjusted area list and allocation flags for memory allocation, and if the memory allocation is successful, jump to the got_pg
label execution;
/* Attempt with potentially adjusted zonelist and alloc_flags */
page = get_page_from_freelist(gfp_mask, order, alloc_flags, ac);
if (page)
goto got_pg;
Source code path: linux-4.12\mm\page_alloc.c #3811
If the caller does not want to wait and waste time, then do not perform subsequent operations, and jump nopage
to execute the subsequent code at ;
/* Caller is not willing to reclaim, we can't balance anything */
if (!can_direct_reclaim)
goto nopage;
Source code path: linux-4.12\mm\page_alloc.c #3817
Call the __alloc_pages_direct_reclaim
function to directly recycle the page;
/* Try direct reclaim and then allocating */
page = __alloc_pages_direct_reclaim(gfp_mask, order, alloc_flags, ac,
&did_some_progress);
if (page)
goto got_pg;
Source code path: linux-4.12\mm\page_alloc.c #3833
Call the __alloc_pages_direct_compact
function to perform the memory defragmentation operation in synchronous mode for the case where the requested physical page order is greater than 0;
/* Try direct compaction and then allocating */
page = __alloc_pages_direct_compact(gfp_mask, order, alloc_flags, ac,
compact_priority, &compact_result);
if (page)
goto got_pg;
Source code path: linux-4.12\mm\page_alloc.c #3839
Judging again, if the caller does not want to loop, then abandon the memory application and jump to the nopage
label execution;
/* Do not loop if specifically requested */
if (gfp_mask & __GFP_NORETRY)
goto nopage;
Source code path: linux-4.12\mm\page_alloc.c #3845
If the applied physical page order is greater than 0, call the should_compact_retry
function to determine whether to retry the memory defragmentation operation. If the determination is successful, continue to jump to the retry
label and execute it again;
/*
* It doesn't make any sense to retry for the compaction if the order-0
* reclaim is not able to make any progress because the current
* implementation of the compaction depends on the sufficient amount
* of free memory (see __compaction_suitable)
*/
if (did_some_progress > 0 &&
should_compact_retry(ac, order, alloc_flags,
compact_result, &compact_priority,
&compaction_retries))
goto retry;
Source code path: linux-4.12\mm\page_alloc.c #3865
Call the read_mems_allowed_retry
function to determine whether cpuset allows modification of the current process to apply for physical page memory from the specified memory node;
/*
* It's possible we raced with cpuset update so the OOM would be
* premature (see below the nopage: label for full explanation).
*/
if (read_mems_allowed_retry(cpuset_mems_cookie))
goto retry_cpuset;
Source code path: linux-4.12\mm\page_alloc.c #3875
Call the __alloc_pages_may_oom
function , if the memory is exhausted and the allocation of memory fails, kill a process to obtain enough memory space;
/* Reclaim has failed us, start killing things */
page = __alloc_pages_may_oom(gfp_mask, order, ac, &did_some_progress);
if (page)
goto got_pg;
Source path: linux-4.12\mm\page_alloc.c #3879
If the current process runs out of memory, the minimum watermark limit is ignored, or the use of emergency reserved memory is not allowed;
/* Avoid allocations with no watermarks from looping endlessly */
if (test_thread_flag(TIF_MEMDIE) &&
(alloc_flags == ALLOC_NO_WATERMARKS ||
(gfp_mask & __GFP_NOMEMALLOC)))
goto nopage;
Source code path: linux-4.12\mm\page_alloc.c #3884
The memory exhaustion killer has made some progress, continue to jump to the retry
label to try to allocate memory again;
/* Retry as long as the OOM killer is making progress */
if (did_some_progress) {
no_progress_loops = 0;
goto retry;
}
Source code path: linux-4.12\mm\page_alloc.c #3890
2. Complete code of retry label
retry
Label complete code:
static inline struct page *
__alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
struct alloc_context *ac)
{
...
retry:
/* Ensure kswapd doesn't accidentally go to sleep as long as we loop */
if (gfp_mask & __GFP_KSWAPD_RECLAIM)
wake_all_kswapds(order, ac);
if (gfp_pfmemalloc_allowed(gfp_mask))
alloc_flags = ALLOC_NO_WATERMARKS;
/*
* Reset the zonelist iterators if memory policies can be ignored.
* These allocations are high priority and system rather than user
* orientated.
*/
if (!(alloc_flags & ALLOC_CPUSET) || (alloc_flags & ALLOC_NO_WATERMARKS)) {
ac->zonelist = node_zonelist(numa_node_id(), gfp_mask);
ac->preferred_zoneref = first_zones_zonelist(ac->zonelist,
ac->high_zoneidx, ac->nodemask);
}
/* Attempt with potentially adjusted zonelist and alloc_flags */
page = get_page_from_freelist(gfp_mask, order, alloc_flags, ac);
if (page)
goto got_pg;
/* Caller is not willing to reclaim, we can't balance anything */
if (!can_direct_reclaim)
goto nopage;
/* Make sure we know about allocations which stall for too long */
if (time_after(jiffies, alloc_start + stall_timeout)) {
warn_alloc(gfp_mask & ~__GFP_NOWARN, ac->nodemask,
"page allocation stalls for %ums, order:%u",
jiffies_to_msecs(jiffies-alloc_start), order);
stall_timeout += 10 * HZ;
}
/* Avoid recursion of direct reclaim */
if (current->flags & PF_MEMALLOC)
goto nopage;
/* Try direct reclaim and then allocating */
page = __alloc_pages_direct_reclaim(gfp_mask, order, alloc_flags, ac,
&did_some_progress);
if (page)
goto got_pg;
/* Try direct compaction and then allocating */
page = __alloc_pages_direct_compact(gfp_mask, order, alloc_flags, ac,
compact_priority, &compact_result);
if (page)
goto got_pg;
/* Do not loop if specifically requested */
if (gfp_mask & __GFP_NORETRY)
goto nopage;
/*
* Do not retry costly high order allocations unless they are
* __GFP_REPEAT
*/
if (costly_order && !(gfp_mask & __GFP_REPEAT))
goto nopage;
if (should_reclaim_retry(gfp_mask, order, ac, alloc_flags,
did_some_progress > 0, &no_progress_loops))
goto retry;
/*
* It doesn't make any sense to retry for the compaction if the order-0
* reclaim is not able to make any progress because the current
* implementation of the compaction depends on the sufficient amount
* of free memory (see __compaction_suitable)
*/
if (did_some_progress > 0 &&
should_compact_retry(ac, order, alloc_flags,
compact_result, &compact_priority,
&compaction_retries))
goto retry;
/*
* It's possible we raced with cpuset update so the OOM would be
* premature (see below the nopage: label for full explanation).
*/
if (read_mems_allowed_retry(cpuset_mems_cookie))
goto retry_cpuset;
/* Reclaim has failed us, start killing things */
page = __alloc_pages_may_oom(gfp_mask, order, ac, &did_some_progress);
if (page)
goto got_pg;
/* Avoid allocations with no watermarks from looping endlessly */
if (test_thread_flag(TIF_MEMDIE) &&
(alloc_flags == ALLOC_NO_WATERMARKS ||
(gfp_mask & __GFP_NOMEMALLOC)))
goto nopage;
/* Retry as long as the OOM killer is making progress */
if (did_some_progress) {
no_progress_loops = 0;
goto retry;
}
...
}
Source code path: linux-4.12\mm\page_alloc.c #3792