<kernel v5.0>
kmem_cache_shrink()
mm/slab_common.c
2 | * kmem_cache_shrink - Shrink a cache. |
3 | * @cachep: The cache to shrink. |
5 | * Releases as many slabs as possible for a cache. |
6 | * To help debugging, a zero exit status indicates all slabs were released. |
01 | int kmem_cache_shrink( struct kmem_cache *cachep) |
07 | ret = __kmem_cache_shrink(cachep); |
12 | EXPORT_SYMBOL(kmem_cache_shrink); |
요청한 슬랩 캐시에서 해지가능한 슬랩 페이지들을 찾아 모두 해지시킨다.
__kmem_cache_shrink()
mm/slub.c
2 | * kmem_cache_shrink discards empty slabs and promotes the slabs filled |
3 | * up most to the head of the partial lists. New allocations will then |
4 | * fill those up and thus they can be removed from the partial lists. |
6 | * The slabs with the least items are placed last. This results in them |
7 | * being allocated from last increasing the chance that the last objects |
01 | int __kmem_cache_shrink( struct kmem_cache *s) |
05 | struct kmem_cache_node *n; |
08 | struct list_head discard; |
09 | struct list_head promote[SHRINK_PROMOTE_MAX]; |
14 | for_each_kmem_cache_node(s, node, n) { |
15 | INIT_LIST_HEAD(&discard); |
16 | for (i = 0; i < SHRINK_PROMOTE_MAX; i++) |
17 | INIT_LIST_HEAD(promote + i); |
19 | spin_lock_irqsave(&n->list_lock, flags); |
27 | list_for_each_entry_safe(page, t, &n->partial, lru) { |
28 | int free = page->objects - page->inuse; |
36 | if ( free == page->objects) { |
37 | list_move(&page->lru, &discard); |
39 | } else if ( free <= SHRINK_PROMOTE_MAX) |
40 | list_move(&page->lru, promote + free - 1); |
47 | for (i = SHRINK_PROMOTE_MAX - 1; i >= 0; i--) |
48 | list_splice(promote + i, &n->partial); |
50 | spin_unlock_irqrestore(&n->list_lock, flags); |
53 | list_for_each_entry_safe(page, t, &discard, lru) |
54 | discard_slab(s, page); |
56 | if (slabs_node(s, node)) |
요청한 슬랩 캐시에서 해지가능한 슬랩 페이지들을 찾아 모두 해지시키기 위해 다음과 같은 과정을 수행한다.
- n->partial 리스트의 슬랩 페이지들 중 사용중인 object가 없는 경우 슬랩 페이지들을 버디 시스템으로 되돌린다.
- n->partial 리스트의 슬랩 페이지들 중 32개 미만의 free object들은 asscending 정렬한다.
- 코드 라인 13에서 슬랩 캐시의 per cpu 슬랩 페이지들을 모두 n->partial 리스트로 옮긴다.
- 코드 라인 14~17에서 슬랩 캐시의 노드를 순회하며 discard 리스트를 초기화하고, SHRINK_PROMOTE_MAX(32) 만큼 promote[] 리스트를 초기화한다.
- 코드 라인 27~41에서 n->partial 리스트의 슬랩 페이지들을 순회하며 object가 모두 free object들로 구성된 슬랩 페이지는 discard 리스트에 추가하고, free object 수가 SHRINK_PROMOTE_MAX(32) 이하인 경우 promote[free-1] 리스트에 추가한다.
- 코드 라인 47~48에서 n->partial 리스트의 선두에 promote[i] 리스트를 추가한다.
- 결국 free object가 1~32개 순으로 정렬되어 선두에 추가된다.
- 가장 선두에 free object가 가장 적은 슬랩 페이지를 위로 배치하여 object 할당 시 슬랩 페이지가 리스트 관리에서 빨리 없어질 수 있게 한다.
- 코드 라인 53~54에서 discard 리스트에 있는 슬랩 페이지들을 모두 해제하여 버디 시스템으로 돌려준다.
- 코드 라인 56~57에서 slub 디버그깅 중에 노드에 슬랩이 남아있는 경우 함수 종료 시 1을 반환하게 한다.
다음 그림은 현재 슬랩 캐시의 모든 슬랩 페이지들을 n->partial 리스트로 옮기고 정리하는 모습을 보여준다.

kick_all_cpus_sync()
kernel/smp.c
02 | * kick_all_cpus_sync - Force all cpus out of idle |
04 | * Used to synchronize the update of pm_idle function pointer. It's |
05 | * called after the pointer is updated and returns after the dummy |
06 | * callback function has been executed on all cpus. The execution of |
07 | * the function can only happen on the remote cpus after they have |
08 | * left the idle function which had been called via pm_idle function |
09 | * pointer. So it's guaranteed that nothing uses the previous pointer |
1 | void kick_all_cpus_sync( void ) |
5 | smp_call_function(do_nothing, NULL, 1); |
7 | EXPORT_SYMBOL_GPL(kick_all_cpus_sync); |
IPI call을 사용하여 각 cpu를 호출하여 더미 callback을 수행시키게 한다.
- pm_idle 함수 포인터의 update의 동기화를 하는데 사용된다.
- do_nothing()은 비어 있는 함수이다.
참고