[Linux kernel memory management] Physical allocation page⑨ ( __alloc_pages_slowpath slow path call function source code analysis | retry label code analysis)

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_nodemaskfunction as follows:

First , according to the gfp_t gfp_maskallocation 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_slowpathslow path memory allocation calling function,retry

Call the wake_all_kswapdsfunction 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_freelistfunction , try to use the adjusted area list and allocation flags for memory allocation, and if the memory allocation is successful, jump to the got_pglabel 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 nopageto 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_reclaimfunction 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_compactfunction 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 nopagelabel 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_retryfunction to determine whether to retry the memory defragmentation operation. If the determination is successful, continue to jump to the retrylabel 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_retryfunction 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_oomfunction , 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 retrylabel 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

Guess you like

Origin blog.csdn.net/han1202012/article/details/124457329