<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          LWN:5.17 中的struct slab!

          共 4634字,需瀏覽 10分鐘

           ·

          2022-03-18 15:08


          關(guān)注了就能看到更多這么棒的文章哦~

          Struct slab comes to 5.17

          By Jonathan Corbet
          January 14, 2022
          DeepL assisted translation
          https://lwn.net/Articles/881039/

          正在進(jìn)行的 memory folio 工作已經(jīng)在內(nèi)核的大部分地方產(chǎn)生了波及,并激發(fā)出了一些輔助項(xiàng)目(side project),其中之一就是從 struct page 中移除 slab 特定的一些字段。這項(xiàng)工作在 5.17 版本的內(nèi)核中已被合入 mainline,因此,現(xiàn)在是一個(gè)很好的時(shí)機(jī)來了解 struct slab 的狀況,以及了解為什么這項(xiàng)工作很重要了。

          struct page and struct slab

          page structure 是內(nèi)存管理子系統(tǒng)的核心。系統(tǒng)中的每一個(gè)物理內(nèi)存 page 都對(duì)應(yīng)著這樣一個(gè)結(jié)構(gòu),用它們來跟蹤相應(yīng)內(nèi)存的狀態(tài),隨著內(nèi)存在系統(tǒng)的生命周期中被使用、釋放和重用,都需要用到它。隨著時(shí)間的推移,物理 page 可以采用許多不同的形式了,它們可以放置用戶空間的數(shù)據(jù),或者內(nèi)核數(shù)據(jù)結(jié)構(gòu),又或者是 DMA buffer 等等。不管某個(gè) page 是如何使用的,都是使用 struct page 來作為跟蹤其狀態(tài)的數(shù)據(jù)結(jié)構(gòu)。這些 struct 存放在一個(gè) discontinuous array 中(也稱為 system memory map )。

          這種做法也出現(xiàn)了一些問題。4.18 版本對(duì) page structure 進(jìn)行了大規(guī)模的重寫,但 struct page 的定義仍然包含很多 #ifdefs 并且使用了 unions 來構(gòu)成的一個(gè)復(fù)雜的混合物,沒有任何機(jī)制來確保人們總是能使用正確的字段(field )。開發(fā)者如果需要在這個(gè)結(jié)構(gòu)中利用一些字節(jié)的話,很不幸,很難確定出哪些 bit 可以安全地使用起來。子系統(tǒng)通常在設(shè)計(jì)上都會(huì)隱藏其內(nèi)部的數(shù)據(jù)結(jié)構(gòu),但是 struct page 卻在整個(gè)內(nèi)核里面到處都在使用,因此導(dǎo)致在內(nèi)存管理中做任何改變都面臨著更加復(fù)雜的情況。人們希望通過確保不用每個(gè) page 都分配一個(gè) structure 來減少 page struct 所占用的內(nèi)存總量,不過在目前的代碼組織情況下只是一個(gè)遙遠(yuǎn)的夢想。

          因此,有很多好理由來推動(dòng)人們要從 struct page 里面刪除掉更多的內(nèi)容,并將仍然保留的信息隱藏在內(nèi)存管理子系統(tǒng)內(nèi)部。對(duì) folio 的討論得出的結(jié)果之一是,人們希望重新處理一下 struct page,但這個(gè)工作是一件很可怕的事情,或者說不耐煩的人無法完成的工作。要達(dá)成這個(gè)目標(biāo)就需要很多步驟。在 5.16 版本中把 folio 的初始 patch 合并,就是其中的一個(gè)步驟。5.17 版本中的 struct slab 出現(xiàn),則是另一個(gè)步驟。

          內(nèi)核中有許多內(nèi)存分配器(memory allocator),其中有兩個(gè)是內(nèi)存管理子系統(tǒng)的最核心功能,負(fù)責(zé)了正在運(yùn)行的系統(tǒng)中的大部分內(nèi)存分配工作。page allocator 只會(huì)以 page 為單位進(jìn)行內(nèi)存管理,正如它的名字所示,因此當(dāng)需要大量的內(nèi)存時(shí)就會(huì)使用它來分配。而 slab allocator 則可以高效處理較小對(duì)象的分配,包括那些用 kmalloc()等函數(shù)來進(jìn)行的內(nèi)存分配。slab allocator 會(huì)從 page allocator 中獲得一個(gè)或多個(gè) page 組成的一塊連續(xù)內(nèi)存,然后把這個(gè)大塊內(nèi)存分割成很小塊內(nèi)存,返回給申請內(nèi)存的用戶。實(shí)際上,內(nèi)核里支持三種 slab allocator(下面會(huì)提到),但必須在 kernel config 的時(shí)候就從中確定選擇哪一個(gè)。

          當(dāng) slab allocator 分配 page 時(shí),這些 page 在相關(guān)的 struct page 里面都會(huì)標(biāo)記成 slab page,而這些結(jié)構(gòu)中的許多字段的含義也會(huì)因此而改變。slab 相關(guān)的特定信息實(shí)際上并不是必須要在 struct page 中,而且 slab allocator 也不應(yīng)該需要訪問該結(jié)構(gòu)中的其他信息,但事實(shí)是目前這些信息都被混在了一起。

          Changes for 5.17

          人們想要糾正這種情況,第一步就是把 struct slab 分離獨(dú)立出來。目前,slab struct 實(shí)際上是 page struct 的一個(gè) overlay,因此事實(shí)上仍在使用同一片內(nèi)存空間,但新的 slab struct 就把 struct page 隱藏了起來,并限制 slab allocator 只使用存儲(chǔ)在那里的 slab 相關(guān)的特定數(shù)據(jù)。這項(xiàng)工作最初是由 Matthew Wilcox 完成的,作為了 folio 工作的一部分,后來由 Vlastimil Babka 接手并推動(dòng)其完成。

          內(nèi)核目前支持三種板塊分配器。SLAB(最早版本的 allocator),SLUB(一個(gè)較新開發(fā)的分配器,專注于提高可擴(kuò)展性,通常用在除了嵌入式應(yīng)用之外的地方),以及 SLOB(一個(gè)用于內(nèi)存非常有限的系統(tǒng)的很小的 allocator)。內(nèi)核會(huì)使用的 allocator 需要在構(gòu)建時(shí)通過 config 選項(xiàng)來指明。Babka 對(duì) patch set 所做的改變之一就是進(jìn)一步縮小了 slab struct 的定義,使其只包括當(dāng)前系統(tǒng)中選中的 allocator 所需的那些字段。目前還是使用帶有若干 #ifdef 代碼的唯一一個(gè) struct slab 定義,但建議大家去看看去掉 #ifdef 之后的最終樣子。如果選擇了 SLAB allocator,struct slab 的最終結(jié)果是這樣的:

          struct slab {
          unsigned long __page_flags;
          union {
          struct list_head slab_list;
          struct rcu_head rcu_head;
          };
          struct kmem_cache *slab_cache;
          void *freelist; /* array of free object indexes */
          void *s_mem; /* first object */
          unsigned int active;
          atomic_t __page_refcount;
          #ifdef CONFIG_MEMCG
          unsigned long memcg_data;
          #endif
          };

          (在LWN原文,跟具體 allocator 相關(guān)的特有字段以粗體顯示)。如果選擇的是 SLUB,這個(gè)結(jié)構(gòu)就變成了:

          struct slab {
          unsigned long __page_flags;
          union {
          struct list_head slab_list;
          struct rcu_head rcu_head;
          #ifdef CONFIG_SLUB_CPU_PARTIAL
          struct {
          struct slab *next;
          int slabs; /* Nr of slabs left */
          };
          #endif
          };
          struct kmem_cache *slab_cache;
          /* Double-word boundary */
          void *freelist; /* first free object */
          union {
          unsigned long counters;
          struct {
          unsigned inuse:16;
          unsigned objects:15;
          unsigned frozen:1;
          };
          };
          unsigned int __unused;
          atomic_t __page_refcount;
          #ifdef CONFIG_MEMCG
          unsigned long memcg_data;
          #endif
          };

          如果用的是 SLOB,則是:

          struct slab {
          unsigned long __page_flags;
          struct list_head slab_list;
          void *__unused_1;
          void *freelist; /* first free block */
          long units;
          unsigned int __unused_2;
          atomic_t __page_refcount;
          #ifdef CONFIG_MEMCG
          unsigned long memcg_data;
          #endif
          };

          這種組織結(jié)構(gòu)有助于確保一個(gè) slab allocator 不會(huì)去意外地使用屬于另一個(gè) slab allocator 的特有字段,從而在類型安全(type safety)方面帶來更多好處。

          新改過的這個(gè)結(jié)構(gòu)定義在了 mm/slab.h 中,它不在 include 之下,因此它不能被內(nèi)存管理子系統(tǒng)之外的代碼所用。這給 x86 bootmem allocator 以及 zsmalloc() 帶來了麻煩,因?yàn)樗鼈兌荚谑褂?page struct 中的 slab 相關(guān)的一些字段,盡管這些代碼并不是一個(gè) slab allocator。這部分代碼已經(jīng)被改為使用 struct page 中的其他字段,而且還添加了注釋,提醒說這種用法應(yīng)該在今后的某一天被清理掉。

          同時(shí),slab allocator 中的代碼也被修改為使用新的結(jié)構(gòu),在調(diào)用棧的一開始就改成使用新的這個(gè) struct。這就將 slab 的大部分代碼與 struct page 隔離開來,為今后的工作鋪平了道路,也就是未來可以完全分離這兩種 struct 了,并允許根據(jù)需要來動(dòng)態(tài)分配 slab structure。

          最終結(jié)果是為 slab allocator 在系統(tǒng)的 memory map 中有了更清晰的視圖,開始將它們與底層的內(nèi)存管理細(xì)節(jié)分開,并增加了 type safety (類型安全)。同時(shí),Linux 用戶應(yīng)該不會(huì)受到任何影響,并且如果幸運(yùn)的話,今后的 bug 數(shù)量也會(huì)有所減少。在更遠(yuǎn)的將來,可能會(huì)有這樣一個(gè)時(shí)刻:struct slab 可以被動(dòng)態(tài)分配并完全從 memory map 中分離出來。不過這種改動(dòng)還需要一段時(shí)間。同時(shí),清理內(nèi)存管理的核心類型則是朝著正確方向邁出的一步。

          全文完
          LWN 文章遵循 CC BY-SA 4.0 許可協(xié)議。

          歡迎分享、轉(zhuǎn)載及基于現(xiàn)有協(xié)議再創(chuàng)作~

          長按下面二維碼關(guān)注,關(guān)注 LWN 深度文章以及開源社區(qū)的各種新近言論~


          瀏覽 30
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  初尝人妻滑进去了莹莹视频 | 操死我网站 | 高清无码国产内射在线观看 | BB在线视频网站 | 3344在线看片 |