歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux內存管理之slab機制(初始化)

Linux內存管理之slab機制(初始化)

日期:2017/2/28 15:59:55   编辑:Linux教程
一、內核啟動早期初始化

start_kernel()->mm_init()->kmem_cache_init()

執行流程:

1,初始化靜態initkmem_list3三鏈;

2,初始化cache_cache的nodelists字段為1中的三鏈;

3,根據內存情況初始化每個slab占用的頁面數變量slab_break_gfp_order;

4,將cache_cache加入cache_chain鏈表中,初始化cache_cache;

5,創建kmalloc所用的general cache:

1)cache的名稱和大小存放在兩個數據結構對應的數組中,對應大小的cache可以從size數組中找到;

2)先創建INDEX_AC和INDEX_L3下標的cache;

3)循環創建size數組中各個大小的cache;

6,替換靜態本地cache全局變量:

1) 替換cache_cache中的arry_cache,本來指向靜態變量initarray_cache.cache;

2) 替換malloc_sizes[INDEX_AC].cs_cachep的local cache,原本指向靜態變量initarray_generic.cache;

7,替換靜態三鏈

1)替換cache_cache三鏈,原本指向靜態變量initkmem_list3;

2)替換malloc_sizes[INDEX_AC].cs_cachep三鏈,原本指向靜態變量initkmem_list3;

8,更新初始化進度

  1. /*
  2. * Initialisation. Called after the page allocator have been initialised and
  3. * before smp_init().
  4. */
  5. void __init kmem_cache_init(void)
  6. {
  7. size_t left_over;
  8. struct cache_sizes *sizes;
  9. struct cache_names *names;
  10. int i;
  11. int order;
  12. int node;
  13. /* 在slab初始化好之前,無法通過kmalloc分配初始化過程中必要的一些對象
  14. ,只能使用靜態的全局變量
  15. ,待slab初始化後期,再使用kmalloc動態分配的對象替換全局變量 */
  16. /* 如前所述,先借用全局變量initkmem_list3表示的slab三鏈
  17. ,每個內存節點對應一組slab三鏈。initkmem_list3是個slab三鏈數組,對於每個內存節點,包含三組
  18. :struct kmem_cache的slab三鏈、struct arraycache_init的slab 三鏈、struct kmem_list3的slab三鏈
  19. 。這裡循環初始化所有內存節點的所有slab三鏈 */
  20. if (num_possible_nodes() == 1)
  21. use_alien_caches = 0;
  22. /*初始化所有node的所有slab中的三個鏈表*/
  23. for (i = 0; i < NUM_INIT_LISTS; i++) {
  24. kmem_list3_init(&initkmem_list3[i]);
  25. /* 全局變量cache_cache指向的slab cache包含所有struct kmem_cache對象,不包含cache_cache本身
  26. 。這裡初始化所有內存節點的struct kmem_cache的slab三鏈為空。*/
  27. if (i < MAX_NUMNODES)
  28. cache_cache.nodelists[i] = NULL;
  29. }
  30. /* 設置struct kmem_cache的slab三鏈指向initkmem_list3中的一組slab三鏈,
  31. CACHE_CACHE為cache在內核cache鏈表中的索引,
  32. struct kmem_cache對應的cache是內核中創建的第一個cache
  33. ,故CACHE_CACHE為0 */
  34. set_up_list3s(&cache_cache, CACHE_CACHE);
  35. /*
  36. * Fragmentation resistance on low memory - only use bigger
  37. * page orders on machines with more than 32MB of memory.
  38. */
  39. /* 全局變量slab_break_gfp_order為每個slab最多占用幾個頁面
  40. ,用來抑制碎片,比如大小為3360的對象
  41. ,如果其slab只占一個頁面,碎片為736
  42. ,slab占用兩個頁面,則碎片大小也翻倍
  43. 。只有當對象很大
  44. ,以至於slab中連一個對象都放不下時
  45. ,才可以超過這個值
  46. 。有兩個可能的取值
  47. :當可用內存大於32MB時
  48. ,BREAK_GFP_ORDER_HI為1
  49. ,即每個slab最多占用2個頁面
  50. ,只有當對象大小大於8192時
  51. ,才可以突破slab_break_gfp_order的限制
  52. 。小於等於32MB時BREAK_GFP_ORDER_LO為0。*/
  53. if (totalram_pages > (32 << 20) >> PAGE_SHIFT)
  54. slab_break_gfp_order = BREAK_GFP_ORDER_HI;
  55. /* Bootstrap is tricky, because several objects are allocated
  56. * from caches that do not exist yet:
  57. * 1) initialize the cache_cache cache: it contains the struct
  58. * kmem_cache structures of all caches, except cache_cache itself:
  59. * cache_cache is statically allocated.
  60. * Initially an __init data area is used for the head array and the
  61. * kmem_list3 structures, it's replaced with a kmalloc allocated
  62. * array at the end of the bootstrap.
  63. * 2) Create the first kmalloc cache.
  64. * The struct kmem_cache for the new cache is allocated normally.
  65. * An __init data area is used for the head array.
  66. * 3) Create the remaining kmalloc caches, with minimally sized
  67. * head arrays.
  68. * 4) Replace the __init data head arrays for cache_cache and the first
  69. * kmalloc cache with kmalloc allocated arrays.
  70. * 5) Replace the __init data for kmem_list3 for cache_cache and
  71. * the other cache's with kmalloc allocated memory.
  72. * 6) Resize the head arrays of the kmalloc caches to their final sizes.
  73. */
  74. node = numa_node_id();
  75. /* 1) create the cache_cache */
  76. /* 第一步,創建struct kmem_cache所在的cache,由全局變量cache_cache指向
  77. ,這裡只是初始化數據結構
  78. ,並未真正創建這些對象,要待分配時才創建。*/
  79. /* 全局變量cache_chain是內核slab cache鏈表的表頭 */
  80. INIT_LIST_HEAD(&cache_chain);
  81. /* 將cache_cache加入到slab cache鏈表 */
  82. list_add(&cache_cache.next, &cache_chain);
  83. /* 設置cache著色基本單位為cache line的大小:32字節 */
  84. cache_cache.colour_off = cache_line_size();
  85. /* 初始化cache_cache的local cache,同樣這裡也不能使用kmalloc
  86. ,需要使用靜態分配的全局變量initarray_cache */
  87. cache_cache.array[smp_processor_id()] = &initarray_cache.cache;
  88. /* 初始化slab鏈表 ,用全局變量*/
  89. cache_cache.nodelists[node] = &initkmem_list3[CACHE_CACHE + node];
  90. /*
  91. * struct kmem_cache size depends on nr_node_ids, which
  92. * can be less than MAX_NUMNODES.
  93. */
  94. /* buffer_size保存slab中對象的大小,這裡是計算struct kmem_cache的大小
  95. , nodelists是最後一個成員
  96. ,nr_node_ids保存內存節點個數,UMA為1
  97. ,所以nodelists偏移加上1個struct kmem_list3 的大小即為struct kmem_cache的大小 */
  98. cache_cache.buffer_size = offsetof(struct kmem_cache, nodelists) +
  99. nr_node_ids * sizeof(struct kmem_list3 *);
  100. #if DEBUG
  101. cache_cache.obj_size = cache_cache.buffer_size;
  102. #endif
  103. /* 將對象大小與cache line大小對齊 */
  104. cache_cache.buffer_size = ALIGN(cache_cache.buffer_size,
  105. cache_line_size());
  106. /* 計算對象大小的倒數,用於計算對象在slab中的索引 */
  107. cache_cache.reciprocal_buffer_size =
  108. reciprocal_value(cache_cache.buffer_size);
  109. for (order = 0; order < MAX_ORDER; order++) {
  110. /* 計算cache_cache中的對象數目 */
  111. cache_estimate(order, cache_cache.buffer_size,
  112. cache_line_size(), 0, &left_over, &cache_cache.num);
  113. /* num不為0意味著創建struct kmem_cache對象成功,退出 */
  114. if (cache_cache.num)
  115. break;
  116. }
  117. BUG_ON(!cache_cache.num);
  118. /* gfporder表示本slab包含2^gfporder個頁面 */
  119. cache_cache.gfporder = order;
  120. /* 著色區的大小,以colour_off為單位 */
  121. cache_cache.colour = left_over / cache_cache.colour_off;
  122. /* slab管理對象的大小 */
  123. cache_cache.slab_size = ALIGN(cache_cache.num * sizeof(kmem_bufctl_t) +
  124. sizeof(struct slab), cache_line_size());
  125. /* 2+3) create the kmalloc caches */
  126. /* 第二步,創建kmalloc所用的general cache
  127. ,kmalloc所用的對象按大小分級
  128. ,malloc_sizes保存大小,cache_names保存cache名 */
  129. sizes = malloc_sizes;
  130. names = cache_names;
  131. /*
  132. * Initialize the caches that provide memory for the array cache and the
  133. * kmem_list3 structures first. Without this, further allocations will
  134. * bug.
  135. */
  136. /* 首先創建struct array_cache和struct kmem_list3所用的general cache
  137. ,它們是後續初始化動作的基礎 */
  138. /* INDEX_AC是計算local cache所用的struct arraycache_init對象在kmalloc size中的索引
  139. ,即屬於哪一級別大小的general cache
  140. ,創建此大小級別的cache為local cache所用 */
  141. sizes[INDEX_AC].cs_cachep = kmem_cache_create(names[INDEX_AC].name,
  142. sizes[INDEX_AC].cs_size,
  143. ARCH_KMALLOC_MINALIGN,
  144. ARCH_KMALLOC_FLAGS|SLAB_PANIC,
  145. NULL);
  146. /* 如果struct kmem_list3和struct arraycache_init對應的kmalloc size索引不同
  147. ,即大小屬於不同的級別
  148. ,則創建struct kmem_list3所用的cache,否則共用一個cache */
  149. if (INDEX_AC != INDEX_L3) {
  150. sizes[INDEX_L3].cs_cachep =
  151. kmem_cache_create(names[INDEX_L3].name,
  152. sizes[INDEX_L3].cs_size,
  153. ARCH_KMALLOC_MINALIGN,
  154. ARCH_KMALLOC_FLAGS|SLAB_PANIC,
  155. NULL);
  156. }
  157. /* 創建完上述兩個general cache後,slab early init階段結束,在此之前
  158. ,不允許創建外置式slab */
  159. slab_early_init = 0;
  160. /* 循環創建kmalloc各級別的general cache */
  161. while (sizes->cs_size != ULONG_MAX) {
  162. /*
  163. * For performance, all the general caches are L1 aligned.
  164. * This should be particularly beneficial on SMP boxes, as it
  165. * eliminates "false sharing".
  166. * Note for systems short on memory removing the alignment will
  167. * allow tighter packing of the smaller caches.
  168. */
  169. /* 某級別的kmalloc cache還未創建,創建之,struct kmem_list3和
  170. struct arraycache_init對應的cache已經創建過了 */
  171. if (!sizes->cs_cachep) {
  172. sizes->cs_cachep = kmem_cache_create(names->name,
  173. sizes->cs_size,
  174. ARCH_KMALLOC_MINALIGN,
  175. ARCH_KMALLOC_FLAGS|SLAB_PANIC,
  176. NULL);
  177. }
  178. #ifdef CONFIG_ZONE_DMA
  179. sizes->cs_dmacachep = kmem_cache_create(
  180. names->name_dma,
  181. sizes->cs_size,
  182. ARCH_KMALLOC_MINALIGN,
  183. ARCH_KMALLOC_FLAGS|SLAB_CACHE_DMA|
  184. SLAB_PANIC,
  185. NULL);
  186. #endif
  187. sizes++;
  188. names++;
  189. }
  190. /* 至此,kmalloc general cache已經創建完畢,可以拿來使用了 */
  191. /* 4) Replace the bootstrap head arrays */
  192. /* 第四步,用kmalloc對象替換靜態分配的全局變量
  193. 。到目前為止一共使用了兩個全局local cache
  194. ,一個是cache_cache的local cache指向initarray_cache.cache
  195. ,另一個是malloc_sizes[INDEX_AC].cs_cachep的local cache指向initarray_generic.cache
  196. ,參見setup_cpu_cache函數。這裡替換它們。*/
  197. {
  198. struct array_cache *ptr;
  199. /* 申請cache_cache所用local cache的空間 */
  200. ptr = kmalloc(sizeof(struct arraycache_init), GFP_NOWAIT);
  201. BUG_ON(cpu_cache_get(&cache_cache) != &initarray_cache.cache);
  202. /* 復制原cache_cache的local cache,即initarray_cache,到新的位置 */
  203. memcpy(ptr, cpu_cache_get(&cache_cache),
  204. sizeof(struct arraycache_init));
  205. /*
  206. * Do not assume that spinlocks can be initialized via memcpy:
  207. */
  208. spin_lock_init(&ptr->lock);
  209. /* cache_cache的local cache指向新的位置 */
  210. cache_cache.array[smp_processor_id()] = ptr;
  211. /* 申請malloc_sizes[INDEX_AC].cs_cachep所用local cache的空間 */
  212. ptr = kmalloc(sizeof(struct arraycache_init), GFP_NOWAIT);
  213. BUG_ON(cpu_cache_get(malloc_sizes[INDEX_AC].cs_cachep)
  214. != &initarray_generic.cache);
  215. /* 復制原local cache到新分配的位置,注意此時local cache的大小是固定的 */
  216. memcpy(ptr, cpu_cache_get(malloc_sizes[INDEX_AC].cs_cachep),
  217. sizeof(struct arraycache_init));
  218. /*
  219. * Do not assume that spinlocks can be initialized via memcpy:
  220. */
  221. spin_lock_init(&ptr->lock);
  222. malloc_sizes[INDEX_AC].cs_cachep->array[smp_processor_id()] =
  223. ptr;
  224. }
  225. /* 5) Replace the bootstrap kmem_list3's */
  226. /* 第五步,與第四步類似,用kmalloc的空間替換靜態分配的slab三鏈 */
  227. {
  228. int nid;
  229. /* UMA只有一個節點 */
  230. for_each_online_node(nid) {
  231. /* 復制struct kmem_cache的slab三鏈 */
  232. init_list(&cache_cache, &initkmem_list3[CACHE_CACHE + nid], nid);
  233. /* 復制struct arraycache_init的slab三鏈 */
  234. init_list(malloc_sizes[INDEX_AC].cs_cachep,
  235. &initkmem_list3[SIZE_AC + nid], nid);
  236. /* 復制struct kmem_list3的slab三鏈 */
  237. if (INDEX_AC != INDEX_L3) {
  238. init_list(malloc_sizes[INDEX_L3].cs_cachep,
  239. &initkmem_list3[SIZE_L3 + nid], nid);
  240. }
  241. }
  242. }
  243. /* 更新slab系統初始化進度 */
  244. g_cpucache_up = EARLY;
  245. }
Copyright © Linux教程網 All Rights Reserved