この記事はLinux Advent Calendar 2014の10日目の記事です。
今回は前回の「slub:slab objectの作成処理を見ていく」で詳細を見なかったnew_slab()でpageを確保するところを見ていきます。
new_slab()では下記のようにallocate_slab()にてページの確保を行います。
1392 page = allocate_slab(s, 1393 flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node);
ここでpageを確保出来たらslab objectの設定をしていきます。今回はpageの確保部分を見たいのでallocate_slab()を見て行きましょう。
最初はページ確保時のgfpフラグの設定です。flagに__GFP_WAITが立っている場合は一連の処理中に待っても良いので割り込みを有効にしています。
1311 static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node) 1312 { 1313 struct page *page; 1314 struct kmem_cache_order_objects oo = s->oo; 1315 gfp_t alloc_gfp; 1316 1317 flags &= gfp_allowed_mask; 1318 1319 if (flags & __GFP_WAIT) 1320 local_irq_enable(); 1321 1322 flags |= s->allocflags; 1323 1324 /* 1325 * Let the initial higher-order allocation fail under memory pressure 1326 * so we fall-back to the minimum order allocation. 1327 */ 1328 alloc_gfp = (flags | __GFP_NOWARN | __GFP_NORETRY) & ~__GFP_NOFAIL; 1329
実際にページを確保しているのはalloc_slab_page()です。これは後で見ます。
1330 page = alloc_slab_page(s, alloc_gfp, node, oo);
もしpageの確保ができなかった場合は確保するページ数を減らして再度ページの確保を行います。
1331 if (unlikely(!page)) { 1332 oo = s->min; 1333 alloc_gfp = flags; 1334 /* 1335 * Allocation may have failed due to fragmentation. 1336 * Try a lower order alloc if possible 1337 */ 1338 page = alloc_slab_page(s, alloc_gfp, node, oo); 1339 1340 if (page) 1341 stat(s, ORDER_FALLBACK); 1342 } 1343
ここはkmemcheckによるデバッグ関連の部分なので飛ばしましょう。
1344 if (kmemcheck_enabled && page 1345 && !(s->flags & (SLAB_NOTRACK | DEBUG_DEFAULT_FLAGS))) { 1346 int pages = 1 << oo_order(oo); 1347 1348 kmemcheck_alloc_shadow(page, oo_order(oo), alloc_gfp, node); 1349 1350 /* 1351 * Objects from caches that have a constructor don't get 1352 * cleared when they're allocated, so we need to do it here. 1353 */ 1354 if (s->ctor) 1355 kmemcheck_mark_uninitialized_pages(page, pages); 1356 else 1357 kmemcheck_mark_unallocated_pages(page, pages); 1358 } 1359
割り込みを有効にしていた場合はここで無効に戻します。最終的には__slab_alloc()が最後にlocal_irq_restore()を実行し、元の状態に戻ります。
1360 if (flags & __GFP_WAIT) 1361 local_irq_disable();
pageが確保できなかったらNULLを返すしかありませんね。
1362 if (!page) 1363 return NULL; 1364
ooというのは
1365 page->objects = oo_objects(oo);
kmem_cache_order_objects構造体は以下のような構造です。
50 /* 51 * Word size structure that can be atomically updated or read and that 52 * contains both the order and the number of objects that a slab of the 53 * given order would contain. 54 */ 55 struct kmem_cache_order_objects { 56 unsigned long x; 57 };
oo_objectsは以下のようにandを取っているだけです。
340 static inline int oo_objects(struct kmem_cache_order_objects x) 341 { 342 return x.x & OO_MASK; 343 } 344
ここはvmstatの部分なので飛ばしてもOKかな。
1366 mod_zone_page_state(page_zone(page), 1367 (s->flags & SLAB_RECLAIM_ACCOUNT) ? 1368 NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE, 1369 1 << oo_order(oo)); 1370
最後に確保したページを返す。
1371 return page; 1372 }
先ほど飛ばしたalloc_slab_page()です。確保するpage数は先ほど見たkmem_cache_order_objects構造体にある数値からorderを算出します。これはoo_order()で以下のように行います。
335 static inline int oo_order(struct kmem_cache_order_objects x) 336 { 337 return x.x >> OO_SHIFT; 338 }
ではalloc_slab_page()の中身に。最初は確保するorderを計算。
1289 static inline struct page *alloc_slab_page(struct kmem_cache *s, 1290 gfp_t flags, int node, struct kmem_cache_order_objects oo) 1291 { 1292 struct page *page; 1293 int order = oo_order(oo); 1294
__GFP_NOTRACKはkmemcheckによるチェックをしないためらしい。
1295 flags |= __GFP_NOTRACK; 1296
memcg_charge_slab()はmemory control groupの処理でようは取得したいpage数のアカウンティングができるかどうかのチェックで、アカウンティングできないならメモリが確保できないのでNULLを返すということでしょう。
1297 if (memcg_charge_slab(s, flags, order)) 1298 return NULL; 1299
ここNUMAノードの指定の有無で呼ぶ関数が変わりますがバディシステムにpageの要求をします。
1300 if (node == NUMA_NO_NODE) 1301 page = alloc_pages(flags, order); 1302 else 1303 page = alloc_pages_exact_node(node, flags, order); 1304
pageを確保できなかったらチャージした分を元に戻します。
1305 if (!page) 1306 memcg_uncharge_slab(s, order); 1307
最後はpageを返す。
1308 return page; 1309 }
サーバ/インフラ徹底攻略 (WEB+DB PRESS plus)
- 作者: 伊藤直也,片山暁雄,平山毅,舟崎健治,吉荒祐一,今井雄太,八木橋徹平,安川健太,宮下剛輔,田中慎司,久保達彦,道井俊介,飯田祐基,桑野章弘,松浦隼人,中村俊之,福永亘,杉山仁則,WEB+DB PRESS編集部
- 出版社/メーカー: 技術評論社
- 発売日: 2014/10/30
- メディア: 大型本
- この商品を含むブログ (3件) を見る