*参照元 [#mfe86fff]
#backlinks

*説明 [#wc78abef]
-パス: [[linux-4.4.1/mm/page_alloc.c]]

-FIXME: これは何?
--説明


**引数 [#v6e491d4]
-struct zone *preferred_zone
--
--[[linux-4.4.1/zone]]
-struct zone *zone
--
--[[linux-4.4.1/zone]]
-unsigned int order
--
-gfp_t gfp_flags
--
--[[linux-4.4.1/gfp_t]]
-int alloc_flags
--
-int migratetype
--


**返り値 [#r0956db3]
-struct page *
--
--[[linux-4.4.1/page]]


**参考 [#k381a8c9]


*実装 [#h66b6139]
 /*
  * Allocate a page from the given zone. Use pcplists for order-0 allocations.
  */
 static inline
 struct page *buffered_rmqueue(struct zone *preferred_zone,
 			struct zone *zone, unsigned int order,
 			gfp_t gfp_flags, int alloc_flags, int migratetype)
 {
 	unsigned long flags;
 	struct page *page;
 	bool cold = ((gfp_flags & __GFP_COLD) != 0);
 
-
--[[linux-4.4.1/__GFP_COLD]]

 	if (likely(order == 0)) {
 		struct per_cpu_pages *pcp;
 		struct list_head *list;
 
-オーダー 0 つまり 1 ページだけ割り当てる場合。
--[[linux-4.4.1/likely()]]
--[[linux-4.4.1/per_cpu_pages]]
--[[linux-4.4.1/list_head]]

 		local_irq_save(flags);
 		pcp = &this_cpu_ptr(zone->pageset)->pcp;
 		list = &pcp->lists[migratetype];
 		if (list_empty(list)) {
 			pcp->count += rmqueue_bulk(zone, 0,
 					pcp->batch, list,
 					migratetype, cold);
 			if (unlikely(list_empty(list)))
 				goto failed;
 		}
 
-
--[[linux-4.4.1/local_irq_save()]]
--[[linux-4.4.1/this_cpu_ptr()]]
--[[linux-4.4.1/rmqueue_bulk()]]
--[[linux-4.4.1/unlikely()]]
--[[linux-4.4.1/list_empty()]]

 		if (cold)
 			page = list_entry(list->prev, struct page, lru);
 		else
 			page = list_entry(list->next, struct page, lru);
 
 		list_del(&page->lru);
 		pcp->count--;
-cold ならリストの終端から、そうでなければリストの先頭からページを取得する。
--リストの先頭は「最近使われた可能性が高い」ため、CPU のキャッシュに載っている可能性も高い。
逆に cold で最も古いページが割り当てられる保証は考慮されない。それなりに古いページが来るようにはなっている。
--例えば hot のみ解放した場合、リストの終端は最も古いページになる。
hot と cold を混ぜて解放した場合、リストの中央部が最も古いページになってしまう。
 hot を 3つ、cold 3つ、hot 3つの順で解放すると、
 (1) hot 3つ
 h2 h1 h0
 (2) cold 3つ
 h2 h1 h0 c3 c4 c5
 (3) hot 3つ
 h8 h7 h6 h2 h1 h0 c3 c4 c5
--[[linux-4.4.1/list_entry()]]
--[[linux-4.4.1/list_del()]]
-list にページを追加する関数は下記の通り。
cold なら list_add_tail つまり終端に追加し、hot なら list_add つまり先頭に追加している。
--[[linux-4.4.1/free_hot_cold_page()]]

 	} else {

-オーダー 0 以外、つまり複数の物理連続ページを割り当てる場合。

 		if (unlikely(gfp_flags & __GFP_NOFAIL)) {
 			/*
 			 * __GFP_NOFAIL is not to be used in new code.
 			 *
 			 * All __GFP_NOFAIL callers should be fixed so that they
 			 * properly detect and handle allocation failures.
 			 *
 			 * We most definitely don't want callers attempting to
 			 * allocate greater than order-1 page units with
 			 * __GFP_NOFAIL.
 			 */
 			WARN_ON_ONCE(order > 1);
 		}

-
--[[linux-4.4.1/__GFP_NOFAIL]]
--[[linux-4.4.1/WARN_ON_ONCE()]]

 		spin_lock_irqsave(&zone->lock, flags);
 
-zone のロックを取得する。
--__rmqueue 系の関数を呼ぶときはこのロックが必要。
--[[linux-4.4.1/spin_lock_irqsave()]]

 		page = NULL;
 		if (alloc_flags & ALLOC_HARDER) {
 			page = __rmqueue_smallest(zone, order, MIGRATE_HIGHATOMIC);
 			if (page)
 				trace_mm_page_alloc_zone_locked(page, order, migratetype);
 		}
-
-ALLOC_HARDER が指定されているなら、
MIGRATE_HIGHATOMIC リストからメモリを割り当てる。
--[[linux-4.4.1/__rmqueue_smallest()]]
--[[linux-4.4.1/trace_mm_page_alloc_zone_locked()]]
--[[linux-4.4.1/MIGRATE_HIGHATOMIC]]

 		if (!page)
 			page = __rmqueue(zone, order, migratetype, gfp_flags);
 		spin_unlock(&zone->lock);
-
--[[linux-4.4.1/__rmqueue()]]
--[[linux-4.4.1/spin_unlock()]]

 		if (!page)
 			goto failed;
 		__mod_zone_freepage_state(zone, -(1 << order),
 					  get_pcppage_migratetype(page));
-
--[[linux-4.4.1/__mod_zone_freepage_state()]]
--[[linux-4.4.1/get_pcppage_migratetype()]]

 	}
 
 	__mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order));
 	if (atomic_long_read(&zone->vm_stat[NR_ALLOC_BATCH]) <= 0 &&
 	    !test_bit(ZONE_FAIR_DEPLETED, &zone->flags))
 		set_bit(ZONE_FAIR_DEPLETED, &zone->flags);
 
-
--[[linux-4.4.1/__mot_zone_page_state()]]
--[[linux-4.4.1/atomic_long_read()]]
--[[linux-4.4.1/test_bit()]]
--[[linux-4.4.1/set_bit()]]

 	__count_zone_vm_events(PGALLOC, zone, 1 << order);
 	zone_statistics(preferred_zone, zone, gfp_flags);
 	local_irq_restore(flags);
 
-
--[[linux-4.4.1/__count_zone_vm_events()]]
--[[linux-4.4.1/zone_statistics()]]
--[[linux-4.4.1/local_irq_restore()]]

 	VM_BUG_ON_PAGE(bad_range(zone, page), page);
 	return page;
 
-
--[[linux-4.4.1/VM_BUG_ON_PAGE()]]
--[[linux-4.4.1/bad_range()]]

 failed:
 	local_irq_restore(flags);
 	return NULL;
 }


*コメント [#r91da1a3]

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS