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

Linux內存管理之slab機制(創建slab)

日期:2017/2/28 15:59:54   编辑:Linux教程
Linux內核中創建slab主要由函數cache_grow()實現,從slab的創建中我們可以完整地看到slab與對象、頁面的組織方式。
  1. /*
  2. * Grow (by 1) the number of slabs within a cache. This is called by
  3. * kmem_cache_alloc() when there are no active objs left in a cache.
  4. */
  5. /*使用一個或多個頁面創建一個空slab。
  6. objp:頁面虛擬地址,為空表示還未申請內存頁,不為空
  7. ,說明已申請內存頁,可直接用來創建slab*/
  8. static int cache_grow(struct kmem_cache *cachep,
  9. gfp_t flags, int nodeid, void *objp)
  10. {
  11. struct slab *slabp;
  12. size_t offset;
  13. gfp_t local_flags;
  14. struct kmem_list3 *l3;
  15. /*
  16. * Be lazy and only check for valid flags here, keeping it out of the
  17. * critical path in kmem_cache_alloc().
  18. */
  19. BUG_ON(flags & GFP_SLAB_BUG_MASK);
  20. local_flags = flags & (GFP_CONSTRAINT_MASK|GFP_RECLAIM_MASK);
  21. /* Take the l3 list lock to change the colour_next on this node */
  22. check_irq_off();
  23. /* 獲得本內存節點的slab三鏈 */
  24. l3 = cachep->nodelists[nodeid];
  25. spin_lock(&l3->list_lock);
  26. /* Get colour for the slab, and cal the next value. */
  27. /* 獲得本slab的著色區偏移 */
  28. offset = l3->colour_next;
  29. /* 更新著色區偏移,使不同slab的著色偏移不同 */
  30. l3->colour_next++;
  31. /* 不能超過著色區的總大小,如果超過了,重置為0。這就是前面分析過的著色循環問題
  32. 。事實上,如果slab中浪費的空間很少,那麼很快就會循環一次。*/
  33. if (l3->colour_next >= cachep->colour)
  34. l3->colour_next = 0;
  35. spin_unlock(&l3->list_lock);
  36. /* 將著色單位區間的個數轉換為著色區大小 */
  37. offset *= cachep->colour_off;
  38. if (local_flags & __GFP_WAIT)
  39. local_irq_enable();
  40. /*
  41. * The test for missing atomic flag is performed here, rather than
  42. * the more obvious place, simply to reduce the critical path length
  43. * in kmem_cache_alloc(). If a caller is seriously mis-behaving they
  44. * will eventually be caught here (where it matters).
  45. */
  46. kmem_flagcheck(cachep, flags);
  47. /*
  48. * Get mem for the objs. Attempt to allocate a physical page from
  49. * 'nodeid'.
  50. */
  51. if (!objp)/* 還未分配頁面,從本內存節點分配1<<cachep->gfporder個頁面
  52. ,objp為slab首頁面的虛擬地址 */
  53. objp = kmem_getpages(cachep, local_flags, nodeid);
  54. if (!objp)
  55. goto failed;
  56. /* Get slab management. */
  57. /* 分配slab管理對象 */
  58. slabp = alloc_slabmgmt(cachep, objp, offset,
  59. local_flags & ~GFP_CONSTRAINT_MASK, nodeid);
  60. if (!slabp)
  61. goto opps1;
  62. /* 設置page到cache、slab的映射 */
  63. slab_map_pages(cachep, slabp, objp);
  64. /* 初始化slab中的對象 */
  65. cache_init_objs(cachep, slabp);
  66. if (local_flags & __GFP_WAIT)
  67. local_irq_disable();
  68. check_irq_off();
  69. spin_lock(&l3->list_lock);
  70. /* Make slab active. */
  71. list_add_tail(&slabp->list, &(l3->slabs_free));
  72. /* 更新本cache增長計數 */
  73. STATS_INC_GROWN(cachep);
  74. /* 更新slab鏈表中空閒對象計數 */
  75. l3->free_objects += cachep->num;
  76. spin_unlock(&l3->list_lock);
  77. return 1;
  78. opps1:
  79. kmem_freepages(cachep, objp);
  80. failed:
  81. if (local_flags & __GFP_WAIT)
  82. local_irq_disable();
  83. return 0;
  84. }

執行流程:

1,從cache結構中獲得並計算著色區偏移量;

2,從伙伴系統中獲得1<<cachep->gfporder個頁面用於slab;

3,初始化slab中相關變量,如果是外置式slab需要從新申請slab管理區的空間,由函數alloc_slabmgmt()實現。

  1. /*分配slab管理對象*/
  2. static struct slab *alloc_slabmgmt(struct kmem_cache *cachep, void *objp,
  3. int colour_off, gfp_t local_flags,
  4. int nodeid)
  5. {
  6. struct slab *slabp;
  7. if (OFF_SLAB(cachep)) {
  8. /* Slab management obj is off-slab. */
  9. /* 外置式slab。從general slab cache中分配一個管理對象,
  10. slabp_cache指向保存有struct slab對象的general slab cache。
  11. slab初始化階段general slab cache可能還未創建,slabp_cache指針為空
  12. ,故初始化階段創建的slab均為內置式slab。*/
  13. slabp = kmem_cache_alloc_node(cachep->slabp_cache,
  14. local_flags, nodeid);
  15. /*
  16. * If the first object in the slab is leaked (it's allocated
  17. * but no one has a reference to it), we want to make sure
  18. * kmemleak does not treat the ->s_mem pointer as a reference
  19. * to the object. Otherwise we will not report the leak.
  20. *//* 對第一個對象做檢查 */
  21. kmemleak_scan_area(slabp, offsetof(struct slab, list),
  22. sizeof(struct list_head), local_flags);
  23. if (!slabp)
  24. return NULL;
  25. } else {/* 內置式slab。objp為slab首頁面的虛擬地址,加上著色偏移
  26. ,得到slab管理對象的虛擬地址 */
  27. slabp = objp + colour_off;
  28. /* 計算slab中第一個對象的頁內偏移,slab_size保存slab管理對象的大小
  29. ,包含struct slab對象和kmem_bufctl_t數組 */
  30. colour_off += cachep->slab_size;
  31. } /* 在用(已分配)對象數為0 */
  32. slabp->inuse = 0;
  33. /* 第一個對象的頁內偏移,可見對於內置式slab,colouroff成員不僅包括著色區
  34. ,還包括管理對象占用的空間
  35. ,外置式slab,colouroff成員只包括著色區。*/
  36. slabp->colouroff = colour_off;
  37. /* 第一個對象的虛擬地址 */
  38. slabp->s_mem = objp + colour_off;
  39. /* 內存節點ID */
  40. slabp->nodeid = nodeid;
  41. /* 第一個空閒對象索引為0,即kmem_bufctl_t數組的第一個元素 */
  42. slabp->free = 0;
  43. return slabp;
  44. }
Copyright © Linux教程網 All Rights Reserved