歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux教程

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

一、內核啟動早期初始化

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