linux 內核 2.4 中有 2 個版本的物理頁面分配函數 alloc_pages()。 一個在 mm/numa.c 中, 另一個在 mm/page_alloc.c 中, 根據條件編譯選項 CONFIG_DISCONTIGMEM 決定取捨。
==================== mm/numa.c 43 43 ====================
43 #ifdef CONFIG_DISCONTIGMEM
==================== mm/numa.c 91 128 ====================
91 /*
92 * This can be refined. Currently, tries to do round robin, instead
93 * should do concentratic circle search, starting from current node.
94 */
95 struct page * alloc_pages(int gfp_mask, unsigned long order)
96 {
97 struct page *ret = 0;
98 pg_data_t *start, *temp;
99 #ifndef CONFIG_NUMA
100 unsigned long flags;
101 static pg_data_t *next = 0;
102 #endif
103
104 if (order >= MAX_ORDER)
105 return NULL;
106 #ifdef CONFIG_NUMA
107 temp = NODE_DATA(numa_node_id());
108 #else
109 spin_lock_irqsave(&node_lock, flags);
110 if (!next) next = pgdat_list;
111 temp = next;
112 next = next->node_next;
113 spin_unlock_irqrestore(&node_lock, flags);
114 #endif
115 start = temp;
82
116 while (temp) {
117 if ((ret = alloc_pages_pgdat(temp, gfp_mask, order)))
118 return(ret);
119 temp = temp->node_next;
120 }
121 temp = pgdat_list;
122 while (temp != start) {
123 if ((ret = alloc_pages_pgdat(temp, gfp_mask, order)))
124 return(ret);
125 temp = temp->node_next;
126 }
127 return(0);
128 }
通過設置 CONFIG_DISCONTIGMEM 這個條件編譯選項之後, 這段代碼才能得到編譯。
我們可以把 不連續的物理存儲空間 看做是一種廣義的 NUMA, 兩塊內存之間的孤島看成是非均質的。這樣, 在處理不連續的物理空間的時候, 也需要像處理 NUMA 一樣劃分出若干連續且均勻的 “存儲節點”, 因而, 也有一個 pg_data_t 的數據結構的隊列。 調用參數中的 gfp_mask, 他是一個整數代表著一種分配策略。它對應的實際上是給定節點中數組node_zonelist[] 的下標, 而這個node_zonelist[] 表征的是物理內存頁面分配時候的一個策略。 在node_zonelist 中, 維護了一個zone_t 的數組, 這個數組就用來表征 分配物理頁面的時候, 先到 zone[i]管理區嘗試分配, 如果不行, 轉到zone[i + 1]。由於, 有多種分配的策略, 因而, 定義了一個node_zonelist[] 的分配策略數組。
第二個參數 Z喎?http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vcmRlciCx7dX3y/nQ6NKqtcTO78Dtv+m1xLTz0KGjrL/J0tS/tLW9y/vKx9K7uPZ1bnNpZ25lZCBsb25nIMDg0M2ho7zGy+O7+tbQyseyydPDtv69+NbG0M7KvbXEo6wgztLDx7fWxeTSs8PmtcTKsbryo6wg0rLKx7C01dUgPG5vYnI+Mm48L25vYnI+ILXE0M7KvcC0vfjQ0LfWxeSho7rcyN3S17/J0tTP67W9o6wg1eK49m9yZGVyIL7NtPqx7cHL0OjSqrfWxeQgv9W85CC089ChINbQIDIgtcTD3bTOtcTQzsq9oaMgaWUsILfWxeS1xNKzw+a089ChzqogPG5vYnI+Mm9yZGVyPC9ub2JyPqGjILbU09ogTlVNQSC94bm5tcTPtc2ztvjR1KOsIM7Sw8e/ydLUzai5/U5VTUFfREFUQSC6zSBudW1hX25vZGVfaWQoKSDV0rW9Y3B1IMv51Nq92rXjtcRwZ19kYXRhX3QgtcTK/b7dveG5ubbTwdChoyC21NPaILfHwazQ+LXEIFVNQSC94bm5o6wg0rLT0NK7uPZwZ2RhdF9saXN0ILXEveG5uaGjztLDx7/J0tTV4sO0wO294sv7o6wgPHN0cm9uZz48ZW0+VU1BIM/gtbHT2k5VTUEg1tDL+dPQx/jT8rXEssTWyrHks8nSu9bCyrG68rXEzNjK4sfp0M6jrCBpZaOsIHBnZGF0X2xpc3QgtcSzpLbIzqogMS48L2VtPjwvc3Ryb25nPiDSsr7NysfLtaOsILT6wuu1xDEwNiB+IDExNCDKtbzKyc+78cihtb3By9K7uPYgcGdkYXRfdCC92rXjtcTWuNXroaPIu7rzo6wgMTE1IH4gMTI2ILHpwPrV4rj2cGdkYXRfbGlzdCDL+dTatcRwZ2RhdF9saXN0IMG0se3W0LXEw7+49nBnZGF0X3Qgvdq146OsIMrUzbzU2tXi0Km05rSivdq148nPt9bF5Mv50Oi1xM7vwO3Ss8PmoaM8c3Ryb25nPjxlbT7Oqsqyw7TKx8G9uPZ3aGlsZSDE2KOsINLyzqrO0sPH0ru/qsq8xMO1vbXEcGdkYXRfdCC05rSivdq14yC/ycTc1rvKx9XiuPbBtLHt1tC85LXExLPSu73ateO2+NLRPC9lbT48L3N0cm9uZz6hoyA8L2NvZGU+DQo8aDMgaWQ9"11-allocpagespdat">1.1. alloc_pages_pdat
==================== mm/numa.c 85 89 ====================
85 static struct page * alloc_pages_pgdat(pg_data_t *pgdat, int gfp_mask,
86 unsigned long order)
87 {
88 return __alloc_pages(pgdat->node_zonelists + gfp_mask, order);
89 }
可以看到,在每個pgdat_t 節點上, 分配頁面的時候, 都是調用了 __alloc_pages 函數。
2. UMA 中的 alloc_pages
==================== include/linux/mm.h 343 352 ====================
343 #ifndef CONFIG_DISCONTIGMEM
344 static inline struct page * alloc_pages(int gfp_mask, unsigned long order)
83
345 {
346 /*
347 * Gets optimized away by the compiler.
348 */
349 if (order >= MAX_ORDER)
350 return NULL;
351 return __alloc_pages(contig_page_data.node_zonelists+(gfp_mask), order);
352 }
這個函數比較簡單, 他只有在 CONFIG_DISCONTIGMEM 沒有定義的時候才會編譯, ie, 他處理UMA 均質連續時候的物理頁面分配。
其實, 個人感覺這兩段代碼, 邏輯上是統一的,因為之前也說過, UMA 可以看成是 NUMA 的一種特例情形,在UMA 中 pgdat_list 的長度縮小到 1。因而, 就不需要再去遍歷 這個 pgdat_list 了, 或者說相當於 遍歷過程只執行了1 次。
3. __alloc_pages
這段代碼有些長, 分段來看:
3.1 part 1
==================== mm/page_alloc.c 270 315 ====================
[alloc_pages()>__alloc_pages()]
270 /*
271 * This is the 'heart' of the zoned buddy allocator:
272 */
273 struct page * __alloc_pages(zonelist_t *zonelist, unsigned long order)
274 {
275 zone_t **zone;
276 int direct_reclaim = 0;
277 unsigned int gfp_mask = zonelist->gfp_mask;
278 struct page * page;
279
280 /*
281 * Allocations put pressure on the VM subsystem.
282 */
283 memory_pressure++;
284
285 /*
286 * (If anyone calls gfp from interrupts nonatomically then it
287 * will sooner or later tripped up by a schedule().)
288 *
289 * We are falling back to lower-level zones if allocation
290 * in a higher zone fails.
291 */
292
293 /*
294 * Can we take pages directly from the inactive_clean
295 * list?
296 */
297 if (order == 0 && (gfp_mask & __GFP_WAIT) &&
298 !(current->flags & PF_MEMALLOC))
299 direct_reclaim = 1;
300
301 /*
302 * If we are about to get low on free pages and we also have
303 * an inactive page shortage, wake up kswapd.
304 */
305 if (inactive_shortage() > inactive_target / 2 && free_shortage())
306 wakeup_kswapd(0);
307 /*
308 * If we are about to get low on free pages and cleaning
309 * the inactive_dirty pages would fix the situation,
310 * wake up bdflush.
311 */
312 else if (free_shortage() && nr_inactive_dirty_pages > free_shortage()
313 && nr_inactive_dirty_pages >= freepages.high)
314 wakeup_bdflush(0);
315
我們的第一個參數 zonelist 指向一個代表著一個具體分配策略的zonelist_t 的數據結構, order 和前面一樣, 表征需要分配頁面的大小。 gfp_mask 表征的是具體分配策略中用於控制目的的標志位。 如果要求分配單頁 (order = 0), 並且是等待分配完成(__GFP_WAIT), 同時, 不是內存分配者(PF_MEMALLOC), 就把 局部量 direct_reclaim 設置為 1。表示, 我們可以從相應的頁面管理區中的 不活躍干淨頁面 的緩沖隊列中進行回收。 上一章中講到, 這種頁面的內容已經寫入到了交換設備中, 只是還是保留著頁面的內容而已。由於這些頁面不一定是連續的, 所以, 只有需要單頁的時候, 才從這裡回收分配。 當內存頁面短缺的時候, 會喚醒kswapd 和 bdflush 兩個內核線程, 獲取更多的內存頁面, 進行分配。
3.2 part 2
==================== mm/page_alloc.c 316 340 ====================
[alloc_pages()>__alloc_pages()]
316 try_again:
317 /*
318 * First, see if we have any zones with lots of free memory.
319 *
320 * We allocate free memory first because it doesn't contain
321 * any data ... DUH!
322 */
323 zone = zonelist->zones;
324 for (;;) {
325 zone_t *z = *(zone++);
326 if (!z)
327 break;
328 if (!z->size)
329 BUG();
330
331 if (z->free_pages >= z->pages_low) {
332 page = rmqueue(z, order);
333 if (page)
334 return page;
335 } else if (z->free_pages < z->pages_min &&
336 waitqueue_active(&kreclaimd_wait)) {
337 wake_up_interruptible(&kreclaimd_wait);
338 }
339 }
340
上面一段代碼, 會對我們所設定的分配策略數組 zone[] 中的每個管理區 zone 進行遍歷,如果發現 管理區中 空閒頁面的數量, 高於設定的管理區中最少需要保留的頁面的數量 pages_low的時候, 就調用 requeue 試圖分配頁面。否則要是發現空閒頁面, 比設定的最小的頁面數量 pages_min 還少,並且, kreclaimd 處於睡眠狀態, 就喚醒他, 讓他回收一些頁面備用。
3.2.1 rmqueue
==================== mm/page_alloc.c 172 211 ====================
[alloc_pages()>__alloc_pages()>rmqueue()]
172 static struct page * rmqueue(zone_t *zone, unsigned long order)
173 {
174 free_area_t * area = zone->free_area + order;
175 unsigned long curr_order = order;
176 struct list_head *head, *curr;
177 unsigned long flags;
178 struct page *page;
179
180 spin_lock_irqsave(&zone->lock, flags);
181 do {
182 head = &area->free_list;
183 curr = memlist_next(head);
184
185 if (curr != head) {
186 unsigned int index;
187
188 page = memlist_entry(curr, struct page, list);
189 if (BAD_RANGE(zone,page))
190 BUG();
191 memlist_del(curr);
192 index = (page - mem_map) - zone->offset;
193 MARK_USED(index, curr_order, area);
194 zone->free_pages -= 1 << order;
195
196 page = expand(zone, page, index, order, curr_order, area);
197 spin_unlock_irqrestore(&zone->lock, flags);
198
199 set_page_count(page, 1);
200 if (BAD_RANGE(zone,page))
201 BUG();
202 DEBUG_ADD_PAGE
203 return page;
204 }
205 curr_order++;
206 area++;
207 } while (curr_order < MAX_ORDER);
208 spin_unlock_irqrestore(&zone->lock, flags);
209
210 return NULL;
211 }
這個函數試圖從一個頁面管理區中分配若干連續的內存頁面。 由於代表物理頁面的page 數據結構, 是通過雙向鏈表的形式連接在管理區的某個空閒隊列中的, 分配頁面, 就是將他們從隊列中摘除的過程。 大概這就是這個函數命名為 rmqueue 的原因吧。 zone 管理區中的free_area 是個結構數組。
通過 zone->free_area + order 可以找到free_area 所管理的 2order 大小的頁面塊的鏈表的入口。 我們通過 memlist_next 獲取第一個頁面上 list_head 結構的地址, 然後通過調用 memlist_entry (在chap 1中 C 語言部分 有介紹)獲取list_head 所在頁面 page 的地址信息。並將該段頁面空間 使用 memlist_del 進行移出free_area 所管理的隊列。 index 表示分配的頁面在 zone 中的位置 如果一個 order 所對應的頁面塊隊列中沒有可以分配的頁面塊, 就移動到下一個更大的order + 1 所對應的頁面塊隊列中嘗試分配。如果, 在更大的頁面塊中成功分配了頁面, 就調用expand 將剩余的頁面空間分解成小的塊連入到相應的隊列中。
3.2.2 expand
==================== mm/page_alloc.c 150 169 ====================
[alloc_pages()>__alloc_pages()>rmqueue()>expand()]
150 static inline struct page * expand (zone_t *zone, struct page *page,
151 unsigned long index, int low, int high, free_area_t * area)
152 {
153 unsigned long size = 1 << high;
154
155 while (high > low) {
156 if (BAD_RANGE(zone,page))
157 BUG();
158 area--;
159 high--;
160 size >>= 1;
161 memlist_add_head(&(page)->list, &(area)->free_list);
162 MARK_USED(index, high, area);
163 index += size;
164 page += size;
165 }
166 if (BAD_RANGE(zone,page))
167 BUG();
168 return page;
169 }
調用參數中的low 表征需要的頁面塊的大小, high 表示 實際滿足要求的物理塊的大小。 當 high > low 的時候, 將2high?1 的區塊, 連入到high - 1 對應的free_list 中去, 利用 memlist_add_head; 同時設置位圖, 直到全部處理完畢。
3.3 part 3
從part2 部分的代碼中, 我們知道, 我們現在當前管理區zone 的free_list 中進行分配, (遍歷該區域所有不同大小的頁面塊), 如果還是失敗的話, 就進入到下一個zone 進行分配。如果分配成功, page 結構中的引用計數通過 set_page_count 被設置為 1。 但是,如果沒有分配成功呢?
這時候, 我們需要加大分配的力度:
1. 降低對 zone 管理區中 保持 page_low 的要求
2. 將緩沖在管理區中的 不活躍干淨頁面, 也加入考慮分配的范圍。
==================== mm/page_alloc.c 341 364 ====================
[alloc_pages()>__alloc_pages()]
341 /*
342 * Try to allocate a page from a zone with a HIGH
343 * amount of free + inactive_clean pages.
344 *
345 * If there is a lot of activity, inactive_target
346 * will be high and we'll have a good chance of
347 * finding a page using the HIGH limit.
348 */
349 page = __alloc_pages_limit(zonelist, order, PAGES_HIGH, direct_reclaim);
350 if (page)
351 return page;
352
353 /*
354 * Then try to allocate a page from a zone with more
355 * than zone->pages_low free + inactive_clean pages.
356 *
357 * When the working set is very large and VM activity
358 * is low, we're most likely to have our allocation
359 * succeed here.
360 */
361 page = __alloc_pages_limit(zonelist, order, PAGES_LOW, direct_reclaim);
362 if (page)
363 return page;
364
先後使用 pages_high 和 pages_low 來嘗試分配。
3.3.1 __alloc_pages_limit
==================== mm/page_alloc.c 213 267 ====================
[alloc_pages()>__alloc_pages()>__alloc_pages_limit()]
213 #define PAGES_MIN 0
214 #define PAGES_LOW 1
215 #define PAGES_HIGH 2
88
216
217 /*
218 * This function does the dirty work for __alloc_pages
219 * and is separated out to keep the code size smaller.
220 * (suggested by Davem at 1:30 AM, typed by Rik at 6 AM)
221 */
222 static struct page * __alloc_pages_limit(zonelist_t *zonelist,
223 unsigned long order, int limit, int direct_reclaim)
224 {
225 zone_t **zone = zonelist->zones;
226
227 for (;;) {
228 zone_t *z = *(zone++);
229 unsigned long water_mark;
230
231 if (!z)
232 break;
233 if (!z->size)
234 BUG();
235
236 /*
237 * We allocate if the number of free + inactive_clean
238 * pages is above the watermark.
239 */
240 switch (limit) {
241 default:
242 case PAGES_MIN:
243 water_mark = z->pages_min;
244 break;
245 case PAGES_LOW:
246 water_mark = z->pages_low;
247 break;
248 case PAGES_HIGH:
249 water_mark = z->pages_high;
250 }
251
252 if (z->free_pages + z->inactive_clean_pages > water_mark) {
253 struct page *page = NULL;
254 /* If possible, reclaim a page directly. */
255 if (direct_reclaim && z->free_pages < z->pages_min + 8)
256 page = reclaim_page(z);
257 /* If that fails, fall back to rmqueue. */
258 if (!page)
259 page = rmqueue(z, order);
260 if (page)
261 return page;
262 }
263 }
264
265 /* Found nothing. */
266 return NULL;
267 }
在這裡放寬了對分配時候要求zone 管理區保留的頁面的限制, 現在只要求 空閒區頁面數量 加上 所管理的不活躍干淨頁面的數量 能夠達到分配要求的 water_mark 就可以再次嘗試分配了。 這裡, 我們先前設置的direct_reclaim 局部變量就可以起作用了。 他使得我們在空閒頁面與要求的zone 的page_min 差距小於 8 的時候, 可以直接 使用reclaim_page 從inactive_clean_list 中回收頁面。 如果沒有找到相應的page, 就再對這個zone 進行嘗試分配, 不行轉下一個zone (雖然這個操作, 我們之前已經做過了, 不過萬一呢?)
3.4 part 4
如果上述操作, 還是不成功的話, 就表明zone 中的頁面已經是嚴重短缺了。
==================== mm/page_alloc.c 365 399 ====================
[alloc_pages()>__alloc_pages()]
365 /*
366 * OK, none of the zones on our zonelist has lots
367 * of pages free.
368 *
369 * We wake up kswapd, in the hope that kswapd will
370 * resolve this situation before memory gets tight.
371 *
372 * We also yield the CPU, because that:
373 * - gives kswapd a chance to do something
374 * - slows down allocations, in particular the
375 * allocations from the fast allocator that's
376 * causing the problems ...
377 * - ... which minimises the impact the "bad guys"
378 * have on the rest of the system
379 * - if we don't have __GFP_IO set, kswapd may be
380 * able to free some memory we can't free ourselves
381 */
382 wakeup_kswapd(0);
383 if (gfp_mask & __GFP_WAIT) {
384 __set_current_state(TASK_RUNNING);
385 current->policy |= SCHED_YIELD;
386 schedule();
387 }
388
389 /*
390 * After waking up kswapd, we try to allocate a page
391 * from any zone which isn't critical yet.
392 *
393 * Kswapd should, in most situations, bring the situation
394 * back to normal in no time.
395 */
396 page = __alloc_pages_limit(zonelist, order, PAGES_MIN, direct_reclaim);
397 if (page)
398 return page;
399
我們喚醒內核線程kswapd, 讓他設法在換出一些頁面出來。 如果是一定要等待到分配的頁面的話, 就讓系統進行調度, schedule, 為kswapd 讓路。 然後再次嘗試分配。
3.5 part 5
==================== mm/page_alloc.c 400 477 ====================
[alloc_pages()>__alloc_pages()]
400 /*
401 * Damn, we didn't succeed.
402 *
403 * This can be due to 2 reasons:
404 * - we're doing a higher-order allocation
405 * --> move pages to the free list until we succeed
406 * - we're /really/ tight on memory
407 * --> wait on the kswapd waitqueue until memory is freed
408 */
409 if (!(current->flags & PF_MEMALLOC)) {
410 /*
411 * Are we dealing with a higher order allocation?
412 *
413 * Move pages from the inactive_clean to the free list
414 * in the hope of creating a large, physically contiguous
415 * piece of free memory.
416 */
417 if (order > 0 && (gfp_mask & __GFP_WAIT)) {
418 zone = zonelist->zones;
419 /* First, clean some dirty pages. */
420 current->flags |= PF_MEMALLOC;
421 page_launder(gfp_mask, 1);
422 current->flags &= ~PF_MEMALLOC;
423 for (;;) {
424 zone_t *z = *(zone++);
425 if (!z)
426 break;
427 if (!z->size)
428 continue;
429 while (z->inactive_clean_pages) {
430 struct page * page;
431 /* Move one page to the free list. */
432 page = reclaim_page(z);
433 if (!page)
434 break;
435 __free_page(page);
436 /* Try if the allocation succeeds. */
437 page = rmqueue(z, order);
438 if (page)
439 return page;
440 }
441 }
442 }
443 /*
444 * When we arrive here, we are really tight on memory.
445 *
446 * We wake up kswapd and sleep until kswapd wakes us
447 * up again. After that we loop back to the start.
448 *
449 * We have to do this because something else might eat
450 * the memory kswapd frees for us and we need to be
451 * reliable. Note that we don't loop back for higher
452 * order allocations since it is possible that kswapd
453 * simply cannot free a large enough contiguous area
454 * of memory *ever*.
455 */
456 if ((gfp_mask & (__GFP_WAIT|__GFP_IO)) == (__GFP_WAIT|__GFP_IO)) {
457 wakeup_kswapd(1);
458 memory_pressure++;
459 if (!order)
460 goto try_again;
461 /*
462 * If __GFP_IO isn't set, we can't wait on kswapd because
463 * kswapd just might need some IO locks /we/ are holding ...
464 *
465 * SUBTLE: The scheduling point above makes sure that
466 * kswapd does get the chance to free memory we can't
467 * free ourselves...
468 */
469 } else if (gfp_mask & __GFP_WAIT) {
470 try_to_free_pages(gfp_mask);
471 memory_pressure++;
472 if (!order)
473 goto try_again;
474 }
475
476 }
477
這是非內存分配者來進一步嘗試分配頁面的情形 這裡采用的方式是, 嘗試將不活躍髒頁面中的內容寫入交換區, 將他變為不活躍干淨頁面, 參與頁面分配。 如果回收之後, 還是不行, 兩種途徑: 要麼喚醒 kswapd ,自己休眠等待, 在kswapd完成一輪操作之後, 在讓他喚醒自己, 如果要求分配單個頁面的話, 就重新執行try_again 部分。 或者調用 try_to_free_pages 獲取一部分由髒頁面轉化過來的干淨頁面進行分配。 為什麼這裡只有當要求單個頁面, 才重新執行try_again 部分呢?個人的理解: 將髒頁面轉化成干淨頁面後, 不能保證頁面的連續性, 所以只能處理單個頁面的情形。我們認為系統中管理的頁面塊大小是不一樣的
3.6 part 6
我們前面的分配過程, 都是留了一點後路的, 每個zone 規定保留的水位 還是要高於 pages_min 的。這次我們決定搾干他。
==================== mm/page_alloc.c 478 521 ====================
[alloc_pages()>__alloc_pages()]
478 /*
479 * Final phase: allocate anything we can!
480 *
481 * Higher order allocations, GFP_ATOMIC allocations and
482 * recursive allocations (PF_MEMALLOC) end up here.
483 *
484 * Only recursive allocations can use the very last pages
485 * in the system, otherwise it would be just too easy to
486 * deadlock the system...
487 */
488 zone = zonelist->zones;
489 for (;;) {
490 zone_t *z = *(zone++);
491 struct page * page = NULL;
492 if (!z)
493 break;
494 if (!z->size)
495 BUG();
496
497 /*
498 * SUBTLE: direct_reclaim is only possible if the task
499 * becomes PF_MEMALLOC while looping above. This will
500 * happen when the OOM killer selects this task for
501 * instant execution...
502 */
503 if (direct_reclaim) {
504 page = reclaim_page(z);
505 if (page)
506 return page;
507 }
508
509 /* XXX: is pages_min/4 a good amount to reserve for this? */
510 if (z->free_pages < z->pages_min / 4 &&
511 !(current->flags & PF_MEMALLOC))
512 continue;
513 page = rmqueue(z, order);
514 if (page)
515 return page;
516 }
517
518 /* No luck.. */
519 printk(KERN_ERR "__alloc_pages: %lu-order allocation failed.\n", order);
520 return NULL;
521 }
這裡做的事情就是直接進入到zone 中進行分配, 不在考慮 zone 的水位保持的問題了。 如果這個操作也失敗了, 那就沒辦法了。
4. 主要的分配流程小結
在每個存儲節點上 pgdat_t 上嘗試分配
根據分配策略 zonelist 在每個管理區zone 上嘗試分配 (__alloc_pages)
在zone 管理區 的free_area 區域嘗試直接分配 在zone管理區 嘗試利用 free_area 和 inactive_clean_list 嘗試分配, 並降低對水位的要求 利用kswapd 交換出一些頁面來嘗試分配 將inactive_dirty_list 數據寫入交換區, 再嘗試分配 利用kswapd 釋放些頁面出來, 嘗試分配單個頁面 如果上面都不行, 不考慮水位要求, 直接在zone 上嘗試分配