*参照元 [#x8596b7f] #backlinks *説明 [#kb2ef2cc] -パス: [[linux-4.4.1/mm/page_alloc.c]] -FIXME: これは何? --説明 -free_list から取得した領域は大きすぎる可能性があるため、 余分な領域を分割して、小さい領域用の free_area に追加する。 --例えば、要求されたサイズが 2(オーダー 2, 4 pages)なのに、 free_list から取得した領域が 5(オーダー 5, 32 pages)だとする。 --32 pages の領域を 4, 4, 8, 16 と分割し、先頭の 4 pages 以外を使い、他は空き領域として free_list に追加する。 --32 pages の領域を 4, 4, 8, 16 と分割し、先頭の 4 pages を使い、他は空き領域として free_list に追加する。 -処理の例 --上記の例だと area = order 5 用のエリア, low = 2, high = 5, size = 32 で始まる。 while 1回目 area = order 4 用のエリア high = 4 size = 16 page[16] を free_list に追加 area の空き領域数を 1 追加 page[16] の page_order を 4 に設定 page 0 4 8 16 31 |....|....|....|....|....|....|....|....| |<--- ここ処理した -->| | 先頭は page[16] while 2回目 area = order 3 用のエリア high = 3 size = 8 page[8] を free_list に追加 area の空き領域数を 1 追加 page[8] の page_order を 4 に設定 page 0 4 8 16 31 |....|....|....|....| 空き | |<- ここ->| | 先頭は page[8] while 3回目 area = order 2 用のエリア high = 2 size = 4 page[4] を free_list に追加 area の空き領域数を 1 追加 page[4] の page_order を 2 に設定 page 0 4 8 16 31 |....|....| 空き | 空き | |<-->| | 先頭は page[4] おしまい page 0 4 8 16 31 |....|空き| 空き | 空き | **引数 [#f49edaa7] -struct zone *zone --ゾーン --[[linux-4.4.1/zone]] -struct page *page --ページ --[[linux-4.4.1/page]] -int low --実際に必要なサイズのオーダー -int high --確保できた空き領域のオーダー -struct free_area *area --フリーエリア --オーダー high 用のエリアを指していなければならない。 --[[linux-4.4.1/free_area]] -int migratetype --マイグレーションの種類 --どの free_list に空き領域を追加するか決めるために使う。 **返り値 [#ndacdd79] -void **参考 [#mea210a4] *実装 [#efaf0a49] /* * The order of subdivision here is critical for the IO subsystem. * Please do not alter this order without good reasons and regression * testing. Specifically, as large blocks of memory are subdivided, * the order in which smaller blocks are delivered depends on the order * they're subdivided in this function. This is the primary factor * influencing the order in which pages are delivered to the IO * subsystem according to empirical testing, and this is also justified * by considering the behavior of a buddy system containing a single * large block of memory acted on by a series of small allocations. * This behavior is a critical factor in sglist merging's success. * * -- nyc */ static inline void expand(struct zone *zone, struct page *page, int low, int high, struct free_area *area, int migratetype) { unsigned long size = 1 << high; while (high > low) { area--; high--; size >>= 1; VM_BUG_ON_PAGE(bad_range(zone, &page[size]), &page[size]); -1つ小さいオーダーの free_area を選択する。 --[[linux-4.4.1/VM_BUG_ON_PAGE()]] --[[linux-4.4.1/bad_range()]] if (IS_ENABLED(CONFIG_DEBUG_PAGEALLOC) && debug_guardpage_enabled() && high < debug_guardpage_minorder()) { - --[[linux-4.4.1/IS_ENABLED()]] --[[linux-4.4.1/CONFIG_DEBUG_PAGEALLOC]] --[[linux-4.4.1/debug_guardpage_enabled()]] --[[linux-4.4.1/debug_guardpage_minorder()]] /* * Mark as guard pages (or page), that will allow to * merge back to allocator when buddy will be freed. * Corresponding page table entries will not be touched, * pages will stay not present in virtual address space */ set_page_guard(zone, &page[size], high, migratetype); continue; - --[[linux-4.4.1/set_page_guard()]] } list_add(&page[size].lru, &area->free_list[migratetype]); area->nr_free++; set_page_order(&page[size], high); -オーダー high 用の free_area の free_list に空き領域を追加する。 --[[linux-4.4.1/list_add()]] -page_order を high の値に設定する。 --[[linux-4.4.1/set_page_order()]] } } *コメント [#p1172d9c]