<kernel v5.0>
슬랩 페이지 해제
다음 그림은 해제할 slub page가 free_slab() 함수를 통해 버디 시스템으로 돌아가기까지의 흐름을 보여준다.

free_slab()
mm/slub.c
1 | static void free_slab( struct kmem_cache *s, struct page *page) |
3 | if (unlikely(s->flags & SLAB_TYPESAFE_BY_RCU)) { |
4 | call_rcu(&page->rcu_head, rcu_free_slab); |
슬랩 페이지를 해제하여 버디 시스템으로 돌려보낸다.
- 코드 라인 3~4에서 적은 확률로 슬랩 해제에 lock-less rcu를 사용하여 버디 시스템에 회수시킨다.
- 코드 라인 5~6에서 즉각 슬랩 페이지를 버디 시스템에 회수시킨다.
rcu_free_slab()
mm/slub.c
1 | static void rcu_free_slab( struct rcu_head *h) |
3 | struct page *page = container_of(h, struct page, rcu_head); |
5 | __free_slab(page->slab_cache, page); |
슬랩 페이지를 버디 시스템으로 회수시킨다. 이 함수는 rcu를 통해 호출된다.
__free_slab()
mm/slub.c
01 | static void __free_slab( struct kmem_cache *s, struct page *page) |
03 | int order = compound_order(page); |
04 | int pages = 1 << order; |
06 | if (s->flags & SLAB_CONSISTENCY_CHECKS) { |
09 | slab_pad_check(s, page); |
10 | for_each_object(p, s, page_address(page), |
12 | check_object(s, page, p, SLUB_RED_INACTIVE); |
15 | mod_lruvec_page_state(page, |
16 | (s->flags & SLAB_RECLAIM_ACCOUNT) ? |
17 | NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE, |
20 | __ClearPageSlabPfmemalloc(page); |
21 | __ClearPageSlab(page); |
24 | if (current->reclaim_state) |
25 | current->reclaim_state->reclaimed_slab += pages; |
26 | memcg_uncharge_slab(page, order, s); |
27 | __free_pages(page, order); |
슬랩 페이지를 해제하여 버디 시스템으로 회수시킨다.
- 코드 라인 3~4에서 슬랩 페이지는 compound 페이지로 구성 가능하다. 따라서 해당하는 order 값과 페이지 수를 알아온다.
- 코드 라인 6~13에서 SLAB_CONSISTENCY_CHECKS 플래그를 사용한 경우 슬랩 페이지에 대한 consistency 체크를 다음과 같이 수행한다.
- 슬랩 페이지에 대한 패딩을 확인한다.
- 각 슬랩 object의 red-zone을 확인하여 SLUB_RED_INACTIVE(0xbb)인지 확인한다.
- 코드 라인 15~18에서 reclaimable 슬랩 캐시인 경우 NR_SLAB_RECLAIMABLE 카운터를, 아닌 경우 NR_SLAB_UNRECLAIMABLE 카운터를 페이지 수만큼 감소시킨다.
- 코드 라인 20~23에서 PG_active 및 PG_slab 를 클리어하고 페이지 매핑 연결도 해제한다.
- 코드 라인 24~25에서 현재 태스크의 회수 상태가 설정된 경우 reclaimed_slab을 페이지 수 만큼 더한다.
- 코드 라인 26에서 memory cgroup으로 slab 페이지가 회수되었다는 것을 알려 counting에서 감소시키게 한다.
- 코드 라인 27에서 버디 시스템으로 페이지를 order 수 만큼 회수시킨다.
memcg_uncharge_slab()
mm/slab.h
1 | static __always_inline void memcg_uncharge_slab( struct page *page, int order, |
4 | if (!memcg_kmem_enabled()) |
6 | memcg_kmem_uncharge(page, order); |
CONFIG_MEMCG_KMEM 커널 옵션을 사용하면서 memcg_kmem이 활성화된 경우 memory cgroup으로 슬랩 페이지가 회수되었다는 것을 알려 counting에서 감소시키게 한다. 단 루트 캐시인 경우 처리하지 않고 루틴을 빠져나간다.
참고