記憶體管理 API

使用者空間記憶體訪問

get_user

get_user (x, ptr)

從使用者空間獲取一個簡單變數。

引數

x

儲存結果的變數。

ptr

源地址,在使用者空間中。

上下文

僅限使用者上下文。如果啟用了頁故障,此函式可能會休眠。

描述

此宏將單個簡單變數從使用者空間複製到核心空間。它支援 char 和 int 等簡單型別,但不支援結構體或陣列等較大型別。

ptr 必須是指向簡單變數的指標型別,並且解引用 ptr 的結果必須可以賦值給 x,無需型別轉換。

返回

成功時返回零,錯誤時返回 -EFAULT。出錯時,變數 x 設定為零。

__get_user

__get_user (x, ptr)

從使用者空間獲取一個簡單變數,檢查較少。

引數

x

儲存結果的變數。

ptr

源地址,在使用者空間中。

上下文

僅限使用者上下文。如果啟用了頁故障,此函式可能會休眠。

描述

此宏將單個簡單變數從使用者空間複製到核心空間。它支援 char 和 int 等簡單型別,但不支援結構體或陣列等較大型別。

ptr 必須是指向簡單變數的指標型別,並且解引用 ptr 的結果必須可以賦值給 x,無需型別轉換。

呼叫此函式前,呼叫者必須使用 access_ok() 檢查指標。

返回

成功時返回零,錯誤時返回 -EFAULT。出錯時,變數 x 設定為零。

put_user

put_user (x, ptr)

將一個簡單值寫入使用者空間。

引數

x

要複製到使用者空間的值。

ptr

目標地址,在使用者空間中。

上下文

僅限使用者上下文。如果啟用了頁故障,此函式可能會休眠。

描述

此宏將單個簡單值從核心空間複製到使用者空間。它支援 char 和 int 等簡單型別,但不支援結構體或陣列等較大型別。

ptr 必須是指向簡單變數的指標型別,並且 x 必須可以賦值給解引用 ptr 的結果。

返回

成功時返回零,錯誤時返回 -EFAULT。

__put_user

__put_user (x, ptr)

將一個簡單值寫入使用者空間,檢查較少。

引數

x

要複製到使用者空間的值。

ptr

目標地址,在使用者空間中。

上下文

僅限使用者上下文。如果啟用了頁故障,此函式可能會休眠。

描述

此宏將單個簡單值從核心空間複製到使用者空間。它支援 char 和 int 等簡單型別,但不支援結構體或陣列等較大型別。

ptr 必須是指向簡單變數的指標型別,並且 x 必須可以賦值給解引用 ptr 的結果。

呼叫此函式前,呼叫者必須使用 access_ok() 檢查指標。

返回

成功時返回零,錯誤時返回 -EFAULT。

unsigned long clear_user(void __user *to, unsigned long n)

將使用者空間中的一塊記憶體清零。

引數

void __user *to

目標地址,在使用者空間中。

unsigned long n

要清零的位元組數。

描述

將使用者空間中的一塊記憶體清零。

返回

未能清零的位元組數。成功時,此值為零。

unsigned long __clear_user(void __user *to, unsigned long n)

將使用者空間中的一塊記憶體清零,檢查較少。

引數

void __user *to

目標地址,在使用者空間中。

unsigned long n

要清零的位元組數。

描述

將使用者空間中的一塊記憶體清零。呼叫此函式前,呼叫者必須使用 access_ok() 檢查指定的記憶體塊。

返回

未能清零的位元組數。成功時,此值為零。

int get_user_pages_fast(unsigned long start, int nr_pages, unsigned int gup_flags, struct page **pages)

鎖定使用者頁面到記憶體

引數

unsigned long start

起始使用者地址

int nr_pages

從起始地址開始鎖定的頁數

unsigned int gup_flags

修改鎖定行為的標誌

struct page **pages

接收鎖定頁面指標的陣列。長度應至少為 nr_pages。

描述

嘗試在不獲取 mm->mmap_lock 的情況下鎖定使用者頁面到記憶體。如果失敗,它將回退到獲取鎖並呼叫 get_user_pages()。

返回鎖定的頁數。這可能少於請求的頁數。如果 nr_pages 為 0 或負數,返回 0。如果沒有鎖定任何頁面,返回 -errno。

記憶體分配控制

頁面移動性和放置提示

這些標誌提供了關於頁面移動性的提示。具有相似移動性的頁面被放置在相同的頁塊中,以儘量減少外部碎片引起的問題。

__GFP_MOVABLE (也是一個區域修飾符)表示頁面可以在記憶體壓縮期間透過頁面遷移移動或可以被回收。

__GFP_RECLAIMABLE 用於指定 SLAB_RECLAIM_ACCOUNT 的 slab 分配,其頁面可以透過收縮器釋放。

__GFP_WRITE 表示呼叫者打算髒化頁面。在可能的情況下,這些頁面將分散在本地區域之間,以避免所有髒頁面集中在一個區域(公平區域分配策略)。

__GFP_HARDWALL 強制執行 cpuset 記憶體分配策略。

__GFP_THISNODE 強制分配從請求的節點滿足,不進行回退或放置策略強制。

__GFP_ACCOUNT 導致分配被計入 kmemcg。

__GFP_NO_OBJ_EXT 導致 slab 分配沒有物件擴充套件。

水印修飾符 -- 控制對緊急儲備的訪問

__GFP_HIGH 表示呼叫者優先順序高,並且在系統能夠向前推進之前,必須滿足請求。例如,建立 IO 上下文以清除頁面和原子上下文的請求。

__GFP_MEMALLOC 允許訪問所有記憶體。這隻應在呼叫者保證分配將很快釋放更多記憶體時使用,例如程序退出或交換。使用者要麼是 MM,要麼與 VM 密切協調(例如,透過 NFS 交換)。此標誌的使用者必須極其小心,不要完全耗盡儲備,並實施一種節流機制,根據釋放的記憶體量控制儲備的消耗。在使用此標誌之前,應始終考慮使用預分配池(例如 mempool)。

__GFP_NOMEMALLOC 用於明確禁止訪問緊急儲備。如果兩者都設定,此標誌優先於 __GFP_MEMALLOC 標誌。

回收修飾符

請注意,以下所有標誌僅適用於可休眠分配(例如 GFP_NOWAITGFP_ATOMIC 將忽略它們)。

__GFP_IO 可以啟動物理 IO。

__GFP_FS 可以呼叫底層 FS。清除此標誌可避免分配器遞迴進入可能已持有鎖的檔案系統。

__GFP_DIRECT_RECLAIM 表示呼叫者可能進入直接回收。可以清除此標誌以避免在有備用選項時出現不必要的延遲。

__GFP_KSWAPD_RECLAIM 表示當達到低水位線時,呼叫者希望喚醒 kswapd 並讓其回收頁面直到達到高水位線。當有備用選項並且回收可能擾亂系統時,呼叫者可能希望清除此標誌。典型的例子是 THP 分配,其中回退成本低廉,但回收/壓縮可能導致間接停頓。

__GFP_RECLAIM 是允許/禁止直接回收和 kswapd 回收的簡寫。

預設分配器行為取決於請求大小。我們有成本高昂的分配(order > PAGE_ALLOC_COSTLY_ORDER)的概念。非成本高昂的分配通常非常關鍵,預設情況下不會失敗(除了 OOM 受害者可能會失敗,因此呼叫者仍然需要檢查失敗),而成本高昂的請求則儘量不具有破壞性,即使不呼叫 OOM killer 也會回退。以下三個修飾符可用於覆蓋這些隱式規則中的一些。請注意,所有這些修飾符都必須與 __GFP_DIRECT_RECLAIM 標誌一起使用。

__GFP_NORETRY: VM 實現只會嘗試非常輕量的記憶體直接回收以在記憶體壓力下獲取一些記憶體(因此它可以休眠)。它將避免像 OOM killer 這樣的破壞性操作。呼叫者必須處理在重記憶體壓力下很可能發生的失敗。當可以以較小代價輕鬆處理失敗時,例如降低吞吐量,此標誌是合適的。

__GFP_RETRY_MAYFAIL: 如果有跡象表明其他地方取得了進展,VM 實現將重試以前失敗的記憶體回收過程。它可以等待其他任務嘗試釋放記憶體的高階方法,例如碎片整理(清除碎片)和頁面換出。重試次數仍然有明確的限制,但比 __GFP_NORETRY 更大。帶有此標誌的分配可能會失敗,但僅當真正沒有多少未使用的記憶體時。雖然這些分配不會直接觸發 OOM killer,但它們的失敗表明系統可能很快需要使用 OOM killer。呼叫者必須處理失敗,但可以合理地透過使更高級別的請求失敗,或以效率低得多的方式完成它來實現。如果分配確實失敗,並且呼叫者能夠釋放一些非必要記憶體,這樣做可能會使整個系統受益。

__GFP_NOFAIL: VM 實現_必須_無限期重試:呼叫者無法處理分配失敗。分配可能無限期阻塞,但絕不會返回失敗。測試失敗是毫無意義的。它_必須_是可阻塞的,並與 __GFP_DIRECT_RECLAIM 一起使用。它_絕不_應在不可休眠的上下文中使用。新使用者應仔細評估(並且此標誌應僅在沒有合理失敗策略時使用),但使用此標誌絕對優於圍繞分配器編寫無限迴圈程式碼。不支援使用 __GFP_NOFAIL 且 order > 1 從 buddy 分配頁面。請考慮使用 kvmalloc() 代替。

有用的 GFP 標誌組合

常用的一些有用的 GFP 標誌組合。建議子系統從這些組合之一開始,然後根據需要設定/清除 __GFP_FOO 標誌。

GFP_ATOMIC 使用者不能休眠,並且需要分配成功。應用較低的水位線以允許訪問“原子儲備”。當前實現不支援 NMI 和其他一些嚴格的非搶佔上下文(例如 raw_spin_lock)。GFP_NOWAIT 也是如此。

GFP_KERNEL 是核心內部分配的典型標誌。呼叫者需要 ZONE_NORMAL 或較低的區域進行直接訪問,但可以進行直接回收。

GFP_KERNEL_ACCOUNT 與 GFP_KERNEL 相同,只是分配會計入 kmemcg。

GFP_NOWAIT 用於不應因直接回收而停頓、啟動物理 IO 或使用任何檔案系統回撥的核心分配。它很可能無法分配記憶體,即使是很小的分配。

GFP_NOIO 將使用直接回收來丟棄不需要啟動任何物理 IO 的乾淨頁面或 slab 頁面。請儘量避免直接使用此標誌,而是使用 memalloc_noio_{save,restore} 標記整個不能執行任何 IO 的範圍,並附帶簡短的解釋。所有分配請求都將隱式繼承 GFP_NOIO。

GFP_NOFS 將使用直接回收,但不會使用任何檔案系統介面。請儘量避免直接使用此標誌,而是使用 memalloc_nofs_{save,restore} 標記整個不能/不應遞迴進入 FS 層的範圍,並附帶簡短的解釋。所有分配請求都將隱式繼承 GFP_NOFS。

GFP_USER 用於使用者空間分配,這些分配也需要核心或硬體直接訪問。它通常由硬體用於對映到使用者空間的緩衝區(例如圖形),硬體仍必須對其進行 DMA。這些分配會強制執行 cpuset 限制。

GFP_DMA 出於歷史原因存在,應儘可能避免使用。此標誌表示呼叫者要求使用最低區域(ZONE_DMA 或 x86-64 上的 16M)。理想情況下,這將被刪除,但這需要仔細審計,因為有些使用者確實需要它,而另一些使用者則使用此標誌來避免 ZONE_DMA 中的低記憶體儲備,並將最低區域視為一種緊急儲備。

GFP_DMA32 類似於 GFP_DMA,只是呼叫者需要一個 32 位地址。請注意,kmalloc(..., GFP_DMA32) 不會返回 DMA32 記憶體,因為 DMA32 kmalloc 快取陣列未實現。(原因:核心中沒有這樣的使用者)。

GFP_HIGHUSER 用於使用者空間分配,這些分配可能對映到使用者空間,不需要核心直接訪問,但一旦使用就不能移動。一個例子可能是將資料直接對映到使用者空間但沒有定址限制的硬體分配。

GFP_HIGHUSER_MOVABLE 用於核心不需要直接訪問但需要訪問時可以使用 kmap() 的使用者空間分配。它們預計可以透過頁面回收或頁面遷移移動。通常,LRU 上的頁面也將使用 GFP_HIGHUSER_MOVABLE 分配。

GFP_TRANSHUGEGFP_TRANSHUGE_LIGHT 用於 THP 分配。它們是複合分配,如果記憶體不可用,通常會迅速失敗,並且在失敗時不會喚醒 kswapd/kcompactd。_LIGHT 版本完全不嘗試回收/壓縮,預設用於頁故障路徑,而非 light 版本由 khugepaged 使用。

Slab 快取

SLAB_HWCACHE_ALIGN

SLAB_HWCACHE_ALIGN

將物件對齊到快取行邊界。

描述

足夠大的物件會按照快取行邊界對齊。對於小於快取行大小一半的物件,對齊方式是快取行大小的一半。通常,如果物件大小小於快取行大小的 1/2^n,則對齊方式調整為 1/2^n。

如果相應的 struct kmem_cache_args 欄位也請求了顯式對齊,則應用兩者中較大的對齊方式。

SLAB_TYPESAFE_BY_RCU

SLAB_TYPESAFE_BY_RCU

警告 閱讀此內容!

描述

這會將 SLAB 頁的釋放延遲一個寬限期,但_不_會延遲物件的釋放。這意味著,如果您呼叫 kmem_cache_free(),該記憶體位置可以隨時被重用。因此,在同一個 RCU 寬限期內,可能會在該位置看到另一個物件。

此功能僅確保支援物件的記憶體位置保持有效,使用此功能的訣竅是依賴獨立的“物件驗證”過程。類似於

begin:
 rcu_read_lock();
 obj = lockless_lookup(key);
 if (obj) {
   if (!try_get_ref(obj)) // might fail for free objects
     rcu_read_unlock();
     goto begin;

   if (obj->key != key) { // not the object we expected
     put_ref(obj);
     rcu_read_unlock();
     goto begin;
   }
 }
rcu_read_unlock();

如果我們從沒有常規鎖定的情況下獲得的地址,需要間接訪問核心結構,這會很有用。我們可以鎖定該結構以使其穩定,並檢查它是否仍在該給定地址,前提是我們能夠確保該記憶體沒有被重用於其他型別的物件(這可能會破壞我們子系統的鎖)。

在讀取地址前呼叫 rcu_read_lock,然後在預期在該地址的結構內獲取自旋鎖後呼叫 rcu_read_unlock。

請注意,物件身份檢查必須在獲取引用後進行,因此使用者必須確保正確的載入順序。同樣,在使用 SLAB_TYPESAFE_BY_RCU 分配的物件進行初始化時,新分配的物件必須在其引用計數初始化之前完全初始化,並且需要適當的儲存順序。refcount_{add|inc}_not_zero_acquire() 和 refcount_set_release() 的設計考慮了使用 SLAB_TYPESAFE_BY_RCU 分配的引用計數物件所需的正確屏障。

請注意,在不首先如上所述獲取引用的情況下,無法獲取使用 SLAB_TYPESAFE_BY_RCU 分配的結構中的鎖。原因在於 SLAB_TYPESAFE_BY_RCU 頁面在交給 slab 之前不會清零,這意味著任何鎖都必須在每次 kmem_struct_alloc() 之後初始化。或者,讓傳遞給 kmem_cache_create() 的 ctor 在頁面分配時初始化鎖,就像在 __i915_request_ctor()、sighand_ctor() 和 anon_vma_ctor() 中所做的那樣。這樣的 ctor 允許讀取者在 rcu_read_lock() 保護下安全地獲取那些 ctor 初始化的鎖。

請注意,SLAB_TYPESAFE_BY_RCU 最初名為 SLAB_DESTROY_BY_RCU。

SLAB_ACCOUNT

SLAB_ACCOUNT

將分配計入 memcg。

描述

此快取的所有物件分配都將進行 memcg 記賬,無論 __GFP_ACCOUNT 是否傳遞給單個分配。

SLAB_RECLAIM_ACCOUNT

SLAB_RECLAIM_ACCOUNT

物件可回收。

描述

將此標誌用於具有關聯收縮器的快取。因此,slab 頁面將使用 __GFP_RECLAIMABLE 分配,這會影響按移動性分組頁面,並計入 /proc/meminfo 中的 SReclaimable 計數器。

struct kmem_cache_args

kmem_cache_create() 的不常用引數

定義:

struct kmem_cache_args {
    unsigned int align;
    unsigned int useroffset;
    unsigned int usersize;
    unsigned int freeptr_offset;
    bool use_freeptr_offset;
    void (*ctor)(void *);
};

成員

align

物件所需的對齊方式。

0 表示未請求特定對齊。

useroffset

使用者複製區域偏移。

0 是一個有效偏移,當 usersize0 時。

usersize

使用者複製區域大小。

0 表示未指定使用者複製區域。

freeptr_offset

SLAB_TYPESAFE_BY_RCU 快取中自由指標的自定義偏移量

預設情況下,SLAB_TYPESAFE_BY_RCU 快取會將自由指標放在物件之外。這可能會導致物件大小增加。需要避免這種情況的快取建立者可以在其結構中指定一個自定義的自由指標偏移量,自由指標將放在那裡。

請注意,將自由指標放在物件內部要求呼叫者確保不會使阻止物件回收所需的欄位失效(詳見 SLAB_TYPESAFE_BY_RCU)。

使用 0 作為 freeptr_offset 的值是有效的。如果指定了 freeptr_offset,則 use_freeptr_offset 必須設定為 true

請注意,由於 ctor 需要外部自由指標,目前不支援自定義自由指標的 ctor

use_freeptr_offset

是否使用 freeptr_offset

ctor

物件的建構函式。

在每個新分配的 slab 頁中的物件上都會呼叫建構函式。快取使用者有責任在呼叫建構函式後以相同的狀態釋放物件,或者適當地處理新構造物件和重新分配物件之間的任何差異。

NULL 表示沒有建構函式。

描述

結構的任何未初始化欄位都被解釋為未使用。例外是 freeptr_offset,其中 0 是一個有效值,因此 use_freeptr_offset 也必須設定為 true 才能將該欄位解釋為已使用。對於 useroffset0 也是有效的,但僅限於 usersize0 的情況。

當將 NULL args 傳遞給 kmem_cache_create() 時,它等同於所有欄位都未使用。

struct kmem_cache *kmem_cache_create_usercopy(const char *name, unsigned int size, unsigned int align, slab_flags_t flags, unsigned int useroffset, unsigned int usersize, void (*ctor)(void*))

建立一個帶有適合複製到使用者空間區域的 kmem 快取。

引數

const char *name

用於在 /proc/slabinfo 中標識此快取的字串。

unsigned int size

在此快取中建立的物件大小。

unsigned int align

物件所需的對齊方式。

slab_flags_t flags

SLAB 標誌

unsigned int useroffset

使用者複製區域偏移

unsigned int usersize

使用者複製區域大小

void (*ctor)(void *)

物件的建構函式,或 NULL

描述

這是一個遺留封裝器,新程式碼應使用 KMEM_CACHE_USERCOPY()(如果白名單單個欄位就足夠)或 kmem_cache_create() 並透過 args 引數傳遞必要引數(參見 struct kmem_cache_args

返回

成功時返回指向快取的指標,失敗時返回 NULL。

kmem_cache_create

kmem_cache_create (__name, __object_size, __args, ...)

建立一個 kmem 快取。

引數

__name

用於在 /proc/slabinfo 中標識此快取的字串。

__object_size

在此快取中建立的物件大小。

__args

可選引數,參見 struct kmem_cache_args。傳遞 NULL 意味著所有引數將使用預設值。

...

可變引數

描述

此函式目前作為宏實現,使用 _Generic() 呼叫新版本函式或遺留版本函式。

新版本有 4 個引數:kmem_cache_create(name, object_size, args, flags)

參見實現此功能的 __kmem_cache_create_args()

遺留版本有 5 個引數:kmem_cache_create(name, object_size, align, flags, ctor)

align 和 ctor 引數對映到 struct kmem_cache_args 的相應欄位。

上下文

不能在中斷中呼叫,但可以被中斷。

返回

成功時返回指向快取的指標,失敗時返回 NULL。

size_t ksize(const void *objp)

報告關聯物件的實際分配大小

引數

const void *objp

從先前 kmalloc() 族分配返回的指標。

描述

此函式不應用於寫入超出最初請求的分配大小的區域。應使用 krealloc() 或在分配前使用 kmalloc_size_roundup() 將分配大小向上取整。如果此函式用於訪問超出最初請求的分配大小的區域,UBSAN_BOUNDS 和/或 FORTIFY_SOURCE 可能會觸發,因為它們只知道最初分配的大小(透過 __alloc_size 屬性)。

void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)

分配一個物件

引數

struct kmem_cache *cachep

從中分配的快取。

gfp_t flags

參見 kmalloc()

描述

從此快取中分配一個物件。有關將 __GFP_ZERO 新增到 flags 的快捷方式,請參見 kmem_cache_zalloc()。

返回

指向新物件的指標,如果出錯則為 NULL

bool kmem_cache_charge(void *objp, gfp_t gfpflags)

memcg 記賬已分配的 slab 記憶體

引數

void *objp

要進行 memcg 記賬的 slab 物件地址

gfp_t gfpflags

描述分配上下文

描述

kmem_cache_charge 允許將 slab 物件記賬到當前 memcg,主要用於在分配時可能無法確定目標 memcg 的情況(即軟中斷上下文)

objp 應該是 slab 分配器函式(如 kmalloc(帶 __GFP_ACCOUNT 標誌)或 kmem_cache_alloc)返回的指標。memcg 記賬行為可以透過 gfpflags 引數控制,這會影響必要內部元資料的分配方式。包含 __GFP_NOFAIL 表示請求超額記賬而不是失敗,但不適用於內部元資料分配。

在幾種情況下,即使未進行記賬,它也會返回 true:更具體地說

  1. 對於 !CONFIG_MEMCG 或 cgroup_disable=memory 系統。

  2. 已記賬的 slab 物件。

  3. 對於來自 KMALLOC_NORMAL 快取的 slab 物件——由不帶 __GFP_ACCOUNT 的 kmalloc() 分配

  4. 分配內部元資料失敗

返回

如果記賬成功則為 true,否則為 false。

void *kmalloc(size_t size, gfp_t flags)

分配核心記憶體

引數

size_t size

所需的記憶體位元組數。

gfp_t flags

描述分配上下文

描述

kmalloc 是在核心中為小於頁面大小的物件分配記憶體的常用方法。

分配的記憶體物件地址至少對齊到 ARCH_KMALLOC_MINALIGN 位元組。對於 size 為 2 的冪的位元組數,對齊也保證至少達到該大小。對於其他大小,對齊保證至少達到 size 的最大 2 的冪因子。

flags 引數可以是 include/linux/gfp_types.h 中定義並於 Documentation/core-api/mm-api.rst 中描述的 GFP 標誌之一

flags 的推薦用法在 Documentation/core-api/memory-allocation.rst 中描述

以下是關於最有用的 GFP 標誌的簡要概述

GFP_KERNEL

分配普通核心記憶體。可能會休眠。

GFP_NOWAIT

分配不會休眠。

GFP_ATOMIC

分配不會休眠。可能使用緊急池。

還可以透過“或”上以下一個或多個額外 flags 來設定不同的標誌

__GFP_ZERO

返回前將分配的記憶體清零。另請參見 kzalloc()

__GFP_HIGH

此分配具有高優先順序,可能使用緊急池。

__GFP_NOFAIL

表示此分配絕不允許失敗(使用前請三思)。

__GFP_NORETRY

如果記憶體無法立即獲得,則立即放棄。

__GFP_NOWARN

如果分配失敗,不要發出任何警告。

__GFP_RETRY_MAYFAIL

非常努力地嘗試使分配成功,但最終仍可能失敗。

void *kmalloc_array(size_t n, size_t size, gfp_t flags)

為陣列分配記憶體。

引數

size_t n

元素數量。

size_t size

元素大小。

gfp_t flags

要分配的記憶體型別(參見 kmalloc)。

void *krealloc_array(void *p, size_t new_n, size_t new_size, gfp_t flags)

重新分配陣列記憶體。

引數

void *p

指向要重新分配的記憶體塊的指標

size_t new_n

要分配的新元素數量

size_t new_size

陣列單個成員的新大小

gfp_t flags

要分配的記憶體型別(參見 kmalloc)

描述

如果請求 __GFP_ZERO 邏輯,呼叫者必須確保從初始記憶體分配開始,每次後續對同一記憶體分配的此 API 呼叫都必須標記為 __GFP_ZERO。否則,此 API 可能無法完全遵守 __GFP_ZERO。

有關更多詳細資訊,請參見 krealloc_noprof()。

在任何情況下,指向物件的記憶體內容都會保留到新舊大小中的較小者。

kcalloc

kcalloc (n, size, flags)

為陣列分配記憶體。記憶體設定為零。

引數

n

元素數量。

size

元素大小。

flags

要分配的記憶體型別(參見 kmalloc)。

void *kzalloc(size_t size, gfp_t flags)

分配記憶體。記憶體設定為零。

引數

size_t size

所需的記憶體位元組數。

gfp_t flags

要分配的記憶體型別(參見 kmalloc)。

size_t kmalloc_size_roundup(size_t size)

報告給定大小的分配桶大小

引數

size_t size

要向上取整的位元組數。

描述

此函式返回 kmalloc() 分配 size 位元組後可用的位元組數。例如,126 位元組的請求將被向上取整到下一個大小的 kmalloc 桶,即 128 位元組。(這嚴格適用於通用 kmalloc()-based 分配,不適用於預設大小的 kmem_cache_alloc()-based 分配。)

使用此函式可以提前 kmalloc() 完整的桶大小,而不是在分配後使用 ksize() 查詢大小。

void kmem_cache_free(struct kmem_cache *s, void *x)

釋放一個物件

引數

struct kmem_cache *s

分配來自的快取。

void *x

先前分配的物件。

描述

釋放先前從此快取分配的物件。

void kfree(const void *object)

釋放先前分配的記憶體

引數

const void *object

kmalloc()kmem_cache_alloc() 返回的指標

描述

如果 object 為 NULL,則不執行任何操作。

void *kvfree(const void *addr)

釋放記憶體。

引數

const void *addr

指向已分配記憶體的指標。

描述

kvfree 釋放由 vmalloc()、kmalloc() 或 kvmalloc() 分配的記憶體。如果您確定知道使用哪個函式,使用 kfree()vfree() 會稍微更高效。

上下文

要麼是可搶佔的任務上下文,要麼是非 NMI 中斷。

void kvfree_sensitive(const void *addr, size_t len)

釋放包含敏感資訊的資料物件。

引數

const void *addr

要釋放的資料物件地址。

size_t len

資料物件的長度。

描述

使用特殊的 memzero_explicit() 函式清除包含敏感資料的 kvmalloc'ed 物件的內容,以確保編譯器不會最佳化掉資料清除操作。

struct kmem_cache *__kmem_cache_create_args(const char *name, unsigned int object_size, struct kmem_cache_args *args, slab_flags_t flags)

建立一個 kmem 快取。

引數

const char *name

用於在 /proc/slabinfo 中標識此快取的字串。

unsigned int object_size

在此快取中建立的物件大小。

struct kmem_cache_args *args

快取建立的附加引數(參見 struct kmem_cache_args)。

slab_flags_t flags

參見各個標誌的描述。常用標誌列於以下描述中。

描述

不要直接呼叫,使用引數相同的 kmem_cache_create() 封裝器。

常用的 flags

SLAB_ACCOUNT - 將分配計入 memcg。

SLAB_HWCACHE_ALIGN - 將物件對齊到快取行邊界。

SLAB_RECLAIM_ACCOUNT - 物件是可回收的。

SLAB_TYPESAFE_BY_RCU - Slab 頁(而非單個物件)的釋放延遲一個寬限期 - 使用前請閱讀完整描述。

上下文

不能在中斷中呼叫,但可以被中斷。

返回

成功時返回指向快取的指標,失敗時返回 NULL。

kmem_buckets *kmem_buckets_create(const char *name, slab_flags_t flags, unsigned int useroffset, unsigned int usersize, void (*ctor)(void*))

建立一組透過 kmem_buckets_alloc() 處理動態大小分配的快取

引數

const char *name

一個字首字串,用於在 /proc/slabinfo 中標識此快取。單個快取將以其大小作為字尾。

slab_flags_t flags

SLAB 標誌(詳見 kmem_cache_create())。

unsigned int useroffset

分配中可以複製到/從使用者空間的起始偏移量。

unsigned int usersize

useroffset 開始,可以複製到/從使用者空間的位元組數。

void (*ctor)(void *)

物件的建構函式,在新分配時執行。

描述

不能在中斷中呼叫,但可以被中斷。

返回

成功時返回指向快取的指標,失敗時返回 NULL。當 CONFIG_SLAB_BUCKETS 未啟用時,返回 ZERO_SIZE_PTR,並且後續對 kmem_buckets_alloc() 的呼叫將回退到 kmalloc()。(即,呼叫者只需在失敗時檢查 NULL。)

int kmem_cache_shrink(struct kmem_cache *cachep)

收縮一個快取。

引數

struct kmem_cache *cachep

要收縮的快取。

描述

為快取釋放盡可能多的 slab。為了幫助除錯,退出狀態為零表示所有 slab 都已釋放。

返回

如果所有 slab 都已釋放,則為 0,否則為非零

bool kmem_dump_obj(void *object)

列印可用的 slab 來源資訊

引數

void *object

要查詢來源資訊的 slab 物件。

描述

此函式使用 pr_cont(),因此呼叫者應已打印出適當的序言。來源資訊取決於物件型別和啟用的除錯程度。對於 slab-cache 物件,會列印它是 slab 物件的事實,如果可用,還會列印 slab 名稱、返回地址以及該物件的分配和上次釋放路徑的堆疊跟蹤。

返回

如果指標指向從 kmalloc()kmem_cache_alloc() 未釋放的物件,則為 true;如果指標指向已釋放的物件,則為 truefalse;否則為 false

void kfree_sensitive(const void *p)

在釋放記憶體前清除記憶體中的敏感資訊

引數

const void *p

要釋放記憶體的物件

描述

指標 p 指向的物件的記憶體將在釋放前清零。如果 pNULLkfree_sensitive() 不執行任何操作。

注意

此函式會清零整個已分配緩衝區,其大小可能遠大於傳遞給 kmalloc() 的請求緩衝區大小。因此,在效能敏感的程式碼中使用此函式時請務必小心。

void kvfree_rcu_barrier(void)

等待所有進行中的 kvfree_rcu() 完成。

引數

void

無引數

描述

請注意,kvfree_rcu() 呼叫的單個引數有一個慢速路徑,它會觸發 synchronize_rcu(),然後釋放指標。這在函式返回之前完成。因此,對於任何導致 kfree() 到將在模組退出時銷燬的快取的單引數呼叫,開發人員有責任確保所有此類呼叫在呼叫 kmem_cache_destroy() 之前已返回。

void kfree_const(const void *x)

有條件地釋放記憶體

引數

const void *x

指向記憶體的指標

描述

僅當 x 不在 .rodata 段時,函式才呼叫 kfree。

虛擬連續對映

void vm_unmap_aliases(void)

解除 vmap 層中未決的惰性別名對映

引數

void

無引數

描述

vmap/vmalloc 層會惰性重新整理核心虛擬對映,主要是為了分攤 TLB 重新整理開銷。這意味著您現在擁有的任何頁面,在以前的生命週期中,可能已經被 vmap 層對映到核心虛擬地址空間,因此可能有一些 CPU 仍然引用該頁面(除了常規的 1:1 核心對映)。

vm_unmap_aliases 重新整理所有此類惰性對映。它返回後,我們可以確定我們控制的任何頁面都不會有來自 vmap 層的任何別名。

void vm_unmap_ram(const void *mem, unsigned int count)

解除由 vm_map_ram 設定的線性核心地址空間對映

引數

const void *mem

vm_map_ram 返回的指標

unsigned int count

傳遞給 vm_map_ram 呼叫的計數(不能解除部分對映)

void *vm_map_ram(struct page **pages, unsigned int count, int node)

將頁面線性對映到核心虛擬地址(vmalloc 空間)

引數

struct page **pages

指向要對映頁面的指標陣列

unsigned int count

要對映的頁數

int node

優先在此節點上分配資料結構

描述

如果您使用此函式對映少於 VMAP_MAX_ALLOC 頁,它可能比 vmap 更快,所以它很好。但是,如果您將長生命週期和短生命週期物件與 vm_map_ram() 混合使用,它可能會因碎片化而消耗大量地址空間(尤其是在 32 位機器上)。最終您可能會看到失敗。請為短生命週期物件使用此函式。

返回

對映區域的地址,如果失敗則為 NULL

void vfree(const void *addr)

釋放 vmalloc() 分配的記憶體

引數

const void *addr

記憶體基地址

描述

釋放從 vmalloc() 系列 API 獲取的、從 addr 開始的虛擬連續記憶體區域。這通常也會釋放虛擬分配底層的物理記憶體,但該記憶體是引用計數的,因此在最後一個使用者離開之前不會被釋放。

如果 addr 為 NULL,則不執行任何操作。

上下文

如果呼叫並非來自中斷上下文,則可能會休眠。不能在 NMI 上下文呼叫(嚴格來說,如果我們有 CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG,它可能可以,但使 vfree() 的呼叫約定依賴於架構是一個非常糟糕的主意)。

void vunmap(const void *addr)

釋放由 vmap() 獲取的虛擬對映

引數

const void *addr

記憶體基地址

描述

釋放從頁面陣列建立的、由 vmap() 傳入的、從 addr 開始的虛擬連續記憶體區域。

不能在中斷上下文呼叫。

void *vmap(struct page **pages, unsigned int count, unsigned long flags, pgprot_t prot)

將頁面陣列對映到虛擬連續空間

引數

struct page **pages

頁面指標陣列

unsigned int count

要對映的頁數

unsigned long flags

vm_area->flags

pgprot_t prot

對映的頁面保護

描述

pages 中的 count 個頁面對映到連續的核心虛擬空間。如果 flags 包含 VM_MAP_PUT_PAGES,則頁面陣列本身(必須是 kmalloc 或 vmalloc 記憶體)的所有權以及其中每個頁面的一個引用從呼叫者轉移到 vmap(),並在對返回值呼叫 vfree() 時被釋放/刪除。

返回

區域的地址,如果失敗則為 NULL

void *vmap_pfn(unsigned long *pfns, unsigned int count, pgprot_t prot)

將 PFN 陣列對映到虛擬連續空間

引數

unsigned long *pfns

PFN 陣列

unsigned int count

要對映的頁數

pgprot_t prot

對映的頁面保護

描述

pfns 中的 count 個 PFN 對映到連續的核心虛擬空間,並返回對映的起始地址。

int remap_vmalloc_range(struct vm_area_struct *vma, void *addr, unsigned long pgoff)

將vmalloc頁對映到使用者空間

引數

struct vm_area_struct *vma

要覆蓋的vma(對映vma的整個範圍)

void *addr

vmalloc記憶體

unsigned long pgoff

在對映第一個頁之前,`addr` 中的頁數偏移

返回

成功返回0,失敗返回-Exxx

描述

此函式檢查 `addr` 是否是一個有效的 vmalloc 區域,並且它是否足夠大以覆蓋 vma。如果條件不滿足,將返回失敗。

類似於 remap_pfn_range()(參見 mm/memory.c)

檔案對映和頁快取

檔案對映

int filemap_fdatawrite_wbc(struct address_space *mapping, struct writeback_control *wbc)

開始回寫指定範圍內對映的髒頁

引數

struct address_space *mapping

要回寫的 address space 結構

struct writeback_control *wbc

控制回寫的 writeback_control

描述

使用提供的 `wbc` 呼叫 `writepages` 對 `mapping` 進行回寫。

返回

成功返回 0,否則返回負錯誤碼。

int filemap_fdatawrite_range_kick(struct address_space *mapping, loff_t start, loff_t end)

開始範圍回寫

引數

struct address_space *mapping

目標地址空間

loff_t start

開始回寫的索引

loff_t end

回寫的最後一個(包含)索引

描述

這是一個非完整性回寫輔助函式,用於開始回寫指定範圍內的 folio。

返回

成功返回 0,否則返回負錯誤碼。

int filemap_flush(struct address_space *mapping)

主要是一個非阻塞重新整理

引數

struct address_space *mapping

目標地址空間

描述

這主要是一個非阻塞重新整理。不適用於資料完整性目的——I/O 可能不會針對所有髒頁啟動。

返回

成功返回 0,否則返回負錯誤碼。

bool filemap_range_has_page(struct address_space *mapping, loff_t start_byte, loff_t end_byte)

檢查指定範圍內是否存在頁。

引數

struct address_space *mapping

要檢查的地址空間

loff_t start_byte

範圍起始的位元組偏移量

loff_t end_byte

範圍結束的位元組偏移量(包含)

描述

在提供的範圍內查詢至少一個頁,通常用於檢查在此範圍內的直接寫入是否會觸發回寫。

返回

如果指定範圍內至少存在一個頁,返回 true,否則返回 false

int filemap_fdatawait_range(struct address_space *mapping, loff_t start_byte, loff_t end_byte)

等待回寫完成

引數

struct address_space *mapping

要等待的地址空間結構

loff_t start_byte

範圍起始的位元組偏移量

loff_t end_byte

範圍結束的位元組偏移量(包含)

描述

遍歷給定地址空間中指定範圍內正在回寫的頁列表,並等待所有這些頁完成。檢查地址空間的錯誤狀態並返回它。

由於此函式會清除地址空間的錯誤狀態,呼叫者有責任檢查返回值並處理和/或報告錯誤。

返回

地址空間的錯誤狀態。

int filemap_fdatawait_range_keep_errors(struct address_space *mapping, loff_t start_byte, loff_t end_byte)

等待回寫完成

引數

struct address_space *mapping

要等待的地址空間結構

loff_t start_byte

範圍起始的位元組偏移量

loff_t end_byte

範圍結束的位元組偏移量(包含)

描述

遍歷給定地址空間中指定範圍內正在回寫的頁列表,並等待所有這些頁完成。與 filemap_fdatawait_range() 不同,此函式不會清除地址空間的錯誤狀態。

如果呼叫者不自行處理錯誤,請使用此函式。預期呼叫場景是系統範圍/檔案系統範圍的資料重新整理器:例如 `sync(2)`、`fsfreeze(8)`。

int file_fdatawait_range(struct file *file, loff_t start_byte, loff_t end_byte)

等待回寫完成

引數

struct file *file

指向要等待的地址空間結構的檔案

loff_t start_byte

範圍起始的位元組偏移量

loff_t end_byte

範圍結束的位元組偏移量(包含)

描述

遍歷 `file` 所指向的地址空間中指定範圍內正在回寫的頁列表,並等待所有這些頁完成。檢查地址空間的錯誤狀態與 `file->f_wb_err` 游標,並返回它。

由於此函式會使檔案的錯誤狀態向前推進,呼叫者有責任檢查返回值並處理和/或報告錯誤。

返回

地址空間的錯誤狀態與 `file->f_wb_err` 游標。

int filemap_fdatawait_keep_errors(struct address_space *mapping)

等待回寫而不清除錯誤

引數

struct address_space *mapping

要等待的地址空間結構

描述

遍歷給定地址空間中正在回寫的頁列表,並等待所有這些頁完成。與 `filemap_fdatawait()` 不同,此函式不會清除地址空間的錯誤狀態。

如果呼叫者不自行處理錯誤,請使用此函式。預期呼叫場景是系統範圍/檔案系統範圍的資料重新整理器:例如 `sync(2)`、`fsfreeze(8)`。

返回

地址空間的錯誤狀態。

int filemap_write_and_wait_range(struct address_space *mapping, loff_t lstart, loff_t lend)

回寫並等待檔案範圍

引數

struct address_space *mapping

頁面的 address_space

loff_t lstart

範圍起始的位元組偏移量

loff_t lend

範圍結束的位元組偏移量(包含)

描述

回寫並等待檔案偏移量 `lstart` 到 `lend`(包含)。

請注意,**lend** 是包含的(描述要寫入的最後一個位元組),因此此函式可以用於寫入到檔案末尾(end = -1)。

返回

地址空間的錯誤狀態。

int file_check_and_advance_wb_err(struct file *file)

報告之前發生的回寫錯誤(如果有),並將 `wb_err` 前進到當前錯誤

引數

struct file *file

正在報告錯誤的 struct file

描述

當用戶空間呼叫 `fsync`(或 `nfsd` 等效操作)時,我們希望報告自上次 `fsync` 以來(或自檔案開啟以來,如果沒有發生過)發生的任何回寫錯誤。

從 `mapping` 中獲取 `wb_err`。如果它與我們在檔案中擁有的匹配,則快速返回 `0`。檔案已全部同步。

如果不匹配,則獲取對映值,設定其“seen”標誌並嘗試將其交換到位。如果成功,或另一個任務以新值搶先我們,則更新 `f_wb_err` 並返回錯誤部分。此時的錯誤必須透過適當的渠道(例如 `fsync` 或 NFS `COMMIT` 操作等)報告。

雖然我們使用原子操作處理 `mapping->wb_err`,但 `f_wb_err` 值受 `f_lock` 保護,因為我們必須確保它反映為此檔案描述符交換的最新值。

返回

成功返回 0,否則返回負錯誤碼。

int file_write_and_wait_range(struct file *file, loff_t lstart, loff_t lend)

回寫並等待檔案範圍

引數

struct file *file

指向包含頁面的 address_space 的檔案

loff_t lstart

範圍起始的位元組偏移量

loff_t lend

範圍結束的位元組偏移量(包含)

描述

回寫並等待檔案偏移量 `lstart` 到 `lend`(包含)。

請注意,**lend** 是包含的(描述要寫入的最後一個位元組),因此此函式可以用於寫入到檔案末尾(end = -1)。

在回寫並等待資料後,我們檢查並將 `f_wb_err` 游標推進到最新值,並返回在那裡檢測到的任何錯誤。

返回

成功返回 0,否則返回負錯誤碼。

void replace_page_cache_folio(struct folio *old, struct folio *new)

用新的 folio 替換頁快取中的 folio

引數

struct folio *old

要被替換的 folio

struct folio *new

替換用的 folio

描述

此函式用一個新的 folio 替換頁快取中的現有 folio。成功時,它會為新 folio 獲取頁快取引用,併為舊 folio 釋放引用。舊 folio 和新 folio 都必須被鎖定。此函式不會將新 folio 新增到 LRU,呼叫者必須自行處理。

移除和新增是原子操作。此函式不會失敗。

void folio_unlock(struct folio *folio)

解鎖一個已鎖定的 folio。

引數

struct folio *folio

該 folio。

描述

解鎖 folio 並喚醒任何在頁鎖上睡眠的執行緒。

上下文

可以在中斷或程序上下文中呼叫。不能在 NMI 上下文中呼叫。

void folio_end_read(struct folio *folio, bool success)

結束對 folio 的讀取。

引數

struct folio *folio

該 folio。

bool success

如果所有讀取都成功完成,則為真。

描述

當針對某個 folio 的所有讀取都完成後,檔案系統應呼叫此函式以告知頁快取不再有未完成的讀取。這將解鎖 folio 並喚醒任何在鎖上睡眠的執行緒。如果所有讀取都成功,folio 也將被標記為最新。

上下文

可以在中斷或程序上下文中呼叫。不能在 NMI 上下文中呼叫。

void folio_end_private_2(struct folio *folio)

清除 PG_private_2 並喚醒任何等待者。

引數

struct folio *folio

該 folio。

描述

清除 folio 上的 `PG_private_2` 位,並喚醒任何等待它的睡眠者。為 `PG_private_2` 設定而持有的 folio 引用將被釋放。

例如,當網路檔案系統 (netfs) 的 folio 正在寫入本地磁碟快取時,此功能可用於序列化對同一 folio 的快取寫入。

void folio_wait_private_2(struct folio *folio)

等待 folio 上的 PG_private_2 被清除。

引數

struct folio *folio

要等待的 folio。

描述

等待 folio 上的 PG_private_2 被清除。

int folio_wait_private_2_killable(struct folio *folio)

等待 folio 上的 PG_private_2 被清除。

引數

struct folio *folio

要等待的 folio。

描述

等待 folio 上的 `PG_private_2` 被清除,或者直到呼叫任務收到致命訊號。

返回

  • 成功返回0。

  • 如果遇到致命訊號,返回 -EINTR。

void folio_end_writeback(struct folio *folio)

結束對 folio 的回寫。

引數

struct folio *folio

該 folio。

描述

該 folio 必須實際處於回寫狀態。

上下文

可以在程序或中斷上下文中呼叫。

void __folio_lock(struct folio *folio)

在 folio 上獲取鎖,假設我們需要睡眠才能獲取它。

引數

struct folio *folio

要鎖定的 folio

pgoff_t page_cache_next_miss(struct address_space *mapping, pgoff_t index, unsigned long max_scan)

在頁快取中查詢下一個空隙。

引數

struct address_space *mapping

對映。

pgoff_t index

索引。

unsigned long max_scan

要搜尋的最大範圍。

描述

在範圍 `[index, min(index + max_scan - 1, ULONG_MAX)]` 中搜索索引最低的空隙。

此函式可以在 `rcu_read_lock` 下呼叫。但是,這不會原子地搜尋快取的單個時間點快照。例如,如果在索引 `5` 處建立了一個空隙,然後又在索引 `10` 處建立了一個空隙,那麼如果在 `rcu_read_lock` 下呼叫覆蓋這兩個索引的 `page_cache_next_miss`,它可能會返回 `10`。

返回

如果找到空隙,返回該空隙的索引;否則返回超出指定範圍的索引(在這種情況下,`return - index >= max_scan` 將為真)。在極少數的索引環繞情況下,將返回 `0`。

pgoff_t page_cache_prev_miss(struct address_space *mapping, pgoff_t index, unsigned long max_scan)

在頁快取中查詢前一個空隙。

引數

struct address_space *mapping

對映。

pgoff_t index

索引。

unsigned long max_scan

要搜尋的最大範圍。

描述

在範圍 `[max(index - max_scan + 1, 0), index]` 中搜索索引最高的空隙。

此函式可以在 `rcu_read_lock` 下呼叫。但是,這不會原子地搜尋快取的單個時間點快照。例如,如果在索引 `10` 處建立了一個空隙,然後又在索引 `5` 處建立了一個空隙,那麼如果在 `rcu_read_lock` 下呼叫覆蓋這兩個索引的 page_cache_prev_miss(),它可能會返回 `5`。

返回

如果找到空隙,返回該空隙的索引;否則返回超出指定範圍的索引(在這種情況下,`index - return >= max_scan` 將為真)。在極少數的環繞情況下,將返回 `ULONG_MAX`。

struct folio *__filemap_get_folio(struct address_space *mapping, pgoff_t index, fgf_t fgp_flags, gfp_t gfp)

查詢並獲取對 folio 的引用。

引數

struct address_space *mapping

要搜尋的 address_space。

pgoff_t index

頁索引。

fgf_t fgp_flags

FGP 標誌修改 folio 的返回方式。

gfp_t gfp

如果指定了 FGP_CREAT,則使用的記憶體分配標誌。

描述

查詢 **mapping** & **index** 處的頁快取條目。

如果指定了 FGP_LOCKFGP_CREAT,則即使為 FGP_CREAT 指定的 GFP 標誌是原子的,函式也可能睡眠。

如果此函式返回一個 folio,它將以增加的引用計數返回。

返回

找到的 folio,否則返回 ERR_PTR()

unsigned filemap_get_folios(struct address_space *mapping, pgoff_t *start, pgoff_t end, struct folio_batch *fbatch)

獲取一批 folio

引數

struct address_space *mapping

要搜尋的 address_space

pgoff_t *start

起始頁索引

pgoff_t end

最終頁索引(包含)

struct folio_batch *fbatch

要填充的批次。

描述

在 `mapping` 中搜索並返回從索引 **start** 開始到索引 **end**(包含)的一批 folio。這些 folio 將以增加的引用計數返回到 **fbatch** 中。

返回

找到的 folio 數量。我們還會更新 **start** 以索引下一次遍歷的 folio。

unsigned filemap_get_folios_contig(struct address_space *mapping, pgoff_t *start, pgoff_t end, struct folio_batch *fbatch)

獲取一批連續的 folio

引數

struct address_space *mapping

要搜尋的 address_space

pgoff_t *start

起始頁索引

pgoff_t end

最終頁索引(包含)

struct folio_batch *fbatch

要填充的批次

描述

filemap_get_folios_contig() 的工作方式與 filemap_get_folios() 完全相同,不同之處在於返回的 folio 保證是連續的。如果批次被填滿,這可能不會返回所有連續的 folio。

返回

找到的 folio 數量。同時更新 **start**,使其定位為遍歷下一個 folio。

unsigned filemap_get_folios_tag(struct address_space *mapping, pgoff_t *start, pgoff_t end, xa_mark_t tag, struct folio_batch *fbatch)

獲取一批與 **tag** 匹配的 folio

引數

struct address_space *mapping

要搜尋的 address_space

pgoff_t *start

起始頁索引

pgoff_t end

最終頁索引(包含)

xa_mark_t tag

標籤索引

struct folio_batch *fbatch

要填充的批次

描述

第一個 folio 可能在 **start** 之前開始;如果它確實如此,它將包含 **start**。最後一個 folio 可能超出 **end**;如果它確實如此,它將包含 **end**。folio 具有升序索引。如果頁快取中沒有 folio 的索引,則 folio 之間可能存在空隙。如果在此函式執行時 folio 被新增到或從頁快取中移除,則此呼叫可能找到也可能找不到它們。僅返回帶有 **tag** 標籤的 folio。

返回

找到的 folio 數量。同時更新 **start** 以索引下一次遍歷的 folio。

ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *iter, ssize_t already_read)

從頁快取中讀取資料。

引數

struct kiocb *iocb

要讀取的 iocb。

struct iov_iter *iter

資料目的地。

ssize_t already_read

呼叫者已讀取的位元組數。

描述

從頁快取複製資料。如果資料當前不存在,則使用預讀和 `read_folio` 地址空間操作來獲取它。

返回

複製的總位元組數,包括呼叫者已讀取的位元組。如果複製任何位元組之前發生錯誤,則返回負錯誤碼。

ssize_t generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)

通用檔案系統讀取例程

引數

struct kiocb *iocb

核心 I/O 控制塊

struct iov_iter *iter

讀取資料目的地

描述

這是所有可以直接使用頁快取的檔案系統的“read_iter()”例程。

`iocb->ki_flags` 中的 `IOCB_NOWAIT` 標誌表示當無法在不等待 I/O 請求完成的情況下讀取資料時,應返回 `-EAGAIN`;它不會阻止預讀。

`iocb->ki_flags` 中的 `IOCB_NOIO` 標誌表示不應為讀取或預讀發出新的 I/O 請求。當無法讀取資料時,應返回 `-EAGAIN`。當會觸發預讀時,應返回部分(可能為空)讀取。

返回

  • 複製的位元組數,即使是部分讀取

  • 如果沒有讀取任何資料,則為負錯誤碼(或如果 `IOCB_NOIO` 則為 `0`)

ssize_t filemap_splice_read(struct file *in, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags)

將檔案頁快取中的資料拼接進管道

引數

struct file *in

要讀取的檔案

loff_t *ppos

指向要讀取的檔案位置的指標

struct pipe_inode_info *pipe

要拼接到的管道

size_t len

要拼接的量

unsigned int flags

SPLICE_F_* 標誌

描述

此函式從檔案的頁快取中獲取 folio 並將其拼接進管道。必要時將呼叫預讀以填充更多 folio。此函式也可用於塊裝置。

返回

成功時,將返回讀取的位元組數,並酌情更新 **\*ppos**;如果沒有更多資料可讀,將返回 0;如果管道沒有空間,將返回 `-EAGAIN`;如果出錯,將返回其他負錯誤碼。如果管道空間不足、我們到達資料末尾或遇到空洞,可能會發生短讀。

vm_fault_t filemap_fault(struct vm_fault *vmf)

讀入檔案資料以進行頁錯誤處理

引數

struct vm_fault *vmf

包含錯誤詳細資訊的 struct vm_fault

描述

filemap_fault() 透過對映記憶體區域的 vma 操作向量呼叫,以在頁錯誤期間讀入檔案資料。

goto 語句有些難看,但這簡化了將其放入頁快取的正常情況,併合理地處理了特殊情況,而沒有大量重複程式碼。

進入時必須持有 `vma->vm_mm->mmap_lock`。

如果我們的返回值設定了 `VM_FAULT_RETRY`,那是因為 `mmap_lock` 可能會在進行 I/O 之前或被 `lock_folio_maybe_drop_mmap()` 釋放。

如果我們的返回值沒有設定 `VM_FAULT_RETRY`,則 `mmap_lock` 未被釋放。

我們從不返回 `VM_FAULT_RETRY` 並設定 `VM_FAULT_ERROR` 中的位。

返回

VM_FAULT_ 程式碼的按位或。

struct folio *read_cache_folio(struct address_space *mapping, pgoff_t index, filler_t filler, struct file *file)

讀入頁快取,如果需要則填充。

引數

struct address_space *mapping

要讀取的地址空間。

pgoff_t index

要讀取的索引。

filler_t filler

執行讀取的函式,如果使用 `aops->read_folio()` 則為 `NULL`。

struct file *file

傳遞給填充函式,如果不需要可以為 `NULL`。

描述

將一頁讀入頁快取。如果成功,返回的 folio 將包含 **index**,但它可能不是 folio 的第一頁。

如果填充函式返回錯誤,該錯誤將返回給呼叫者。

上下文

可能會睡眠。期望 `mapping->invalidate_lock` 被持有。

返回

成功時返回一個最新的 folio,失敗時返回 ERR_PTR()

struct folio *mapping_read_folio_gfp(struct address_space *mapping, pgoff_t index, gfp_t gfp)

讀入頁快取,使用指定的分配標誌。

引數

struct address_space *mapping

folio 的 address_space。

pgoff_t index

分配的 folio 將包含的索引。

gfp_t gfp

如果進行分配,使用的頁分配器標誌。

描述

這與“read_cache_folio(mapping, index, NULL, NULL)”相同,但任何新的記憶體分配都使用指定的分配標誌。

此函式最可能出現的錯誤是 `EIO`,但也可能出現 `ENOMEM` 和 `EINTR`。如果 `->read_folio` 返回其他錯誤,該錯誤將返回給呼叫者。

函式期望 `mapping->invalidate_lock` 已被持有。

返回

成功時返回最新的 folio,失敗時返回 ERR_PTR()

struct page *read_cache_page_gfp(struct address_space *mapping, pgoff_t index, gfp_t gfp)

讀入頁快取,使用指定的頁分配標誌。

引數

struct address_space *mapping

頁面的地址空間

pgoff_t index

頁索引

gfp_t gfp

如果進行分配,使用的頁分配器標誌

描述

這與“read_mapping_page(mapping, index, NULL)”相同,但任何新的頁分配都使用指定的分配標誌。

如果頁面未更新,則返回 `-EIO`。

函式期望 `mapping->invalidate_lock` 已被持有。

返回

成功時返回最新的頁面,失敗時返回 ERR_PTR()

ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from)

向檔案寫入資料

引數

struct kiocb *iocb

I/O 狀態結構(檔案、偏移量等)

struct iov_iter *from

包含要寫入資料的 iov_iter

描述

此函式執行將資料實際寫入檔案所需的所有工作。它執行所有基本檢查,從檔案中移除 SUID,更新修改時間,並根據我們是執行直接 I/O 還是標準緩衝寫入來呼叫適當的子例程。

它期望 `i_rwsem` 被獲取,除非我們處理塊裝置或類似不需要任何鎖定的物件。

此函式**不**負責在 `O_SYNC` 寫入的情況下同步資料。呼叫者必須處理它。這主要是因為我們希望避免在 `i_rwsem` 下進行同步。

返回

  • 寫入的位元組數,即使是截斷寫入

  • 如果完全沒有寫入資料,則為負錯誤碼

ssize_t generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from)

向檔案寫入資料

引數

struct kiocb *iocb

I/O 狀態結構

struct iov_iter *from

包含要寫入資料的 iov_iter

描述

這是 __generic_file_write_iter() 的包裝器,供大多數檔案系統使用。它處理 `O_SYNC` 檔案情況下的檔案同步,並根據需要獲取 `i_rwsem`。

返回

  • 如果完全沒有寫入資料,或者對於同步寫入,vfs_fsync_range() 失敗,則為負錯誤碼

  • 寫入的位元組數,即使是截斷寫入

bool filemap_release_folio(struct folio *folio, gfp_t gfp)

釋放 folio 上的檔案系統特定元資料。

引數

struct folio *folio

核心試圖釋放的 folio。

gfp_t gfp

記憶體分配標誌(和 I/O 模式)。

描述

`address_space` 試圖釋放附加到 folio(大概在 `folio->private`)的任何資料。

如果頁面上設定了 `private_2` 標誌,指示該 folio 具有其他相關元資料,也將呼叫此函式。

**gfp** 引數指定是否可以執行 I/O 來釋放此頁(`__GFP_IO`),以及呼叫是否可能阻塞(`__GFP_RECLAIM` & `__GFP_FS`)。

返回

如果釋放成功,則為 true,否則為 false

int filemap_invalidate_inode(struct inode *inode, bool flush, loff_t start, loff_t end)

使 inode 頁快取的某個範圍無效/強制回寫

引數

struct inode *inode

要重新整理的 inode

bool flush

設定為回寫而非簡單地使其無效。

loff_t start

範圍內的第一個位元組。

loff_t end

範圍內的最後一個位元組(包含),或 `LLONG_MAX` 表示從 `start` 開始的所有內容。

描述

使 inode 上對指定範圍有貢獻的所有 folio 無效,可能首先將它們回寫。在執行操作期間,`invalidate` 鎖被持有以防止新 folio 的安裝。

預讀

預讀用於在應用程式明確請求之前將內容讀入頁快取。預讀僅嘗試讀取尚未在頁快取中的 folio。如果 folio 存在但不是最新狀態,預讀將不會嘗試讀取它。在這種情況下,將請求簡單的 `->read_folio()`。

當應用程式讀取請求(無論是系統呼叫還是頁錯誤)發現請求的 folio 不在頁快取中,或者它在頁快取中且設定了預讀標誌時,會觸發預讀。此標誌表示該 folio 是作為先前預讀請求的一部分讀取的,現在已被訪問,是進行下一次預讀的時候了。

每個預讀請求都部分是同步讀取,部分是非同步預讀。這反映在 struct file_ra_state 中,其中 `->size` 是總頁數,`->async_size` 是非同步部分的頁數。預讀標誌將設定在此非同步部分中的第一個 folio 上,以觸發後續預讀。一旦建立了一系列順序讀取,就不需要同步元件,所有預讀請求都將完全非同步。

當任一觸發器導致預讀時,需要確定三個數字:要讀取區域的起始,區域的大小,以及非同步尾部的大小。

區域的起始只是訪問地址處或之後的第一個頁地址,該地址當前未在頁快取中填充。這透過在頁快取中的簡單搜尋找到。

非同步尾部的大小透過從確定的請求大小中減去明確請求的大小來確定,除非這會小於零——在這種情況下使用零。注意:當區域的起始不是訪問頁時,此計算是錯誤的。而且此計算未被一致使用。

區域的大小通常根據載入前一頁的先前預讀的大小來確定。這可以從簡單順序讀取的 struct file_ra_state 中發現,或者在多個順序讀取交錯時檢查頁快取的狀態。具體來說:如果預讀是由預讀標誌觸發的,則假定先前預讀的大小是從觸發頁到新預讀開始的頁數。在這些情況下,先前預讀的大小會按比例縮放,通常會翻倍,用於新的預讀,但具體細節請參閱 `get_next_ra_size()`。

如果無法確定前一次讀取的大小,則使用頁快取中前置頁的數量來估計前一次讀取的大小。這個估計很容易被偶然相鄰的隨機讀取誤導,因此除非它大於當前請求,否則它會被忽略,並且它不會按比例放大,除非它位於檔案開頭。

通常,預讀在檔案開頭會加速,因為從那裡讀取通常是順序的。在各種特殊情況下,預讀大小還有其他微小的調整,最好透過閱讀程式碼來發現這些調整。

上述基於先前預讀大小的計算確定了預讀的大小,在此基礎上可以新增任何請求的讀取大小。

預讀請求透過 `->readahead()` 地址空間操作傳送到檔案系統,其中 mpage_readahead() 是一個典型的實現。`->readahead()` 通常應啟動所有 folio 的讀取,但可能無法讀取任何或所有 folio 而不導致 I/O 錯誤。頁快取讀取程式碼將對 `->readahead()` 未讀取的任何 folio 發出 `->read_folio()` 請求,並且只有來自此請求的錯誤才是最終的。

`->readahead()` 通常會重複呼叫 readahead_folio() 來獲取為預讀準備的每個 folio。它可能因以下原因無法讀取 folio:

  • 未充分多次呼叫 readahead_folio(),實際上忽略了一些 folio,這在儲存路徑擁堵時可能適用。

  • 未能實際提交給定 folio 的讀取請求,可能是由於資源不足,或者

  • 在請求的後續處理過程中出現錯誤。

在後兩種情況下,檔案系統應解鎖 folio 以指示讀取嘗試失敗。在第一種情況下,folio 將由 VFS 解鎖。

請求最終 `async_size` 中未包含的那些 folio 應被視為重要,`->readahead()` 不應因擁塞或臨時資源不可用而使它們失敗,而應等待必要的資源(例如記憶體或索引資訊)變得可用。最終 `async_size` 中的 folio 可能被視為不那麼緊急,並且未能讀取它們更容易接受。在這種情況下,最好使用 `filemap_remove_folio()` 將 folio 從頁快取中移除,這對於未透過 readahead_folio() 獲取的 folio 會自動完成。這將允許後續的同步預讀請求再次嘗試它們。如果它們留在頁快取中,那麼它們將使用 `->read_folio()` 單獨讀取,這可能效率較低。

void page_cache_ra_unbounded(struct readahead_control *ractl, unsigned long nr_to_read, unsigned longlookahead_size)

開始無邊界預讀。

引數

struct readahead_control *ractl

預讀控制。

unsigned long nr_to_read

要讀取的頁數。

unsigned long lookahead_size

下一次預讀的起始位置。

描述

此函式供檔案系統在希望開始超出檔案宣告的 `i_size` 的預讀時呼叫。這幾乎肯定不是您想要呼叫的函式。請改用 page_cache_async_readahead()page_cache_sync_readahead()

上下文

檔案由呼叫者引用。呼叫者可能持有互斥鎖。可能會睡眠,但不會重入檔案系統以回收記憶體。

void readahead_expand(struct readahead_control *ractl, loff_t new_start, size_t new_len)

擴充套件預讀請求

引數

struct readahead_control *ractl

要擴充套件的請求

loff_t new_start

修訂後的起始位置

size_t new_len

修訂後的請求大小

描述

嘗試將預讀請求從當前大小向外擴充套件到指定大小,透過在當前視窗之前和之後插入鎖定的頁面來增加大小到新視窗。這可能涉及插入 THP,在這種情況下,視窗可能會擴充套件超出請求的範圍。

如果演算法遇到頁快取中已有的衝突頁面,它將停止並保留比請求更小的擴充套件。

呼叫者必須透過檢查修訂後的 **ractl** 物件是否與請求的擴充套件不同來檢查這一點。

回寫

int balance_dirty_pages_ratelimited_flags(struct address_space *mapping, unsigned int flags)

平衡髒記憶體狀態。

引數

struct address_space *mapping

被標記為髒的 address_space。

unsigned int flags

BDP 標誌。

描述

正在將記憶體標記為髒的程序應為每個新標記為髒的頁呼叫此函式一次。該函式將定期檢查系統的髒狀態,並在需要時啟動回寫。

有關詳細資訊,請參閱 balance_dirty_pages_ratelimited()

返回

如果 flags 包含 BDP_ASYNC,它可能返回 -EAGAIN 以指示記憶體失衡,呼叫者必須等待 I/O 完成。否則,它將返回 0,表示記憶體已平衡,或者它能夠休眠直到髒記憶體量恢復平衡。

void balance_dirty_pages_ratelimited(struct address_space *mapping)

平衡髒記憶體狀態。

引數

struct address_space *mapping

被標記為髒的 address_space。

描述

正在將記憶體標記為髒的程序應為每個新標記為髒的頁呼叫此函式一次。該函式將定期檢查系統的髒狀態,並在需要時啟動回寫。

一旦我們超過了髒記憶體限制,我們會大幅降低速率限制,以防止單個程序各自超出限制(ratelimit_pages)。

void tag_pages_for_writeback(struct address_space *mapping, pgoff_t start, pgoff_t end)

標記要由回寫機制寫入的頁面

引數

struct address_space *mapping

要回寫的 address space 結構

pgoff_t start

起始頁索引

pgoff_t end

結束頁索引(包含)

描述

此函式掃描從 startend(包含)的頁範圍,併為所有設定了 DIRTY 標籤的頁標記一個特殊的 TOWRITE 標籤。呼叫者隨後可以使用 TOWRITE 標籤來識別符合回寫條件的頁。此機制用於避免因程序不斷在檔案中建立新的髒頁而導致回寫活鎖(因此此函式必須快速,以便它標記頁的速度快於髒頁建立程序的速度)。

struct folio *writeback_iter(struct address_space *mapping, struct writeback_control *wbc, struct folio *folio, int *error)

迭代對映的 folio 以進行回寫

引數

struct address_space *mapping

要回寫的 address space 結構

struct writeback_control *wbc

回寫上下文

struct folio *folio

之前迭代的 folio(NULL 表示開始)

int *error

用於回寫錯誤的輸入/輸出指標(參見下文)

描述

此函式返回 **wbc** 在 **mapping** 上描述的回寫操作的下一個 folio,應在 `->writepages` 實現的 while 迴圈中呼叫。

要開始回寫操作,在 **folio** 引數中傳遞 NULL,對於隨後的每次迭代,應將之前返回的 folio 傳回。

如果在 writeback_iter() 迴圈內部的每個 folio 回寫中發生錯誤,應將 **error** 設定為錯誤值。

一旦 **wbc** 中描述的回寫完成,此函式將返回 NULL,如果任何迭代中發生錯誤,則將其恢復到 **error**。

注意

呼叫者不應使用 `break` 或 `goto` 手動跳出迴圈,而必須持續呼叫 writeback_iter() 直到它返回 NULL

返回

要寫入的 folio,如果迴圈完成則為 NULL

int write_cache_pages(struct address_space *mapping, struct writeback_control *wbc, writepage_t writepage, void *data)

遍歷給定 address space 的髒頁列表並寫入所有這些頁。

引數

struct address_space *mapping

要回寫的 address space 結構

struct writeback_control *wbc

從 **`*wbc->nr_to_write`** 中減去已寫入頁的數量

writepage_t writepage

為每個頁呼叫的函式

void *data

傳遞給 `writepage` 函式的資料

返回

成功時返回 0,否則返回負錯誤碼

注意

請改用 writeback_iter()

bool filemap_dirty_folio(struct address_space *mapping, struct folio *folio)

為不使用 buffer_heads 的檔案系統將 folio 標記為髒。

引數

struct address_space *mapping

此 folio 所屬的地址空間。

struct folio *folio

要標記為髒的 folio。

描述

不使用 `buffer_heads` 的檔案系統應從其 `dirty_folio` 地址空間操作中呼叫此函式。它忽略 `folio_get_private()` 的內容,因此如果檔案系統將單個塊標記為髒,檔案系統應自行處理。

使用 `buffer_heads` 的檔案系統有時也會在單個緩衝區被標記為髒時使用此函式:在這種情況下,我們希望將 folio 標記為髒,而不是所有緩衝區。這是一種“自下而上”的髒標記,而 block_dirty_folio() 是一種“自上而下”的髒標記。

呼叫者必須確保這不會與截斷髮生競爭。大多數情況下只需持有 folio 鎖即可,但例如 `zap_pte_range()` 在 folio 已對映且持有 pte 鎖時呼叫,這也會阻止截斷。

bool folio_redirty_for_writepage(struct writeback_control *wbc, struct folio *folio)

拒絕寫入髒 folio。

引數

struct writeback_control *wbc

回寫控制。

struct folio *folio

該 folio。

描述

當 `writepage` 實現因某種原因決定不寫入 **folio** 時,它應該呼叫此函式,解鎖 **folio** 並返回 0。

返回

如果重新標記 folio 為髒則為 True。如果其他人先將其標記為髒則為 False。

bool folio_mark_dirty(struct folio *folio)

將 folio 標記為已修改。

引數

struct folio *folio

該 folio。

描述

此函式執行時,folio 不得被截斷。持有 folio 鎖足以防止截斷,但有些呼叫者無法獲取睡眠鎖。這些呼叫者會轉而持有包含此 folio 中至少一個頁的頁表的頁表鎖。截斷會在解除頁對映並從其對映中移除 folio 之前阻塞在頁表鎖上。

返回

如果 folio 是新標記為髒的則為 True,如果已是髒的則為 False。

void folio_wait_writeback(struct folio *folio)

等待 folio 完成回寫。

引數

struct folio *folio

要等待的 folio。

描述

如果 folio 當前正在回寫到儲存,則等待 I/O 完成。

上下文

休眠。必須在程序上下文中呼叫,並且不能持有自旋鎖。呼叫者應持有 folio 的引用。如果 folio 未鎖定,回寫完成後可能會再次開始回寫。

int folio_wait_writeback_killable(struct folio *folio)

等待 folio 完成回寫。

引數

struct folio *folio

要等待的 folio。

描述

如果 folio 當前正在回寫到儲存,則等待 I/O 完成或致命訊號到達。

上下文

休眠。必須在程序上下文中呼叫,並且不能持有自旋鎖。呼叫者應持有 folio 的引用。如果 folio 未鎖定,回寫完成後可能會再次開始回寫。

返回

成功時返回 0,如果在等待期間收到致命訊號則返回 -EINTR。

void folio_wait_stable(struct folio *folio)

等待回寫完成,如果需要的話。

引數

struct folio *folio

要等待的 folio。

描述

此函式判斷給定 folio 是否與要求在回寫期間保持 folio 內容穩定的後端裝置相關。如果是,則它將等待任何待處理的回寫完成。

上下文

休眠。必須在程序上下文中呼叫,並且不能持有自旋鎖。呼叫者應持有 folio 的引用。如果 folio 未鎖定,回寫完成後可能會再次開始回寫。

截斷

void folio_invalidate(struct folio *folio, size_t offset, size_t length)

使 folio 的部分或全部無效。

引數

struct folio *folio

受影響的 folio。

size_t offset

要無效化範圍的起始

size_t length

要無效化範圍的長度

描述

當 folio 的全部或部分因截斷操作而變得無效時,會呼叫 folio_invalidate()

folio_invalidate() 無需釋放所有緩衝區,但它必須確保 **offset** 之外沒有髒緩衝區,並且沒有針對截斷點之外的任何塊進行 I/O。因為呼叫者即將釋放(並可能重用)磁碟上的那些塊。

void truncate_inode_pages_range(struct address_space *mapping, loff_t lstart, loff_t lend)

截斷由起始和結束位元組偏移量指定的頁範圍

引數

struct address_space *mapping

要截斷的對映

loff_t lstart

從哪個偏移量開始截斷

loff_t lend

到哪個偏移量結束截斷(包含)

描述

截斷頁快取,移除指定偏移量之間的頁(如果 `lstart` 或 `lend + 1` 未按頁對齊,則將部分頁清零)。

截斷分兩次進行——第一次是非阻塞的。它不會阻塞頁鎖,也不會阻塞回寫。第二次會等待。這是為了儘可能阻止受影響區域的 I/O。第一次會移除大部分頁,因此第二次的搜尋成本較低。

我們將快取熱點提示傳遞給頁釋放程式碼。即使對映很大,通常也是最後幾個頁是最近訪問過的,並且釋放是按檔案偏移量升序進行的。

請注意,由於 `->invalidate_folio()` 接受要無效化的範圍,truncate_inode_pages_range 能夠正確處理 `lend + 1` 未按頁對齊的情況。

void truncate_inode_pages(struct address_space *mapping, loff_t lstart)

從一個偏移量開始截斷 *所有* 頁

引數

struct address_space *mapping

要截斷的對映

loff_t lstart

從哪個偏移量開始截斷

描述

在 `inode->i_rwsem` 和 `mapping->invalidate_lock` 的保護下(並序列化)呼叫。

注意

當此函式返回時,指定範圍內可能有一個正在刪除過程中的頁(在 `__filemap_remove_folio()` 內部)。因此,即使在整個對映被截斷之後,當此函式返回時 `mapping->nrpages` 也可以是非零的。

void truncate_inode_pages_final(struct address_space *mapping)

在 inode 銷燬前截斷 *所有* 頁

引數

struct address_space *mapping

要截斷的對映

描述

在 `inode->i_rwsem` 的保護下(並序列化)呼叫。

檔案系統必須在 `.evict_inode` 路徑中使用此函式,以通知 VM 這是最終截斷,並且 inode 將被移除。

unsigned long invalidate_mapping_pages(struct address_space *mapping, pgoff_t start, pgoff_t end)

使一個 inode 的所有乾淨、未鎖定快取無效

引數

struct address_space *mapping

包含要無效化快取的 `address_space`

pgoff_t start

要無效化的起始偏移量

pgoff_t end

要無效化的結束偏移量(包含)

描述

此函式移除乾淨、未對映和未鎖定的頁,以及影子條目。它不會阻塞 I/O 活動。

如果您想移除一個 inode 的所有頁,無論其使用和回寫狀態如何,請使用 truncate_inode_pages()

返回

其內容已無效化的索引數量

int invalidate_inode_pages2_range(struct address_space *mapping, pgoff_t start, pgoff_t end)

從 `address_space` 中移除頁範圍

引數

struct address_space *mapping

該 `address_space`

pgoff_t start

要無效化的頁起始偏移量

pgoff_t end

要無效化的頁結束偏移量(包含)

描述

在無效化之前,任何發現對映到頁表中的頁都將被解除對映。

返回

如果任何頁無法無效化,則返回 -EBUSY。

int invalidate_inode_pages2(struct address_space *mapping)

從 `address_space` 中移除所有頁

引數

struct address_space *mapping

該 `address_space`

描述

在無效化之前,任何發現對映到頁表中的頁都將被解除對映。

返回

如果任何頁無法無效化,則返回 -EBUSY。

void truncate_pagecache(struct inode *inode, loff_t newsize)

解除對映並移除已截斷的頁快取

引數

struct inode *inode

inode

loff_t newsize

新檔案大小

描述

在呼叫 `truncate_pagecache` 之前,inode 的新 `i_size` 必須已寫入。

此函式通常應在檔案系統釋放與已釋放範圍相關的資源(例如,解除分配塊)之前呼叫。這樣,頁快取將始終與磁碟格式保持邏輯一致,檔案系統也無需處理諸如為底層塊已解除分配的頁呼叫 `writepage` 的情況。

void truncate_setsize(struct inode *inode, loff_t newsize)

更新 inode 和頁快取以適應新的檔案大小

引數

struct inode *inode

inode

loff_t newsize

新檔案大小

描述

`truncate_setsize` 更新 `i_size` 並(如果需要)將頁快取截斷到 **newsize**。它通常在檔案系統的 `setattr` 函式中,當傳遞 `ATTR_SIZE` 時被呼叫。

必須在持有序列化截斷和寫入的鎖(通常是 `i_rwsem`,但例如 xfs 使用不同的鎖)並且在執行所有檔案系統特定的塊截斷之前呼叫。

void pagecache_isize_extended(struct inode *inode, loff_t from, loff_t to)

在 `i_size` 擴充套件後更新頁快取

引數

struct inode *inode

`i_size` 被擴充套件的 inode

loff_t from

原始 inode 大小

loff_t to

新 inode 大小

描述

處理因擴充套件截斷或在當前 `i_size` 之後開始寫入而導致的 inode 大小擴充套件。我們將跨越當前 `i_size` 的頁標記為只讀 (RO),以便在首次寫入訪問該頁時呼叫 `page_mkwrite()`。在 `i_size` 更改後,檔案系統將在使用者透過 `mmap` 寫入該頁之前更新其每塊資訊。

此函式必須在 `i_size` 更新後呼叫,以便在我們解鎖 folio 之後發生的頁錯誤能夠看到新的 `i_size`。此函式必須在我們仍持有 `i_rwsem` 時呼叫——這不僅確保 `i_size` 穩定,而且確保在準備好以新的 inode 大小儲存 `mmap` 寫入之前,使用者空間無法觀察到新的 `i_size` 值。

void truncate_pagecache_range(struct inode *inode, loff_t lstart, loff_t lend)

解除對映並移除已打洞的頁快取

引數

struct inode *inode

inode

loff_t lstart

洞的起始偏移量

loff_t lend

洞的最後一個位元組的偏移量

描述

此函式通常應在檔案系統釋放與已釋放範圍相關的資源(例如,解除分配塊)之前呼叫。這樣,頁快取將始終與磁碟格式保持邏輯一致,檔案系統也無需處理諸如為底層塊已解除分配的頁呼叫 `writepage` 的情況。

void filemap_set_wb_err(struct address_space *mapping, int err)

在 `address_space` 上設定回寫錯誤

引數

struct address_space *mapping

要設定回寫錯誤的對映

int err

要在對映中設定的錯誤

描述

當回寫以某種方式失敗時,我們必須記錄該錯誤,以便在呼叫 `fsync` 等操作時通知使用者空間。我們力求報告錯誤發生時所有開啟的檔案上的錯誤。一些內部呼叫者也需要知道何時發生了回寫錯誤。

當發生回寫錯誤時,大多數檔案系統會希望呼叫 `filemap_set_wb_err` 來在對映中記錄錯誤,以便在檔案上呼叫 `fsync` 時自動報告該錯誤。

int filemap_check_wb_err(struct address_space *mapping, errseq_t since)

自標記取樣以來是否發生過錯誤?

引數

struct address_space *mapping

要檢查回寫錯誤的對映

errseq_t since

之前取樣的 `errseq_t`

描述

從對映中獲取 `errseq_t` 值,並檢視它自給定值取樣以來是否已更改。

如果已更改,則報告最新設定的錯誤,否則返回 0。

errseq_t filemap_sample_wb_err(struct address_space *mapping)

取樣當前 `errseq_t` 以測試後續錯誤

引數

struct address_space *mapping

要取樣的對映

描述

回寫錯誤總是相對於過去的特定取樣點報告。此函式提供這些取樣點。

errseq_t file_sample_sb_err(struct file *file)

取樣當前 `errseq_t` 以測試後續錯誤

引數

struct file *file

要取樣的檔案指標

描述

獲取給定 struct file 的最新超塊級別 `errseq_t` 值。

void mapping_set_error(struct address_space *mapping, int error)

在 `address_space` 中記錄回寫錯誤

引數

struct address_space *mapping

應設定錯誤的對映

int error

要在對映中設定的錯誤

描述

當回寫以某種方式失敗時,我們必須記錄該錯誤,以便在呼叫 `fsync` 等操作時通知使用者空間。我們力求報告錯誤發生時所有開啟的檔案上的錯誤。一些內部呼叫者也需要知道何時發生了回寫錯誤。

當發生回寫錯誤時,大多數檔案系統會希望呼叫 `mapping_set_error` 來在對映中記錄錯誤,以便在應用程式呼叫 `fsync(2)` 時可以報告該錯誤。

void mapping_set_large_folios(struct address_space *mapping)

指示檔案支援大 folio。

引數

struct address_space *mapping

檔案的地址空間。

描述

檔案系統應在其 inode 建構函式中呼叫此函式,以指示 VFS 可以使用大 folio 來快取檔案內容。

上下文

不應在 inode 活動時呼叫此函式,因為它不是原子的。

pgoff_t mapping_align_index(struct address_space *mapping, pgoff_t index)

為此對映對齊索引。

引數

struct address_space *mapping

該 `address_space`。

pgoff_t index

頁索引。

描述

folio 的索引必須自然對齊。如果您要向頁快取新增新的 folio 並需要知道為其分配哪個索引,請呼叫此函式。

struct folio *folio_flush_mapping(struct folio *folio)

查詢此 folio 所屬的檔案對映。

引數

struct folio *folio

該 folio。

描述

對於頁快取中的 folio,返回此頁所屬的對映。匿名 folio 返回 `NULL`,即使它們在交換快取中。其他型別的 folio 也返回 `NULL`。

此函式僅由架構快取重新整理程式碼使用。如果您不是編寫快取重新整理程式碼,您可能需要 folio_mapping() 或 `folio_file_mapping()`。

struct inode *folio_inode(struct folio *folio)

獲取此 folio 的宿主 inode。

引數

struct folio *folio

該 folio。

描述

對於頁快取中的 folio,返回此 folio 所屬的 inode。

不要為不在頁快取中的 folio 呼叫此函式。

void folio_attach_private(struct folio *folio, void *data)

將私有資料附加到 folio。

引數

struct folio *folio

要附加資料的 folio。

void *data

要附加到 folio 的資料。

描述

將私有資料附加到 folio 會增加頁的引用計數。資料必須在 folio 釋放之前分離。

void *folio_change_private(struct folio *folio, void *data)

更改 folio 上的私有資料。

引數

struct folio *folio

要更改資料的 folio。

void *data

要在 folio 上設定的資料。

描述

更改附加到 folio 的私有資料並返回舊資料。該頁之前必須已附加資料,並且資料必須在 folio 釋放之前分離。

返回

之前附加到 folio 的資料。

void *folio_detach_private(struct folio *folio)

從 folio 分離私有資料。

引數

struct folio *folio

要分離資料的 folio。

描述

移除之前附加到 folio 的資料,並減少頁的引用計數。

返回

附加到 folio 的資料。

type fgf_t

從頁快取獲取 folio 的標誌。

描述

大多數頁快取使用者不需要使用這些標誌;有一些便利函式,例如 filemap_get_folio()filemap_lock_folio()。對於需要更精確控制 folio 操作的使用者,可以使用這些傳遞給 __filemap_get_folio() 的標誌。

  • FGP_ACCESSED - folio 將被標記為已訪問。

  • FGP_LOCK - 返回的 folio 將被鎖定。

  • FGP_CREAT - 如果沒有 folio,則分配一個新的 folio,並將其新增到頁快取和 VM 的 LRU 列表中。返回的 folio 將被鎖定。

  • FGP_FOR_MMAP - 如果 folio 已在快取中,呼叫者希望執行自己的鎖定操作。如果 folio 是新分配的,則在返回前解鎖它,以便呼叫者可以執行相同的操作。

  • FGP_WRITE - folio 將由呼叫者寫入。

  • FGP_NOFS - `__GFP_FS` 將在 `gfp` 中被清除。

  • FGP_NOWAIT - 不阻塞 folio 鎖。

  • FGP_STABLE - 等待 folio 穩定(完成回寫)

  • FGP_DONTCACHE - 無快取的緩衝 I/O

  • FGP_WRITEBEGIN - 在檔案系統 `write_begin()` 實現中使用的標誌。

fgf_t fgf_set_order(size_t size)

在 `fgf_t` 標誌中編碼長度。

引數

size_t size

建議建立的 folio 大小。

描述

__filemap_get_folio() 的呼叫者可以使用此函式來建議建立的 folio 的首選大小。如果索引處已存在 folio,則無論其大小如何,都將返回該 folio。如果新建立 folio,則由於對齊約束、記憶體壓力或附近索引處存在其他 folio,其大小可能與請求的不同。

struct folio *filemap_get_folio(struct address_space *mapping, pgoff_t index)

查詢並獲取 folio。

引數

struct address_space *mapping

要搜尋的 address_space。

pgoff_t index

頁索引。

描述

查詢 **mapping** 和 **index** 處的頁快取條目。如果存在 folio,則返回該 folio 並增加引用計數。

返回

一個 folio,如果此索引的快取中沒有 folio,則返回 `ERR_PTR(-ENOENT)`。不會返回影子、交換或 DAX 條目。

struct folio *filemap_lock_folio(struct address_space *mapping, pgoff_t index)

查詢並鎖定 folio。

引數

struct address_space *mapping

要搜尋的 address_space。

pgoff_t index

頁索引。

描述

查詢 **mapping** 和 **index** 處的頁快取條目。如果存在 folio,則返回該 folio 並鎖定,同時增加引用計數。

上下文

可能休眠。

返回

一個 folio,如果此索引的快取中沒有 folio,則返回 `ERR_PTR(-ENOENT)`。不會返回影子、交換或 DAX 條目。

struct folio *filemap_grab_folio(struct address_space *mapping, pgoff_t index)

從頁快取中獲取 folio

引數

struct address_space *mapping

要搜尋的地址空間

pgoff_t index

頁索引

描述

查詢 **mapping** 和 **index** 處的頁快取條目。如果未找到 folio,則建立一個新的 folio。該 folio 被鎖定,標記為已訪問,並返回。

返回

找到或建立的 folio。如果未找到 folio 且建立失敗,則返回 `ERR_PTR(-ENOMEM)`。

struct page *find_get_page(struct address_space *mapping, pgoff_t offset)

查詢並獲取頁引用

引數

struct address_space *mapping

要搜尋的 `address_space`

pgoff_t offset

頁索引

描述

查詢 **mapping** 和 **offset** 處的頁快取槽。如果存在頁快取頁,則返回該頁並增加引用計數。

否則,返回 NULL

struct page *find_lock_page(struct address_space *mapping, pgoff_t index)

定位、固定並鎖定頁快取頁

引數

struct address_space *mapping

要搜尋的 `address_space`

pgoff_t index

頁索引

描述

查詢 **mapping** 和 **index** 處的頁快取條目。如果存在頁快取頁,則返回該頁並鎖定,同時增加引用計數。

上下文

可能休眠。

返回

一個 `struct page`,如果此索引的快取中沒有頁,則為 NULL

struct page *find_or_create_page(struct address_space *mapping, pgoff_t index, gfp_t gfp_mask)

定位或新增頁快取頁

引數

struct address_space *mapping

頁面的地址空間

pgoff_t index

頁在對映中的索引

gfp_t gfp_mask

頁分配模式

描述

查詢 **mapping** 和 **offset** 處的頁快取槽。如果存在頁快取頁,則返回該頁並鎖定,同時增加引用計數。

如果頁不存在,則使用 **gfp_mask** 分配一個新頁,並將其新增到頁快取和 VM 的 LRU 列表中。該頁被鎖定並返回,同時增加引用計數。

記憶體耗盡時,返回 NULL

find_or_create_page() 可能會休眠,即使 **gfp_flags** 指定了原子分配!

struct page *grab_cache_page_nowait(struct address_space *mapping, pgoff_t index)

返回給定快取中給定索引處的鎖定頁

引數

struct address_space *mapping

目標地址空間

pgoff_t index

頁索引

描述

與 `grab_cache_page()` 相同,但如果頁不可用則不等待。這適用於推測性資料生成器,其中如果無法獲取頁,則可以重新生成資料。在持有另一個頁的鎖時呼叫此例程應該是安全的。

在分配頁時清除 `__GFP_FS`,以避免遞迴進入檔案系統並與呼叫者的鎖定頁產生死鎖。

pgoff_t folio_next_index(struct folio *folio)

獲取下一個 folio 的索引。

引數

struct folio *folio

當前 folio。

返回

檔案中此 folio 之後的 folio 的索引。

struct page *folio_file_page(struct folio *folio, pgoff_t index)

特定索引對應的頁。

引數

struct folio *folio

包含此索引的 folio。

pgoff_t index

我們想要查詢的索引。

描述

有時在頁快取中查詢 folio 後,我們需要獲取特定索引對應的頁(例如頁錯誤)。

返回

包含此索引檔案資料的頁。

bool folio_contains(struct folio *folio, pgoff_t index)

此 folio 是否包含此索引?

引數

struct folio *folio

該 folio。

pgoff_t index

檔案內的頁索引。

上下文

呼叫者應已鎖定 folio 並確保例如 `shmem` 未將此 folio 移動到交換快取。

返回

真或假。

pgoff_t page_pgoff(const struct folio *folio, const struct page *page)

計算此頁的邏輯頁偏移量。

引數

const struct folio *folio

包含此頁的 folio。

const struct page *page

我們需要獲取偏移量的頁。

描述

對於檔案頁,這是檔案開頭以 `PAGE_SIZE` 為單位的偏移量。對於匿名頁,這是 `anon_vma` 開頭以 `PAGE_SIZE` 為單位的偏移量。對於 KSM 頁,這將返回無意義的值。

上下文

呼叫者必須持有 folio 的引用,否則阻止其被拆分或釋放。

返回

以 `PAGE_SIZE` 為單位的偏移量。

loff_t folio_pos(const struct folio *folio)

返回此 folio 在其檔案中的位元組位置。

引數

const struct folio *folio

該 folio。

bool folio_trylock(struct folio *folio)

嘗試鎖定 folio。

引數

struct folio *folio

要嘗試鎖定的 folio。

描述

有時不希望等待 folio 解鎖(例如,當鎖以錯誤的順序獲取時,或者批處理 folio 比按順序處理它們更重要時)。通常 folio_lock() 是正確的呼叫函式。

上下文

任何上下文。

返回

鎖是否成功獲取。

void folio_lock(struct folio *folio)

鎖定此 folio。

引數

struct folio *folio

要鎖定的 folio。

描述

folio 鎖保護許多方面,可能比它應該保護的更多。它主要在 folio 從其後端檔案或交換空間更新時持有。它也在 folio 從其 `address_space` 截斷時持有,因此持有此鎖足以保持 `folio->mapping` 穩定。

當 `write()` 修改頁以提供 POSIX 原子性保證時(只要寫入不跨越頁邊界),也會持有 folio 鎖。對 folio 中資料的其他修改不持有 folio 鎖,並且可能與寫入競爭,例如 DMA 和對對映頁的儲存。

上下文

可能休眠。如果您需要獲取兩個或更多 folio 的鎖,如果它們在同一個 `address_space` 中,則必須按升序索引獲取。如果它們在不同的 `address_space` 中,則首先獲取屬於記憶體中地址最低的 `address_space` 的 folio 的鎖。

void lock_page(struct page *page)

鎖定包含此頁的 folio。

引數

struct page *page

要鎖定的頁。

描述

有關鎖保護內容的描述,請參閱 folio_lock()。這是一個遺留函式,新程式碼可能應該改用 folio_lock()

上下文

可能休眠。同一個 folio 中的頁共享一個鎖,因此不要嘗試鎖定共享一個 folio 的兩個頁。

int folio_lock_killable(struct folio *folio)

鎖定此 folio,可被致命訊號中斷。

引數

struct folio *folio

要鎖定的 folio。

描述

嘗試鎖定 folio,類似於 folio_lock(),但獲取鎖的休眠可被致命訊號中斷。

上下文

可能休眠;參見 folio_lock()

返回

如果成功獲取鎖則為 0;如果收到致命訊號則為 -EINTR。

bool filemap_range_needs_writeback(struct address_space *mapping, loff_t start_byte, loff_t end_byte)

檢查範圍是否可能需要回寫

引數

struct address_space *mapping

要檢查的地址空間

loff_t start_byte

範圍起始的位元組偏移量

loff_t end_byte

範圍結束的位元組偏移量(包含)

描述

在提供的範圍內查詢至少一個頁,通常用於檢查在此範圍內直接寫入是否會觸發回寫。由帶 `IOCB_NOWAIT` 的 `O_DIRECT` 讀/寫使用,以檢視呼叫者在繼續之前是否需要執行 filemap_write_and_wait_range()

返回

如果呼叫者在此範圍內對頁執行 `O_DIRECT` 操作之前應執行 filemap_write_and_wait_range(),則為 true,否則為 false

struct readahead_control

描述一個預讀請求。

定義:

struct readahead_control {
    struct file *file;
    struct address_space *mapping;
    struct file_ra_state *ra;
};

成員

檔案

檔案,主要由網路檔案系統用於身份驗證。如果由檔案系統內部呼叫,則可能為 `NULL`。

對映

預讀此檔案系統物件。

ra

檔案預讀狀態。可能為 `NULL`。

描述

預讀請求針對連續頁。實現 `->readahead` 方法的檔案系統應在迴圈中呼叫 readahead_folio() 或 `__readahead_batch()`,並嘗試開始讀取請求中的每個 folio。

此結構中的大多數字段是私有的,應由以下函式訪問。

void page_cache_sync_readahead(struct address_space *mapping, struct file_ra_state *ra, struct file *file, pgoff_t index, unsigned long req_count)

通用檔案預讀

引數

struct address_space *mapping

包含頁快取和 I/O 向量的 `address_space`

struct file_ra_state *ra

包含預讀狀態的 `file_ra_state`

struct file *file

檔案系統用於身份驗證。

pgoff_t index

要讀取的第一個頁的索引。

unsigned long req_count

呼叫者正在讀取的頁總數。

描述

page_cache_sync_readahead() 應該在快取未命中時被呼叫:它將提交讀取。預讀邏輯可能會決定,如果訪問模式表明能提高效能,則在讀取請求中附加更多頁。

void page_cache_async_readahead(struct address_space *mapping, struct file_ra_state *ra, struct file *file, struct folio *folio, unsigned long req_count)

檔案預讀,用於標記的頁

引數

struct address_space *mapping

包含頁快取和 I/O 向量的 `address_space`

struct file_ra_state *ra

包含預讀狀態的 `file_ra_state`

struct file *file

檔案系統用於身份驗證。

struct folio *folio

觸發預讀呼叫的folio。

unsigned long req_count

呼叫者正在讀取的頁總數。

描述

page_cache_async_readahead() 應該在頁面被標記為 PageReadahead 並被使用時呼叫;這是一個標記,表明應用程式已使用了足夠的預讀視窗,我們應該開始引入更多頁。

struct folio *readahead_folio(struct readahead_control *ractl)

獲取下一個要讀取的folio。

引數

struct readahead_control *ractl

當前的預讀請求。

上下文

該folio已被鎖定。一旦所有對該folio的I/O操作完成,呼叫者應解鎖該folio。

返回

指向下一個folio的指標,如果已完成則為 NULL

loff_t readahead_pos(struct readahead_control *rac)

此預讀請求在檔案中的位元組偏移量。

引數

struct readahead_control *rac

預讀請求。

size_t readahead_length(struct readahead_control *rac)

此預讀請求中的位元組數。

引數

struct readahead_control *rac

預讀請求。

pgoff_t readahead_index(struct readahead_control *rac)

此預讀請求中第一個頁的索引。

引數

struct readahead_control *rac

預讀請求。

unsigned int readahead_count(struct readahead_control *rac)

此預讀請求中的頁數。

引數

struct readahead_control *rac

預讀請求。

size_t readahead_batch_length(struct readahead_control *rac)

當前批處理中的位元組數。

引數

struct readahead_control *rac

預讀請求。

ssize_t folio_mkwrite_check_truncate(struct folio *folio, struct inode *inode)

檢查folio是否被截斷

引數

struct folio *folio

要檢查的folio

struct inode *inode

用於檢查folio的inode

返回

folio中到檔案末尾(EOF)的位元組數,如果folio被截斷則為 -EFAULT。

unsigned int i_blocks_per_folio(struct inode *inode, struct folio *folio)

此folio中可容納的塊數。

引數

struct inode *inode

包含這些塊的inode。

struct folio *folio

該 folio。

描述

如果塊大小大於此folio的大小,則返回零。

上下文

呼叫者應持有對folio的引用計數,以防止其被拆分。

返回

此folio覆蓋的檔案系統塊數量。

記憶體池

void mempool_exit(mempool_t *pool)

退出一個用 mempool_init() 初始化的記憶體池

引數

mempool_t *pool

指向已用 mempool_init() 初始化的記憶體池的指標。

描述

釋放 **pool** 中所有保留的元素以及 **pool** 本身。此函式僅在 free_fn() 函式休眠時休眠。

可以在歸零但未初始化的記憶體池(即使用 kzalloc() 分配的記憶體池)上呼叫。

void mempool_destroy(mempool_t *pool)

解除分配記憶體池

引數

mempool_t *pool

指向透過 mempool_create() 分配的記憶體池的指標。

描述

釋放 **pool** 中所有保留的元素以及 **pool** 本身。此函式僅在 free_fn() 函式休眠時休眠。

int mempool_resize(mempool_t *pool, int new_min_nr)

調整現有記憶體池的大小

引數

mempool_t *pool

指向透過 mempool_create() 分配的記憶體池的指標。

int new_min_nr

保證為此池分配的最小元素新數量。

描述

此函式會收縮/增長記憶體池。在增長的情況下,不能保證記憶體池會立即增長到新大小,但新的 mempool_free() 呼叫會重新填充它。此函式可能會休眠。

請注意,呼叫者必須保證在此函式執行時不會呼叫 mempool_destroy。在此函式執行期間,mempool_alloc() 和 mempool_free() 可能會被呼叫(例如,來自 IRQ 上下文)。

返回

成功返回 0,否則返回負錯誤碼。

void *mempool_alloc_preallocated(mempool_t *pool)

從屬於特定記憶體池的預分配元素中分配一個元素

引數

mempool_t *pool

指向透過 mempool_create() 分配的記憶體池的指標。

描述

此函式類似於 mempool_alloc,但它只嘗試從預分配的元素中分配一個元素。它不會休眠,如果沒有預分配的元素可用,則立即返回。

返回

指向已分配元素的指標,如果沒有元素可用則為 NULL

void mempool_free(void *element, mempool_t *pool)

將一個元素返回給池。

引數

void *element

池元素指標。

mempool_t *pool

指向透過 mempool_create() 分配的記憶體池的指標。

描述

此函式僅在 free_fn() 函式休眠時休眠。

DMA 池

struct dma_pool *dma_pool_create_node(const char *name, struct device *dev, size_t size, size_t align, size_t boundary, int node)

建立一個用於 DMA 的一致性記憶體塊池。

引數

const char *name

池的名稱,用於診斷

struct device *dev

將執行 DMA 的裝置

size_t size

此池中塊的大小。

size_t align

塊的對齊要求;必須是2的冪

size_t boundary

返回的塊不會跨越此2的冪邊界

int node

可選的 NUMA 節點,用於分配 `dma_pool` 和 `dma_page` 結構體

上下文

不在中斷上下文

描述

給定其中一個池,可以使用 dma_pool_alloc() 來分配記憶體。此類記憶體將全部具有“一致性” DMA 對映,裝置及其驅動程式無需使用快取重新整理原語即可訪問。由於對齊原因,實際分配的塊大小可能大於請求的大小。

如果 **boundary** 不為零,從 dma_pool_alloc() 返回的物件將不會跨越該大小邊界。這對於對單個 DMA 傳輸有定址限制的裝置很有用,例如不跨越 4KBytes 的邊界。

返回

具有請求特性的 DMA 分配池,如果無法建立則為 NULL

void dma_pool_destroy(struct dma_pool *pool)

銷燬 DMA 記憶體塊池。

引數

struct dma_pool *pool

將被銷燬的 DMA 池

上下文

不在中斷上下文

描述

呼叫者保證池中不再有記憶體正在使用,並且在此呼叫之後沒有任何東西會嘗試使用該池。

void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags, dma_addr_t *handle)

獲取一塊一致性記憶體

引數

struct dma_pool *pool

將產生該塊的 DMA 池

gfp_t mem_flags

GFP_* 位掩碼

dma_addr_t *handle

指向塊的 DMA 地址的指標

返回

當前未使用的塊的核心虛擬地址,並透過控制代碼報告其 DMA 地址。如果無法分配此類記憶體塊,則返回 NULL

void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma)

將塊放回 DMA 池

引數

struct dma_pool *pool

持有該塊的 DMA 池

void *vaddr

塊的虛擬地址

dma_addr_t dma

塊的 DMA 地址

描述

呼叫者承諾,除非此塊首先被重新分配,否則裝置和驅動程式都不會再觸碰此塊。

struct dma_pool *dmam_pool_create(const char *name, struct device *dev, size_t size, size_t align, size_t allocation)

受管理的 dma_pool_create()

引數

const char *name

池的名稱,用於診斷

struct device *dev

將執行 DMA 的裝置

size_t size

此池中塊的大小。

size_t align

塊的對齊要求;必須是2的冪

size_t allocation

返回的塊不會跨越此邊界(或零)

描述

受管理的 dma_pool_create()。使用此函式建立的 DMA 池會在驅動程式分離時自動銷燬。

返回

具有請求特性的受管理 DMA 分配池,如果無法建立則為 NULL

void dmam_pool_destroy(struct dma_pool *pool)

受管理的 dma_pool_destroy()

引數

struct dma_pool *pool

將被銷燬的 DMA 池

描述

受管理的 dma_pool_destroy()

更多記憶體管理函式

void zap_vma_ptes(struct vm_area_struct *vma, unsigned long address, unsigned long size)

移除對映 VMA 的 PTE

引數

struct vm_area_struct *vma

包含要清除的 PTE 的 vm_area_struct

unsigned long address

要清除的頁的起始地址

unsigned long size

要清除的位元組數

描述

此函式僅解除對映分配給 VM_PFNMAP VMA 的 PTE。

整個地址範圍必須完全包含在 VMA 中。

int vm_insert_pages(struct vm_area_struct *vma, unsigned long addr, struct page **pages, unsigned long *num)

將多個頁插入使用者 VMA,批次處理 PMD 鎖。

引數

struct vm_area_struct *vma

要對映到的使用者 VMA

unsigned long addr

這些頁的目標起始使用者地址

struct page **pages

源核心頁

unsigned long *num

輸入:要對映的頁數。輸出:*未*對映的頁數。(0 表示所有頁都成功對映)。

描述

在插入多個頁時,優先於 vm_insert_page()

如果發生錯誤,我們可能只映射了所提供頁的子集。呼叫者有責任處理這種情況。

適用與 vm_insert_page() 相同的限制。

int vm_insert_page(struct vm_area_struct *vma, unsigned long addr, struct page *page)

將單個頁插入使用者 VMA

引數

struct vm_area_struct *vma

要對映到的使用者 VMA

unsigned long addr

此頁的目標使用者地址

struct page *page

源核心頁

描述

這允許驅動程式將它們分配的單個頁插入使用者 VMA。某些 VMA 支援零頁,請參閱 vm_mixed_zeropage_allowed()。

該頁必須是一個乾淨的 _獨立_ 核心分配。如果你分配了一個複合頁,你需要將其標記為複合頁(__GFP_COMP),或者手動將其拆分(參見 split_page())。

注意!傳統上這是透過“remap_pfn_range()”完成的,該函式接受任意頁保護引數。此函式不允許這樣做。你的 VMA 保護必須正確設定,這意味著如果你想要一個共享可寫對映,最好請求一個共享可寫對映!

該頁不需要被保留。

通常,此函式在 mm->mmap_lock 寫鎖下從 f_op->mmap() 處理程式中呼叫,因此它可以更改 vma->vm_flags。如果呼叫者想從其他地方(例如頁錯誤處理程式)呼叫此函式,則必須在 VMA 上設定 VM_MIXEDMAP。

返回

成功返回 0,否則返回負錯誤碼。

int vm_map_pages(struct vm_area_struct *vma, struct page **pages, unsigned long num)

對映從非零偏移量開始的核心頁範圍

引數

struct vm_area_struct *vma

要對映到的使用者 VMA

struct page **pages

指向源核心頁陣列的指標

unsigned long num

頁陣列中的頁數

描述

對映一個由 **num** 個頁組成的物件,滿足使用者請求的 vm_pgoff

如果我們無法將任何頁插入 VMA,函式將立即返回,保留之前已插入的頁。來自 mmap 處理程式的呼叫者可以立即返回錯誤,因為它們的呼叫者會銷燬 VMA,從而移除任何成功插入的頁。其他呼叫者應自行安排呼叫 unmap_region()。

上下文

程序上下文。由 mmap 處理程式呼叫。

返回

成功時返回 0,否則返回錯誤程式碼。

int vm_map_pages_zero(struct vm_area_struct *vma, struct page **pages, unsigned long num)

對映從零偏移量開始的核心頁範圍

引數

struct vm_area_struct *vma

要對映到的使用者 VMA

struct page **pages

指向源核心頁陣列的指標

unsigned long num

頁陣列中的頁數

描述

類似於 vm_map_pages(),但它明確將偏移量設定為 0。此函式適用於未考慮 vm_pgoff 的驅動程式。

上下文

程序上下文。由 mmap 處理程式呼叫。

返回

成功時返回 0,否則返回錯誤程式碼。

vm_fault_t vmf_insert_pfn_prot(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn, pgprot_t pgprot)

將單個 PFN 插入使用者 VMA 並指定 pgprot

引數

struct vm_area_struct *vma

要對映到的使用者 VMA

unsigned long addr

此頁的目標使用者地址

unsigned long pfn

源核心 PFN

pgprot_t pgprot

插入頁的 pgprot 標誌

描述

這與 vmf_insert_pfn() 完全相同,只是它允許驅動程式按每頁覆蓋 pgprot。

這僅對 I/O 對映有意義,對 COW 對映則無意義。通常,使用多個 VMA 更好;vmf_insert_pfn_prot 應該只在無法使用多個 VMA 的情況下使用。

pgprot 通常僅在驅動程式設定的快取和加密位與 **vma->vm_page_prot** 不同時才與 **vma->vm_page_prot** 不同,因為快取或加密模式在 mmap() 時可能未知。

只要核心 VM 不使用 **vma->vm_page_prot** 來設定這些 VMA 的快取和加密位(除了 COW 頁),這都是可以的。核心 VM 僅使用不觸及快取或加密位的函式(如果需要則使用 pte_modify())來修改這些頁表項,從而確保這一點。(例如參見 mprotect())。

此外,當建立新的頁表項時,這僅透過 fault() 回撥完成,從不使用 vma->vm_page_prot 的值,除了由於 COW 而指向匿名頁的頁表項。

上下文

程序上下文。可以使用 GFP_KERNEL 分配。

返回

vm_fault_t 值。

vm_fault_t vmf_insert_pfn(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn)

將單個 PFN 插入使用者 VMA

引數

struct vm_area_struct *vma

要對映到的使用者 VMA

unsigned long addr

此頁的目標使用者地址

unsigned long pfn

源核心 PFN

描述

類似於 vm_insert_page,這允許驅動程式將它們分配的單個頁插入使用者 VMA。同樣的註釋適用。

此函式只能從 vm_ops->fault 處理程式中呼叫,在這種情況下,處理程式應返回此函式的結果。

VMA 不能是 COW 對映。

由於此函式僅針對當前不存在的頁呼叫,因此我們不需要重新整理舊的虛擬快取或 TLB。

上下文

程序上下文。可以使用 GFP_KERNEL 分配。

返回

vm_fault_t 值。

int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn, unsigned long size, pgprot_t prot)

將核心記憶體重新對映到使用者空間

引數

struct vm_area_struct *vma

要對映到的使用者 VMA

unsigned long addr

目標頁對齊的使用者地址起始點

unsigned long pfn

核心物理記憶體地址的頁幀號

unsigned long size

對映區域的大小

pgprot_t prot

此對映的頁保護標誌

注意

僅在呼叫時持有 MM 訊號量才安全。

返回

成功返回 0,否則返回負錯誤碼。

int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long len)

將記憶體重新對映到使用者空間

引數

struct vm_area_struct *vma

要對映到的使用者 VMA

phys_addr_t start

要對映的物理記憶體的起始地址

unsigned long len

區域大小

描述

這是 io_remap_pfn_range() 的簡化版本,供常見驅動程式使用。驅動程式只需提供要對映的物理記憶體範圍,我們將根據 VMA 資訊推斷出其餘部分。

注意!某些驅動程式可能希望首先調整 vma->vm_page_prot,以獲取寫入合併的詳細資訊或類似內容。

返回

成功返回 0,否則返回負錯誤碼。

void unmap_mapping_pages(struct address_space *mapping, pgoff_t start, pgoff_t nr, bool even_cows)

從程序中解除頁對映。

引數

struct address_space *mapping

包含要解除對映的頁的地址空間。

pgoff_t start

要解除對映的第一個頁的索引。

pgoff_t nr

要解除對映的頁數。如果為 0,則解除對映到檔案末尾。

bool even_cows

是否解除對映甚至私有的 COW(寫時複製)頁。

描述

從任何已將這些頁對映到使用者空間的程序中解除此地址空間中的頁對映。通常,在截斷檔案時,您也希望移除 COW 頁,但在使頁快取中的頁無效時則不希望。

void unmap_mapping_range(struct address_space *mapping, loff_t const holebegin, loff_t const holelen, int even_cows)

解除指定 address_space 中所有 mmap 對映中對應於底層檔案中指定位元組範圍的部分。

引數

struct address_space *mapping

包含要解除對映的 mmap 的地址空間。

loff_t const holebegin

要解除對映的第一個頁中的位元組,相對於底層檔案的起始。這將向下舍入到 PAGE_SIZE 邊界。請注意,這與 truncate_pagecache() 不同,後者必須保留部分頁。相比之下,我們必須清除部分頁。

loff_t const holelen

預期空洞的位元組大小。這將向上舍入到 PAGE_SIZE 邊界。holelen 為零表示截斷到檔案末尾。

int even_cows

截斷檔案時為 1,解除對映甚至私有 COW 頁;但使頁快取無效時為 0,不丟棄私有資料。

int follow_pfnmap_start(struct follow_pfnmap_args *args)

在使用者虛擬地址處查詢 PFN 對映

引數

struct follow_pfnmap_args *args

指向結構體 **follow_pfnmap_args** 的指標

描述

呼叫者需要設定 args->vma 和 args->address 指向作為查詢目標的虛擬地址。成功返回時,結果將放入其他輸出欄位。

呼叫者在使用完這些欄位後,必須呼叫 follow_pfnmap_end() 來正確釋放此類查詢請求的鎖和資源。

start() 和 end() 呼叫期間,**args** 中的結果將有效,因為會持有適當的鎖。在呼叫 end() 後,**follow_pfnmap_args** 中的所有欄位將無效,無法進一步訪問。在 end() 呼叫後進一步使用此類資訊可能需要呼叫者與頁表更新進行適當的同步,否則可能會產生安全漏洞。

如果 PTE 映射了一個帶引用計數的頁,呼叫者有責任使用 MMU 通知器來防止失效;否則,稍後訪問 PFN 可能會觸發使用後釋放(use-after-free)。

只允許 I/O 對映和原始 PFN 對映。mmap 訊號量應以讀模式持有,並且在呼叫 end() 之前不能釋放 mmap 訊號量。

此函式不得用於修改 PTE 內容。

返回

成功時返回零,否則返回負值。

void follow_pfnmap_end(struct follow_pfnmap_args *args)

結束一個 follow_pfnmap_start() 程序

引數

struct follow_pfnmap_args *args

指向結構體 **follow_pfnmap_args** 的指標

描述

必須與 follow_pfnmap_start() 配對使用。有關更多資訊,請參見上面的 start() 函式。

int generic_access_phys(struct vm_area_struct *vma, unsigned long addr, void *buf, int len, int write)

iomem mmap 訪問的通用實現

引數

struct vm_area_struct *vma

要訪問的 VMA

unsigned long addr

使用者空間地址,不是 **vma** 內的相對偏移量

void *buf

要讀/寫的緩衝區

int len

傳輸長度

int write

寫入時設定為 FOLL_WRITE,否則為讀取

描述

這是 iomem 對映的 vm_operations_struct.access 的通用實現。當 **vma** 不是基於頁時,access_process_vm() 使用此回撥。

int copy_remote_vm_str(struct task_struct *tsk, unsigned long addr, void *buf, int len, unsigned int gup_flags)

從另一個程序的地址空間複製字串。

引數

struct task_struct *tsk

目標地址空間的任務

unsigned long addr

要讀取的起始地址

void *buf

目標緩衝區

int len

要複製的位元組數

unsigned int gup_flags

修改查詢行為的標誌

描述

呼叫者必須持有 **mm** 的引用。

返回

從 **addr**(源)複製到 **buf**(目標)的位元組數;不包括末尾的 NUL。始終保證留下以 NUL 結尾的緩衝區。發生任何錯誤時,返回 -EFAULT。

unsigned long get_pfnblock_flags_mask(const struct page *page, unsigned long pfn, unsigned long mask)

返回 pageblock_nr_pages 塊頁的請求標誌組

引數

const struct page *page

感興趣塊內的頁

unsigned long pfn

目標頁幀號

unsigned long mask

呼叫者感興趣的位掩碼

返回

pageblock_bits 標誌

void set_pfnblock_flags_mask(struct page *page, unsigned long flags, unsigned long pfn, unsigned long mask)

設定 pageblock_nr_pages 頁塊的請求標誌組

引數

struct page *page

感興趣塊內的頁

unsigned long flags

要設定的標誌

unsigned long pfn

目標頁幀號

unsigned long mask

呼叫者感興趣的位掩碼

bool move_freepages_block_isolate(struct zone *zone, struct page *page, int migratetype)

移動塊中的空閒頁以進行頁隔離

引數

struct zone *zone

區域

struct page *page

頁塊頁

int migratetype

要在頁塊上設定的遷移型別

描述

這類似於 move_freepages_block(),但處理了頁隔離中遇到的特殊情況,即感興趣的塊可能是跨多個頁塊的更大 buddy 的一部分。

與常規頁分配器路徑(在從空閒列表竊取 buddy 時移動頁)不同,頁隔離關注的是兩端可能有重疊 buddy 的任意 PFN 範圍。

此函式處理了這種情況。跨越的 buddy 會被拆分成單獨的頁塊。只移動感興趣的塊。

如果頁可以移動,返回 true,否則返回 false

void __putback_isolated_page(struct page *page, unsigned int order, int mt)

將已隔離的頁返回到其來源處

引數

struct page *page

被隔離的頁

unsigned int order

隔離頁的階

int mt

頁的頁塊的遷移型別

描述

此函式旨在將透過 __isolate_free_page 從空閒列表取出的頁返回到它們被取出的空閒列表。

void ___free_pages(struct page *page, unsigned int order, fpi_t fpi_flags)

釋放使用 alloc_pages() 分配的頁。

引數

struct page *page

alloc_pages() 返回的頁指標。

unsigned int order

分配的階。

fpi_t fpi_flags

空閒頁內部標誌。

描述

此函式可以釋放非複合頁的多頁分配。它不檢查傳入的 **order** 是否與分配的階匹配,因此很容易導致記憶體洩漏。釋放比分配更多的記憶體可能會發出警告。

如果此頁的最後一個引用是推測性的,它將由 put_page() 釋放,put_page() 只釋放非複合分配的第一個頁。為了防止剩餘的頁洩漏,我們在此處釋放後續的頁。如果您想使用頁的引用計數來決定何時釋放分配,您應該分配一個複合頁,並使用 put_page() 而不是 __free_pages()。

上下文

可以在中斷上下文或持有普通自旋鎖時呼叫,但不能在 NMI 上下文或持有原始自旋鎖時呼叫。

void *alloc_pages_exact(size_t size, gfp_t gfp_mask)

分配精確數量的物理連續頁。

引數

size_t size

要分配的位元組數

gfp_t gfp_mask

分配的 GFP 標誌,不得包含 __GFP_COMP

描述

此函式類似於 alloc_pages(),不同之處在於它分配滿足請求所需的最小頁數。alloc_pages() 只能以2的冪頁數分配記憶體。

此函式也受 MAX_PAGE_ORDER 的限制。

此函式分配的記憶體必須透過 free_pages_exact() 釋放。

返回

指向已分配區域的指標,如果出錯則為 NULL

void *alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask)

在一個節點上分配精確數量的物理連續頁。

引數

int nid

記憶體應分配到的首選節點 ID

size_t size

要分配的位元組數

gfp_t gfp_mask

分配的 GFP 標誌,不得包含 __GFP_COMP

描述

類似於 alloc_pages_exact(),但會首先嚐試在節點 nid 上分配,然後才回退。

返回

指向已分配區域的指標,如果出錯則為 NULL

void *free_pages_exact(void *virt, size_t size)

釋放透過 alloc_pages_exact() 分配的記憶體

引數

void *virt

alloc_pages_exact 返回的值。

size_t size

分配大小,與傳遞給 alloc_pages_exact() 的值相同。

描述

釋放先前呼叫 alloc_pages_exact 所分配的記憶體。

unsigned long nr_free_zone_pages(int offset)

計算超出高水位線的頁數

引數

int offset

最高區域的區域索引

描述

nr_free_zone_pages() 計算在給定區域索引處或以下的所有區域中,超出高水位線的頁數。對於每個區域,頁數計算為

nr_free_zone_pages = managed_pages - high_pages

返回

超出高水位線的頁數。

unsigned long nr_free_buffer_pages(void)

計算超出高水位線的頁數

引數

void

無引數

描述

nr_free_buffer_pages() 計算 ZONE_DMA 和 ZONE_NORMAL 中超出高水位線的頁數。

返回

ZONE_DMA 和 ZONE_NORMAL 中超出高水位線的頁數。

int find_next_best_node(int node, nodemask_t *used_node_mask)

找到應該出現在給定節點的後備列表中的下一個節點

引數

int node

我們正在追加其後備列表的節點

nodemask_t *used_node_mask

已使用節點的 nodemask_t

描述

我們使用多種因素來確定哪個是應該出現在給定節點的後備列表中的下一個節點。該節點不應已出現在 **node** 的後備列表中,並且根據距離陣列(其中包含從系統中每個節點到每個節點的任意距離值),它應該是下一個最近的節點,並且還應優先選擇沒有 CPU 的節點,因為它們通常否則分配壓力很小。

返回

找到的節點 ID,如果未找到節點則為 NUMA_NO_NODE

void setup_per_zone_wmarks(void)

當 min_free_kbytes 改變或記憶體熱插拔(新增/移除)時呼叫

引數

void

無引數

描述

確保每個區域的水位線[min,low,high]值相對於 min_free_kbytes 正確設定。

int alloc_contig_range(unsigned long start, unsigned long end, unsigned migratetype, gfp_t gfp_mask)
  • 嘗試分配給定範圍的頁

引數

unsigned long start

要分配的起始 PFN

unsigned long end

待分配的超出最後一個 PFN 的 PFN

unsigned migratetype

底層頁塊的遷移型別(可以是 #MIGRATE_MOVABLE 或 #MIGRATE_CMA)。範圍內所有頁塊必須具有相同的遷移型別,並且必須是這兩種型別中的一種。

gfp_t gfp_mask

GFP掩碼。節點/區域/放置提示被忽略;只支援部分動作和回收修飾符。回收修飾符控制緊縮/遷移/回收期間的分配行為。

描述

PFN範圍不必頁塊對齊。PFN範圍必須屬於單個區域。

此例程做的第一件事是嘗試MIGRATE_ISOLATE該範圍內的所有頁塊。一旦隔離,頁塊不應被其他方修改。

返回

成功時返回零,否則返回負錯誤碼。成功時,PFN在[start, end)範圍內的所有頁都為呼叫者分配,並需要使用free_contig_range()釋放。

struct page *alloc_contig_pages(unsigned long nr_pages, gfp_t gfp_mask, int nid, nodemask_t *nodemask)
  • 嘗試查詢和分配連續的頁範圍

引數

unsigned long nr_pages

要分配的連續頁數

gfp_t gfp_mask

GFP掩碼。節點/區域/放置提示限制搜尋;只支援部分動作和回收修飾符。回收修飾符控制緊縮/遷移/回收期間的分配行為。

int nid

目標節點

nodemask_t *nodemask

其他可能節點的掩碼

描述

此例程是alloc_contig_range()的包裝器。它掃描適用區域列表中的區域,以查詢連續的PFN範圍,然後可以使用alloc_contig_range()嘗試分配。此例程旨在處理buddy分配器無法滿足的分配請求。

分配的記憶體始終與頁邊界對齊。如果nr_pages是2的冪,則分配的範圍也保證與相同的nr_pages對齊(例如,1GB請求將與1GB對齊)。

已分配的頁可以使用free_contig_range()釋放,或手動對每個已分配的頁呼叫__free_page()。

返回

成功時返回指向連續頁的指標,否則返回NULL。

struct page *alloc_pages_nolock(int nid, unsigned int order)

任何上下文中的機會性重入分配

引數

int nid

要從中分配的節點

unsigned int order

分配階大小

描述

從給定節點分配給定階的頁。此函式在任何上下文(原子上下文、NMI,以及重入分配器 -> 跟蹤點 -> alloc_pages_nolock_noprof)中呼叫都是安全的。分配是盡力而為的,並且很容易失敗,因此不應依賴於其成功。失敗不會透過warn_alloc()報告。請參見下面的“總是失敗條件”。

返回

成功時返回分配的頁,失敗時返回NULL。NULL不表示EBUSY或EAGAIN。它表示ENOMEM。沒有理由再次呼叫它並期望非NULL。

int numa_nearest_node(int node, unsigned int state)

按狀態查詢最近的節點

引數

int node

開始搜尋的節點ID

unsigned int state

過濾搜尋的狀態

描述

如果nid不在狀態中,則按距離查詢最近的節點。

返回

如果此node處於指定狀態,則返回此node;否則,返回距離最近的節點。

int nearest_node_nodemask(int node, nodemask_t *mask)

mask中查詢距離node最近的節點。

引數

int node

一個有效的節點ID,用於開始搜尋。

nodemask_t *mask

指向表示允許節點的節點掩碼的指標。

描述

此函式遍歷mask中的所有節點,並計算與起始node的距離,然後返回最接近node的節點ID,如果未找到節點則返回MAX_NUMNODES。

請注意,node必須是可與node_distance()一起使用的有效節點ID,提供無效節點ID(例如NUMA_NO_NODE)可能導致崩潰或意外行為。

struct page *alloc_pages_mpol(gfp_t gfp, unsigned int order, struct mempolicy *pol, pgoff_t ilx, int nid)

根據NUMA記憶體策略分配頁。

引數

gfp_t gfp

GFP標誌。

unsigned int order

頁分配的階。

struct mempolicy *pol

指向NUMA記憶體策略的指標。

pgoff_t ilx

交錯記憶體策略的索引(也區分alloc_pages())。

int nid

首選節點(通常是numa_node_id(),但mpol可能覆蓋它)。

返回

成功時返回頁,如果分配失敗則返回NULL。

struct folio *vma_alloc_folio(gfp_t gfp, int order, struct vm_area_struct *vma, unsigned long addr)

為VMA分配一個folio。

引數

gfp_t gfp

GFP標誌。

int order

folio的階。

struct vm_area_struct *vma

指向VMA的指標。

unsigned long addr

分配的虛擬地址。必須在vma內部。

描述

vma中特定地址分配一個folio,使用適當的NUMA策略。呼叫者必須持有VMA的mm_struct的mmap_lock,以防止它消失。應將其用於將對映到使用者空間的所有folio分配,hugetlbfs除外,以及直接使用folio_alloc_mpol()更合適的情況除外。

返回

成功時返回folio,如果分配失敗則返回NULL。

struct page *alloc_pages(gfp_t gfp, unsigned int order)

分配頁。

引數

gfp_t gfp

GFP標誌。

unsigned int order

要分配的頁數的2的冪。

描述

分配1 << order個連續頁。第一個頁的物理地址是自然對齊的(例如,3階分配將對齊到8 * PAGE_SIZE位元組的倍數)。在程序上下文中,將遵循當前程序的NUMA策略。

上下文

只要使用適當的GFP標誌,就可以從任何上下文呼叫。

返回

成功時返回頁,如果分配失敗則返回NULL。

int mpol_misplaced(struct folio *folio, struct vm_fault *vmf, unsigned long addr)

檢查當前folio節點在策略中是否有效

引數

struct folio *folio

要檢查的folio

struct vm_fault *vmf

描述錯誤的結構體

unsigned long addr

用於共享策略查詢和交錯策略的vma中的虛擬地址

描述

查詢vma,addr的當前策略節點ID,並與folio的節點ID“比較”。策略確定“模仿”alloc_page_vma()。從我們知道vma和錯誤地址的錯誤路徑中呼叫。

返回

如果頁位於對該策略有效的節點中,則返回NUMA_NO_NODE;否則,返回可用於分配替代folio的合適節點ID。

void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol)

初始化inode的共享策略

引數

struct shared_policy *sp

指向inode共享策略的指標

struct mempolicy *mpol

要安裝的struct mempolicy

描述

在inode的共享策略rb-tree中安裝非NULL的mpol。進入時,當前任務對非NULL的mpol具有引用。退出時必須釋放此引用。這在get_inode()呼叫時呼叫,我們可以使用GFP_KERNEL。

int mpol_parse_str(char *str, struct mempolicy **mpol)

解析字串到記憶體策略,用於tmpfs mpol掛載選項。

引數

char *str

包含要解析的記憶體策略的字串

struct mempolicy **mpol

指向struct mempolicy指標的指標,成功時返回。

描述

輸入格式

<mode>[=<flags>][:<nodelist>]

返回

成功時返回0,否則返回1

void mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)

格式化記憶體策略結構體以供列印

引數

char *buffer

用於存放格式化後的記憶體策略字串

int maxlen

buffer的長度

struct mempolicy *pol

指向要格式化的記憶體策略的指標

描述

pol轉換為字串。如果buffer太短,則截斷字串。建議maxlen至少為51,以便容納最長的模式“weighted interleave”加上最長的標誌“relative|balancing”,並顯示至少幾個節點ID。

struct folio

表示一組連續的位元組。

定義:

struct folio {
    unsigned long flags;
    union {
        struct list_head lru;
        unsigned int mlock_count;
        struct dev_pagemap *pgmap;
    };
    struct address_space *mapping;
    union {
        pgoff_t index;
        unsigned long share;
    };
    union {
        void *private;
        swp_entry_t swap;
    };
    atomic_t _mapcount;
    atomic_t _refcount;
#ifdef CONFIG_MEMCG;
    unsigned long memcg_data;
#elif defined(CONFIG_SLAB_OBJ_EXT);
    unsigned long _unused_slab_obj_exts;
#endif;
#if defined(WANT_PAGE_VIRTUAL);
    void *virtual;
#endif;
#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS;
    int _last_cpupid;
#endif;
    atomic_t _large_mapcount;
    atomic_t _nr_pages_mapped;
#ifdef CONFIG_64BIT;
    atomic_t _entire_mapcount;
    atomic_t _pincount;
#endif ;
    mm_id_mapcount_t _mm_id_mapcount[2];
    union {
        mm_id_t _mm_id[2];
        unsigned long _mm_ids;
    };
#ifdef NR_PAGES_IN_LARGE_FOLIO;
    unsigned int _nr_pages;
#endif ;
    struct list_head _deferred_list;
#ifndef CONFIG_64BIT;
    atomic_t _entire_mapcount;
    atomic_t _pincount;
#endif ;
    void *_hugetlb_subpool;
    void *_hugetlb_cgroup;
    void *_hugetlb_cgroup_rsvd;
    void *_hugetlb_hwpoison;
};

成員

flags

與頁標誌相同。

{匿名聯合體}

匿名

lru

最近最少使用列表;跟蹤此folio最近的使用情況。

mlock_count

此folio被mlock()鎖定的次數。

pgmap

ZONE_DEVICE對映的元資料

對映

此頁所屬的檔案,或指向匿名記憶體的anon_vma。

{匿名聯合體}

匿名

index

檔案內的偏移量,以頁為單位。對於匿名記憶體,這是mmap起始處的索引。

share

引用此folio的DAX對映數量。參見dax_associate_entry。

{匿名聯合體}

匿名

private

檔案系統每folio資料(參見folio_attach_private())。

swap

如果folio_test_swapcache(),則用於swp_entry_t。

_mapcount

不要直接訪問此成員。使用folio_mapcount()來查詢此folio被使用者空間對映的次數。

_refcount

不要直接訪問此成員。使用folio_ref_count()來查詢此folio的引用數量。

memcg_data

記憶體控制組資料。

_unused_slab_obj_exts

用於匹配struct slab中obj_exts的佔位符。

virtual

核心直接對映中的虛擬地址。

_last_cpupid

最後訪問此folio的CPU和程序ID。

_large_mapcount

不要直接使用,請呼叫folio_mapcount()

_nr_pages_mapped

不要在rmap和除錯程式碼之外使用。

_entire_mapcount

不要直接使用,請呼叫folio_entire_mapcount()。

_pincount

不要直接使用,請呼叫folio_maybe_dma_pinned()

_mm_id_mapcount

不要在rmap程式碼之外使用。

{匿名聯合體}

匿名

_mm_id

不要在rmap程式碼之外使用。

_mm_ids

不要在rmap程式碼之外使用。

_nr_pages

不要直接使用,請呼叫folio_nr_pages()

_deferred_list

記憶體壓力下待拆分的folios。

_entire_mapcount

不要直接使用,請呼叫folio_entire_mapcount()。

_pincount

不要直接使用,請呼叫folio_maybe_dma_pinned()

_hugetlb_subpool

不要直接使用,請使用hugetlb.h中的訪問器。

_hugetlb_cgroup

不要直接使用,請使用hugetlb_cgroup.h中的訪問器。

_hugetlb_cgroup_rsvd

不要直接使用,請使用hugetlb_cgroup.h中的訪問器。

_hugetlb_hwpoison

不要直接使用,請呼叫raw_hwp_list_head()。

描述

Folio是物理上、虛擬上和邏輯上連續的位元組集。它的大小是2的冪,並且與相同的2的冪對齊。它至少與PAGE_SIZE一樣大。如果它在頁快取中,則其檔案偏移量是2的冪的倍數。它可能以任意頁偏移量對映到使用者空間,但其核心虛擬地址與其大小對齊。

struct ptdesc

頁表的記憶體描述符。

定義:

struct ptdesc {
    unsigned long __page_flags;
    union {
        struct rcu_head pt_rcu_head;
        struct list_head pt_list;
        struct {
            unsigned long _pt_pad_1;
            pgtable_t pmd_huge_pte;
        };
    };
    unsigned long __page_mapping;
    union {
        pgoff_t pt_index;
        struct mm_struct *pt_mm;
        atomic_t pt_frag_refcount;
#ifdef CONFIG_HUGETLB_PMD_PAGE_TABLE_SHARING;
        atomic_t pt_share_count;
#endif;
    };
    union {
        unsigned long _pt_pad_2;
#if ALLOC_SPLIT_PTLOCKS;
        spinlock_t *ptl;
#else;
        spinlock_t ptl;
#endif;
    };
    unsigned int __page_type;
    atomic_t __page_refcount;
#ifdef CONFIG_MEMCG;
    unsigned long pt_memcg_data;
#endif;
};

成員

__page_flags

與頁標誌相同。僅限PowerPC。

{匿名聯合體}

匿名

pt_rcu_head

用於釋放頁表頁。

pt_list

已使用頁表的列表。用於s390 gmap影子頁(未連結到使用者頁表)和x86 pgds。

{匿名結構體}

匿名

_pt_pad_1

與頁的複合頭別名的填充。

pmd_huge_pte

受ptdesc->ptl保護,用於THPs。

__page_mapping

與page->mapping別名。未用於頁表。

{匿名聯合體}

匿名

pt_index

用於s390 gmap。

pt_mm

用於x86 pgds。

pt_frag_refcount

用於碎片化頁表跟蹤。僅限PowerPC。

pt_share_count

用於HugeTLB PMD頁表共享計數。

{匿名聯合體}

匿名

_pt_pad_2

確保正確對齊的填充。

ptl

頁表的鎖。

ptl

頁表的鎖。

__page_type

與page->page_type相同。未用於頁表。

__page_refcount

與頁引用計數相同。

pt_memcg_data

Memcg資料。在此跟蹤頁表。

描述

此結構體目前覆蓋了struct page。在不充分理解問題的情況下,請勿修改。

type vm_fault_t

頁錯誤處理程式的返回型別。

描述

頁錯誤處理程式返回VM_FAULT值的位掩碼。

enum vm_fault_reason

頁錯誤處理程式返回這些值的位掩碼,以告知核心VM在處理錯誤時發生了什麼。用於決定程序是否收到SIGBUS或僅增加主要/次要錯誤計數器。

常量

VM_FAULT_OOM

記憶體不足

VM_FAULT_SIGBUS

錯誤訪問

VM_FAULT_MAJOR

頁從儲存中讀取

VM_FAULT_HWPOISON

遇到被汙染的小頁

VM_FAULT_HWPOISON_LARGE

遇到被汙染的大頁。索引編碼在高位

VM_FAULT_SIGSEGV

段錯誤

VM_FAULT_NOPAGE

->fault安裝了PTE,未返回頁

VM_FAULT_LOCKED

->fault鎖定了返回的頁

VM_FAULT_RETRY

->fault被阻塞,必須重試

VM_FAULT_FALLBACK

大頁錯誤失敗,回退到小頁

VM_FAULT_DONE_COW

->fault已完全處理COW

VM_FAULT_NEEDDSYNC

->fault未修改頁表,需要fsync()完成(用於DAX中的同步頁錯誤)

VM_FAULT_COMPLETED

->fault完成,同時mmap鎖已釋放

VM_FAULT_HINDEX_MASK

掩碼HINDEX值

enum fault_flag

錯誤標誌定義。

常量

FAULT_FLAG_WRITE

錯誤是寫錯誤。

FAULT_FLAG_MKWRITE

錯誤是對現有PTE的mkwrite操作。

FAULT_FLAG_ALLOW_RETRY

如果被阻塞,允許重試錯誤。

FAULT_FLAG_RETRY_NOWAIT

重試時不要釋放mmap_lock並等待。

FAULT_FLAG_KILLABLE

錯誤任務處於SIGKILL可終止區域。

FAULT_FLAG_TRIED

錯誤已嘗試過一次。

FAULT_FLAG_USER

錯誤源於使用者空間。

FAULT_FLAG_REMOTE

錯誤不針對當前任務/mm。

FAULT_FLAG_INSTRUCTION

錯誤發生在指令獲取期間。

FAULT_FLAG_INTERRUPTIBLE

錯誤可被非致命訊號中斷。

FAULT_FLAG_UNSHARE

錯誤是一個取消共享請求,用於在COW對映中打破COW,確保錯誤後對映一個專用的匿名頁。

FAULT_FLAG_ORIG_PTE_VALID

錯誤是否快取了vmf->orig_pte。只有當此標誌設定時,我們才應訪問orig_pte。

FAULT_FLAG_VMA_LOCK

錯誤在VMA鎖下處理。

描述

關於FAULT_FLAG_ALLOW_RETRYFAULT_FLAG_TRIED:我們可以透過正確設定這兩個錯誤標誌來指定是否允許頁錯誤重試。目前有三種合法組合:

  1. ALLOW_RETRY和!TRIED:這表示頁錯誤允許重試,並且

    這是第一次嘗試

  2. ALLOW_RETRY和TRIED:這表示頁錯誤允許重試,並且

    我們已至少嘗試過一次

  3. !ALLOW_RETRY和!TRIED:這表示頁錯誤不允許重試

未列出的組合(!ALLOW_RETRY && TRIED)是非法的,不應使用。請注意,頁錯誤可以被允許重試多次,在這種情況下,我們將有一個帶標誌(a)的初始錯誤,然後是帶標誌(b)的連續錯誤。我們應始終在重試前嘗試檢測待處理訊號,以確保必要時連續頁錯誤仍可被中斷。

組合FAULT_FLAG_WRITE|FAULT_FLAG_UNSHARE是非法的。當應用於非COW對映時,FAULT_FLAG_UNSHARE將被忽略並被視為普通的讀錯誤。

int folio_is_file_lru(const struct folio *folio)

此folio應該在檔案LRU還是匿名LRU上?

引數

struct folio *folio

要測試的folio。

描述

我們希望在沒有頁標誌的情況下獲取此資訊,但狀態需要一直持續到folio最後從LRU中刪除,這可能遠至__page_cache_release。

返回

一個整數(不是布林值!),用於將folio排序到正確的LRU列表並正確統計folios。如果folio是常規檔案系統支援的頁快取folio或延遲釋放的匿名folio(例如透過MADV_FREE),則為1。如果folio是普通匿名folio、tmpfs folio或其他RAM或交換支援的folio,則為0。

void __folio_clear_lru_flags(struct folio *folio)

在釋放頁之前清除頁LRU標誌。

引數

struct folio *folio

已在LRU上且現在引用計數為零的folio。

enum lru_list folio_lru_list(struct folio *folio)

folio應該在哪個LRU列表上?

引數

struct folio *folio

要測試的folio。

返回

folio應該所在的LRU列表,作為LRU列表陣列的索引。

page_folio

page_folio (p)

將頁轉換為folio。

引數

p

該頁。

描述

每個頁都是一個folio的一部分。此函式不能在NULL指標上呼叫。

上下文

page不需要引用或鎖。如果呼叫者未持有引用,此呼叫可能與folio拆分發生競爭,因此在獲得folio的引用後,應重新檢查folio是否仍包含此頁。

返回

包含此頁的folio。

folio_page

folio_page (folio, n)

從folio返回一個頁。

引數

folio

該 folio。

n

要返回的頁號。

描述

n是相對於folio起始位置的。此函式不檢查頁號是否在folio內;假定呼叫者持有該頁的引用。

bool folio_xor_flags_has_waiters(struct folio *folio, unsigned long mask)

更改一些folio標誌。

引數

struct folio *folio

該 folio。

unsigned long mask

此字中設定的位將被更改。

描述

這隻能用於在持有folio鎖時更改的標誌。例如,它不能安全地用於PG_dirty,因為PG_dirty可以在不持有folio鎖的情況下設定。它也只能用於0-6範圍內的標誌,因為某些實現隻影響這些位。

返回

是否有任務在等待此folio。

bool folio_test_uptodate(const struct folio *folio)

此folio是否最新?

引數

const struct folio *folio

該 folio。

描述

當folio中的每個位元組都至少與儲存中對應的位元組一樣新時,folio上的uptodate標誌被設定。匿名和CoW folio始終是最新狀態。如果folio不是最新狀態,其中的一些位元組可能仍是最新狀態;請參見is_partially_uptodate() address_space操作。

bool folio_test_large(const struct folio *folio)

此folio是否包含多個頁?

引數

const struct folio *folio

要測試的folio。

返回

如果folio大於一個頁,則為True。

bool PageSlab(const struct page *page)

確定頁是否屬於slab分配器

引數

const struct page *page

要測試的頁。

上下文

任何上下文。

返回

對於slab頁為True,對於其他任何型別的頁為False。

bool PageHuge(const struct page *page)

確定頁是否屬於hugetlbfs

引數

const struct page *page

要測試的頁。

上下文

任何上下文。

返回

對於hugetlbfs頁為True,對於匿名頁或屬於其他檔案系統的頁為False。

int folio_has_private(const struct folio *folio)

確定folio是否有私有資料

引數

const struct folio *folio

要檢查的folio

描述

確定folio是否有私有資料,表示應在其上呼叫釋放例程。

bool fault_flag_allow_retry_first(enum fault_flag flags)

第一次檢查ALLOW_RETRY

引數

enum fault_flag flags

錯誤標誌。

描述

這主要用於我們希望在等待另一個條件改變時儘量避免長時間持有mmap_lock的地方,在這種情況下,我們可以在第一輪中禮貌地釋放mmap_lock,以避免其他程序可能出現的飢餓問題,這些程序也可能需要mmap_lock。

返回

如果頁錯誤允許重試且這是錯誤處理的第一次嘗試,則為true;否則為false。

unsigned int folio_order(const struct folio *folio)

folio的分配階。

引數

const struct folio *folio

該 folio。

描述

一個folio由2^order個頁組成。有關order的定義,請參見get_order()。

返回

folio的階。

void folio_reset_order(struct folio *folio)

重置folio的階和派生的_nr_pages

引數

struct folio *folio

該 folio。

描述

將階和派生的_nr_pages重置為0。只能在拆分大型folios的過程中使用。

int folio_mapcount(const struct folio *folio)

此folio的對映數量。

引數

const struct folio *folio

該 folio。

描述

folio對映計數對應於引用folio任何部分的現有使用者頁表條目數量。每個此類現有使用者頁表條目必須與一個folio引用精確配對。

對於普通folios,每個使用者頁表條目(PTE/PMD/PUD/...)只計數一次。

對於hugetlb folios,每個引用整個folio的抽象“hugetlb”使用者頁表條目只計數一次,即使這些特殊頁表條目由多個普通頁表條目組成。

對於無法對映到使用者空間的頁,如slab、頁表等,將報告0。

返回

此folio被對映的次數。

bool folio_mapped(const struct folio *folio)

此folio是否對映到使用者空間?

引數

const struct folio *folio

該 folio。

返回

如果此folio中的任何頁被使用者頁表引用,則為True。

unsigned int thp_order(struct page *page)

透明大頁的階。

引數

struct page *page

透明大頁的頭頁。

unsigned long thp_size(struct page *page)

透明大頁的大小。

引數

struct page *page

透明大頁的頭頁。

返回

此頁中的位元組數。

void folio_get(struct folio *folio)

增加folio的引用計數。

引數

struct folio *folio

該 folio。

上下文

只要您知道自己持有folio的引用計數,就可以在任何上下文呼叫此函式。如果您尚未持有引用,folio_try_get()可能是適合您使用的介面。

void folio_put(struct folio *folio)

減少folio的引用計數。

引數

struct folio *folio

該 folio。

描述

如果folio的引用計數達到零,記憶體將被釋放回頁分配器,並可能立即被另一個分配使用。在呼叫folio_put()之後,請勿訪問記憶體或struct folio,除非您能確定它不是最後一個引用。

上下文

可以在程序或中斷上下文中呼叫,但不能在NMI上下文中呼叫。可以在持有自旋鎖時呼叫。

void folio_put_refs(struct folio *folio, int refs)

減少folio的引用計數。

引數

struct folio *folio

該 folio。

int refs

從folio引用計數中減去的量。

描述

如果folio的引用計數達到零,記憶體將被釋放回頁分配器,並可能立即被另一個分配使用。在呼叫folio_put_refs()之後,請勿訪問記憶體或struct folio,除非您能確定這些不是最後一個引用。

上下文

可以在程序或中斷上下文中呼叫,但不能在NMI上下文中呼叫。可以在持有自旋鎖時呼叫。

void folios_put(struct folio_batch *folios)

減少一組folios的引用計數。

引數

struct folio_batch *folios

folios。

描述

類似於folio_put(),但適用於一組folios。這比您自己編寫迴圈更高效,因為它會最佳化在folios被釋放時需要獲取的鎖。folios批次返回時為空,並準備好用於另一批;無需重新初始化。

上下文

可以在程序或中斷上下文中呼叫,但不能在NMI上下文中呼叫。可以在持有自旋鎖時呼叫。

unsigned long folio_pfn(const struct folio *folio)

返回folio的頁幀號。

引數

const struct folio *folio

該 folio。

描述

一個folio可能包含多個頁。這些頁具有連續的頁幀號。

返回

folio中第一個頁的頁幀號。

pte_t folio_mk_pte(struct folio *folio, pgprot_t pgprot)

為此folio建立一個PTE

引數

struct folio *folio

要為其建立PTE的folio

pgprot_t pgprot

要使用的頁保護位

描述

為此folio的第一個頁建立一個頁表條目。這適合傳遞給set_ptes()。

返回

適合對映此folio的頁表條目。

pmd_t folio_mk_pmd(struct folio *folio, pgprot_t pgprot)

為此folio建立一個PMD

引數

struct folio *folio

要為其建立PMD的folio

pgprot_t pgprot

要使用的頁保護位

描述

為此folio的第一個頁建立一個頁表條目。這適合傳遞給set_pmd_at()。

返回

適合對映此folio的頁表條目。

bool folio_maybe_dma_pinned(struct folio *folio)

報告folio是否可能被DMA鎖定。

引數

struct folio *folio

該 folio。

描述

此函式檢查folio是否已透過呼叫pin_user_pages()系列函式進行鎖定。

對於小型folios,返回值為部分模糊:false不模糊,因為它表示“明確未被DMA鎖定”,但true表示“可能被DMA鎖定,但也可能是誤報,因為它具有至少GUP_PIN_COUNTING_BIAS的普通folio引用”。

誤報是可以的,因為:a) folio不太可能獲得那麼多引用計數,b) 此例程的所有呼叫者都應該能夠優雅地處理誤報。

對於大多數大型folios,結果將是完全正確的。這是因為我們有更多可用的跟蹤資料:使用_pincount欄位而不是GUP_PIN_COUNTING_BIAS方案。

更多資訊,請參見pin_user_pages()及其相關呼叫

返回

如果folio可能已被“dma-pinned”,則為True。如果folio明確未被dma-pinned,則為False。

bool is_zero_page(const struct page *page)

查詢頁是否為零頁

引數

const struct page *page

要查詢的頁

描述

如果page是永久零頁之一,則返回true。

bool is_zero_folio(const struct folio *folio)

查詢folio是否為零頁

引數

const struct folio *folio

要查詢的folio

描述

如果folio是永久零頁之一,則返回true。

long folio_nr_pages(const struct folio *folio)

folio中的頁數。

引數

const struct folio *folio

該 folio。

返回

一個正的2的冪。

struct folio *folio_next(struct folio *folio)

移動到下一個物理folio。

引數

struct folio *folio

我們當前正在操作的folio。

描述

如果您有物理連續記憶體,它可能跨越多個folio(例如struct bio_vec),請使用此函式從一個folio移動到下一個。如果記憶體僅是虛擬連續的,請勿使用此函式,因為folios幾乎肯定不相鄰。這相當於寫入page++的folio版本。

上下文

我們假設folios在更高層已被引用計數和/或鎖定,並且不調整引用計數。

返回

下一個struct folio

unsigned int folio_shift(const struct folio *folio)

此folio描述的記憶體大小。

引數

const struct folio *folio

該 folio。

描述

一個folio表示大小為2的冪的位元組數。此函式告訴您folio是2的哪次冪。另請參見folio_size()folio_order()

上下文

呼叫者應持有folio的引用,以防止它被拆分。folio不需要被鎖定。

返回

此folio大小的以2為底的對數。

size_t folio_size(const struct folio *folio)

folio中的位元組數。

引數

const struct folio *folio

該 folio。

上下文

呼叫者應持有folio的引用,以防止它被拆分。folio不需要被鎖定。

返回

此folio中的位元組數。

bool folio_maybe_mapped_shared(struct folio *folio)

folio是否對映到多個MM的頁表中

引數

struct folio *folio

該 folio。

描述

此函式檢查folio當前是否可能對映到多個MM(“可能共享對映”),或者folio是否確定對映到單個MM(“獨佔對映”)。

對於KSM folios,當一個folio多次對映到同一個MM時,此函式也返回“共享對映”,因為單個頁對映是獨立的。

對於小型匿名folios和匿名hugetlb folios,返回值將完全正確:非KSM folios最多隻能對映到MM一次,並且不能部分對映。KSM folios即使多次對映到同一個MM也被視為共享。

對於其他folios,結果可能模糊。
  1. 對於部分可對映的大folios (THP),如果一個folio在某個時間點被兩個以上MM對映,返回值可能會錯誤地指示“共享對映”(誤報)。

  2. 對於頁快取folios(包括hugetlb),當同一個MM中的兩個VMA覆蓋相同的檔案範圍時,返回值可能會錯誤地指示“共享對映”(誤報)。

此外,此函式只考慮使用folio對映計數跟蹤的當前頁表對映。

此函式不考慮:
  1. folio是否可能在(不久的)將來被對映(例如,交換快取、頁快取、遷移的臨時取消對映)。

  2. folio是否以不同方式對映(VM_PFNMAP)。

  3. hugetlb頁表共享是否適用。呼叫者可能需要檢查hugetlb_pmd_shared()。

返回

folio是否估計對映到多個MM中。

int folio_expected_ref_count(const struct folio *folio)

計算預期的folio引用計數

引數

const struct folio *folio

該folio

描述

計算預期的folio引用計數,考慮來自頁快取、交換快取、PG_private和頁表對映的引用。與folio_ref_count()結合使用時,可用於檢測意外引用(例如,GUP或其他臨時引用)。

目前不考慮來自LRU快取的引用。如果folio是從LRU中隔離的(遷移或拆分時就是這種情況),則LRU快取不適用。

在未對映的folio上呼叫此函式——!folio_mapped()——並且該folio被鎖定時,將返回穩定結果。

在對映的folio上呼叫此函式不會產生穩定結果,因為沒有任何東西能阻止額外的頁表映射出現(例如fork())或消失(例如munmap())。

在沒有folio鎖的情況下呼叫此函式也不會產生穩定結果:例如,folio可能同時從交換快取中移除。

然而,即使在沒有folio鎖或在對映的folio上呼叫,此函式仍可用於及早檢測意外引用(例如,如果鎖定folio並取消對映有意義)。

呼叫者必須將自己可能持有的任何引用(例如,來自folio_try_get())新增到結果中。

返回預期的folio引用計數。

struct ptdesc *pagetable_alloc(gfp_t gfp, unsigned int order)

分配頁表

引數

gfp_t gfp

GFP標誌

unsigned int order

期望的頁表階

描述

pagetable_alloc分配頁表記憶體以及描述該記憶體的頁表描述符。

返回

描述已分配頁表的ptdesc。

void pagetable_free(struct ptdesc *pt)

釋放頁表

引數

struct ptdesc *pt

頁表描述符

描述

pagetable_free釋放頁表描述符描述的所有頁表記憶體以及描述符本身的記憶體。

struct vm_area_struct *vma_lookup(struct mm_struct *mm, unsigned long addr)

在特定地址查詢VMA

引數

struct mm_struct *mm

程序地址空間。

unsigned long addr

使用者地址。

返回

在給定地址處的vm_area_struct,否則為NULL

bool vma_is_special_huge(const struct vm_area_struct *vma)

透明大頁頁表條目是否被視為特殊?

引數

const struct vm_area_struct *vma

指向要考慮的struct vm_area_struct的指標

描述

透明大頁頁表條目是否根據vm_normal_page()中的定義被視為“特殊”。

返回

如果透明大頁頁表條目應被視為特殊則為true,否則為false。

int folio_ref_count(const struct folio *folio)

此folio的引用計數。

引數

const struct folio *folio

該 folio。

描述

引用計數通常透過呼叫folio_get()增加,透過呼叫folio_put()減少。folio引用計數的一些典型使用者:

  • 頁表中的每個引用

  • 頁快取

  • 檔案系統私有資料

  • LRU列表

  • 管道

  • 引用程序地址空間中此頁的直接I/O

返回

此folio的引用數量。

bool folio_try_get(struct folio *folio)

嘗試增加folio的引用計數。

引數

struct folio *folio

該 folio。

描述

如果您尚未持有folio的引用,可以使用此函式嘗試獲取一個。它可能會失敗,例如,如果自從您找到指向它的指標後folio已被釋放,或者它為了拆分或遷移目的而被凍結。

返回

如果引用計數成功增加,則為True。

int is_highmem(struct zone *zone)

一個輔助函式,用於快速檢查struct zone是否為高記憶體區域。這旨在將通用程式碼中對ZONE_{DMA/NORMAL/HIGHMEM/etc}的引用保持在最低限度。

引數

struct zone *zone

指向struct zone變數的指標

返回

對於高記憶體區域為1,否則為0

for_each_online_pgdat

for_each_online_pgdat (pgdat)

遍歷所有線上節點的輔助宏

引數

pgdat

指向pg_data_t變數的指標

for_each_zone

for_each_zone (zone)

遍歷所有記憶體區域的輔助宏

引數

zone

指向struct zone變數的指標

描述

使用者只需宣告zone變數,for_each_zone會填充它。

struct zoneref *next_zones_zonelist(struct zoneref *z, enum zone_type highest_zoneidx, nodemask_t *nodes)

使用zonelist中的遊標作為起始點,返回允許節點掩碼內最高highest_zoneidx處或其以下的下一個區域

引數

struct zoneref *z

用作搜尋起始點的遊標

enum zone_type highest_zoneidx

要返回的最高區域的區域索引

nodemask_t *nodes

用於過濾zonelist的可選節點掩碼

描述

此函式使用遊標作為搜尋的起始點,返回給定區域索引處或其以下、且在允許節點掩碼內的下一個區域。返回的zoneref是一個遊標,表示當前正在檢查的區域。在再次呼叫next_zones_zonelist之前,應將其前進一個。

返回

使用zonelist中的遊標作為起始點,返回允許節點掩碼內最高highest_zoneidx處或其以下的下一個區域

struct zoneref *first_zones_zonelist(struct zonelist *zonelist, enum zone_type highest_zoneidx, nodemask_t *nodes)

在zonelist中允許的節點掩碼內,返回最高highest_zoneidx處或其以下的第一個區域

引數

struct zonelist *zonelist

要搜尋合適區域的zonelist

enum zone_type highest_zoneidx

要返回的最高區域的區域索引

nodemask_t *nodes

用於過濾zonelist的可選節點掩碼

描述

此函式返回給定區域索引處或其以下、且在允許節點掩碼內的第一個區域。返回的zoneref是一個遊標,可以透過在呼叫next_zones_zonelist之前將其前進一個來遍歷zonelist。

當未找到符合條件的區域時,zoneref->zone為NULL(zoneref本身從不為NULL)。這可能是真實情況,也可能是由於cpuset修改導致併發nodemask更新。

返回

找到的第一個合適區域的Zoneref指標

for_each_zone_zonelist_nodemask

for_each_zone_zonelist_nodemask (zone, z, zlist, highidx, nodemask)

遍歷zonelist中給定區域索引處或其以下、且在節點掩碼內的有效區域的輔助宏

引數

zone

迭代器中的當前區域

z

正在迭代的zonelist->_zonerefs中的當前指標

zlist

正在迭代的zonelist

highidx

要返回的最高區域的區域索引

nodemask

分配器允許的節點掩碼

描述

此迭代器遍歷給定區域索引處或其以下、且在給定節點掩碼內的所有區域

for_each_zone_zonelist

for_each_zone_zonelist (zone, z, zlist, highidx)

遍歷zonelist中給定區域索引處或其以下的有效區域的輔助宏

引數

zone

迭代器中的當前區域

z

正在迭代的zonelist->zones中的當前指標

zlist

正在迭代的zonelist

highidx

要返回的最高區域的區域索引

描述

此迭代器遍歷給定區域索引處或其以下的所有區域。

int pfn_valid(unsigned long pfn)

檢查PFN是否有有效的記憶體對映條目

引數

unsigned long pfn

要檢查的頁幀號

描述

檢查PFN是否有所謂的struct page的有效記憶體對映條目。請注意,記憶體對映條目的可用性並不意味著該PFN處有實際可用的記憶體。struct page可能代表一個空洞或一個不可用的頁幀。

返回

對於有記憶體對映條目的PFN為1,否則為0

struct address_space *folio_mapping(struct folio *folio)

找到此 folio 儲存所在的對映。

引數

struct folio *folio

該 folio。

描述

對於頁面快取中的 folio,返回此頁面所屬的對映。交換快取中的 folio 返回儲存此頁面的交換對映(這與儲存資料的交換檔案或交換裝置的對映不同)。

您可以為不在交換快取或頁面快取中的 folio 呼叫此函式,它將返回 NULL。

int __anon_vma_prepare(struct vm_area_struct *vma)

將 anon_vma 附加到記憶體區域

引數

struct vm_area_struct *vma

所討論的記憶體區域

描述

這確保了“vma”描述的記憶體對映附加了一個“anon_vma”,以便我們可以將對映到其中的匿名頁面與該 anon_vma 關聯起來。

常見情況是我們已經有了一個,這由 anon_vma_prepare() 內聯處理。但如果沒有,我們需要找到一個相鄰的對映,從中可以重用 anon_vma(當拆分 vma 的唯一原因是 mprotect() 時非常常見),或者我們分配一個新的。

匿名 vma 的分配非常微妙,因為我們可能在 folio_lock_anon_vma_read() 中樂觀地查找了 anon_vma,這甚至可能在新分配的 vma 中觸及 rwsem(它依賴 RCU 確保 anon_vma 實際上沒有被銷燬)。

因此,即使對於新的分配,我們也需要進行適當的 anon_vma 鎖定。同時,我們不希望在已經存在 anon_vma 的常見情況下進行任何鎖定。

unsigned long page_address_in_vma(const struct folio *folio, const struct page *page, const struct vm_area_struct *vma)

該頁面在此 VMA 中的虛擬地址。

引數

const struct folio *folio

包含該頁面的 folio。

const struct page *page

folio 中的頁面。

const struct vm_area_struct *vma

需要知道地址的 VMA。

描述

計算此頁面在指定 VMA 中的使用者虛擬地址。呼叫者有責任檢查該頁面是否實際在 VMA 內。目前可能沒有指向此頁面的 PTE,但如果在此地址發生頁面錯誤,則將訪問此頁面。

上下文

呼叫者應持有對 folio 的引用。呼叫者應持有鎖(例如 i_mmap_lock 或 mmap_lock),以防止 VMA 被修改。

返回

此頁面在 VMA 中對應的虛擬地址。

int folio_referenced(struct folio *folio, int is_locked, struct mem_cgroup *memcg, unsigned long *vm_flags)

測試 folio 是否被引用。

引數

struct folio *folio

要測試的folio。

int is_locked

呼叫者持有 folio 上的鎖。

struct mem_cgroup *memcg

目標記憶體 cgroup

unsigned long *vm_flags

所有引用 folio 的 vma->vm_flags 的組合。

描述

快速測試並清除 folio 的所有對映的引用,

返回

引用 folio 的對映數量。如果函式因 rmap 鎖競爭而中止,則返回 -1。

int mapping_wrprotect_range(struct address_space *mapping, pgoff_t pgoff, unsigned long pfn, unsigned long nr_pages)

防寫指定範圍內的所有對映。

引數

struct address_space *mapping

應遍歷其反向對映的對映。

pgoff_t pgoff

pfnmapping 中對映的頁面偏移量。

unsigned long pfn

mapping 中在 pgoff 處對映的頁面的 PFN。

unsigned long nr_pages

跨越的物理連續基本頁面的數量。

描述

遍歷反向對映,查詢包含 mapping 中指定範圍內頁面共享對映的所有 VMA,並對它們進行防寫(即,更新頁表以將對映標記為只讀,以便在寫入對映時出現防寫錯誤)。

pfn 值不必引用 folio,而是可以引用對映到使用者空間的核心分配。因此,我們不要求頁面對映到具有有效對映或索引欄位的 folio,而是由呼叫者在 mappingpgoff 中指定這些。

返回

防寫的 PTE 數量,或錯誤。

int pfn_mkclean_range(unsigned long pfn, unsigned long nr_pages, pgoff_t pgoff, struct vm_area_struct *vma)

清理指定 vma 內共享對映中 [pfn, pfn + nr_pages) 範圍在特定偏移量 (pgoff) 處對映的 PTE(包括 PMD)。由於乾淨的 PTE 也應該是隻讀的,因此也對它們進行防寫。

引數

unsigned long pfn

起始 pfn。

unsigned long nr_pages

pfn 開始的物理連續頁面的數量。

pgoff_t pgoff

pfn 對映的頁面偏移量。

struct vm_area_struct *vma

pfn 對映所在的 vma。

描述

返回已清理的 PTE(包括 PMD)的數量。

void folio_move_anon_rmap(struct folio *folio, struct vm_area_struct *vma)

將 folio 移動到我們的 anon_vma

引數

struct folio *folio

要移動到我們的 anon_vma 的 folio

struct vm_area_struct *vma

folio 所屬的 vma

描述

當一個 folio 在 COW 事件後獨佔地屬於一個程序時,該 folio 可以被移動到僅屬於該程序的 anon_vma 中,這樣 rmap 程式碼就不會搜尋父程序或兄弟程序。

void __folio_set_anon(struct folio *folio, struct vm_area_struct *vma, unsigned long address, bool exclusive)

為 folio 設定新的匿名 rmap。

引數

struct folio *folio

要為其設定新匿名 rmap 的 folio。

struct vm_area_struct *vma

要將 folio 新增到的 VM 區域。

unsigned long address

對映的使用者虛擬地址。

bool exclusive

folio 是否對程序獨佔。

void __page_check_anon_rmap(const struct folio *folio, const struct page *page, struct vm_area_struct *vma, unsigned long address)

匿名 rmap 新增的完整性檢查

引數

const struct folio *folio

包含 page 的 folio。

const struct page *page

要檢查對映的頁面

struct vm_area_struct *vma

新增對映的 vm 區域

unsigned long address

對映的使用者虛擬地址

void folio_add_anon_rmap_ptes(struct folio *folio, struct page *page, int nr_pages, struct vm_area_struct *vma, unsigned long address, rmap_t flags)

將 PTE 對映新增到匿名 folio 的頁面範圍

引數

struct folio *folio

要新增對映的 folio

struct page *page

要新增的第一個頁面

int nr_pages

將要對映的頁面數量

struct vm_area_struct *vma

新增對映的 vm 區域

unsigned long address

要對映的第一個頁面的使用者虛擬地址

rmap_t flags

rmap 標誌

描述

folio 的頁面範圍由 [first_page, first_page + nr_pages) 定義

呼叫者需要持有頁表鎖,並且在 anon_vma 情況下,頁面必須被鎖定:以在設定後序列化對映和索引檢查,並確保匿名 folio 不會競爭性地升級為 KSM folio(但 KSM folio 永遠不會降級)。

void folio_add_anon_rmap_pmd(struct folio *folio, struct page *page, struct vm_area_struct *vma, unsigned long address, rmap_t flags)

將 PMD 對映新增到匿名 folio 的頁面範圍

引數

struct folio *folio

要新增對映的 folio

struct page *page

要新增的第一個頁面

struct vm_area_struct *vma

新增對映的 vm 區域

unsigned long address

要對映的第一個頁面的使用者虛擬地址

rmap_t flags

rmap 標誌

描述

folio 的頁面範圍由 [first_page, first_page + HPAGE_PMD_NR) 定義

呼叫者需要持有頁表鎖,並且在 anon_vma 情況下,頁面必須被鎖定:以在設定後序列化對映和索引檢查。

void folio_add_new_anon_rmap(struct folio *folio, struct vm_area_struct *vma, unsigned long address, rmap_t flags)

將對映新增到新的匿名 folio。

引數

struct folio *folio

要新增對映的 folio。

struct vm_area_struct *vma

新增對映的 vm 區域

unsigned long address

對映的使用者虛擬地址

rmap_t flags

rmap 標誌

描述

類似於 folio_add_anon_rmap_*(),但只能在新(new)的 folio 上呼叫。這意味著可以繞過增量和測試。當 folio 獨佔時,除非兩個執行緒併發對映它,否則不必鎖定。但是,如果 folio 是共享的,則必須鎖定。

如果 folio 可透過 PMD 對映,則將其計為 THP。

void folio_add_file_rmap_ptes(struct folio *folio, struct page *page, int nr_pages, struct vm_area_struct *vma)

將 PTE 對映新增到 folio 的頁面範圍

引數

struct folio *folio

要新增對映的 folio

struct page *page

要新增的第一個頁面

int nr_pages

將使用 PTE 對映的頁面數量

struct vm_area_struct *vma

新增對映的 vm 區域

描述

folio 的頁面範圍由 [page, page + nr_pages) 定義

呼叫者需要持有頁表鎖。

void folio_add_file_rmap_pmd(struct folio *folio, struct page *page, struct vm_area_struct *vma)

將 PMD 對映新增到 folio 的頁面範圍

引數

struct folio *folio

要新增對映的 folio

struct page *page

要新增的第一個頁面

struct vm_area_struct *vma

新增對映的 vm 區域

描述

folio 的頁面範圍由 [page, page + HPAGE_PMD_NR) 定義

呼叫者需要持有頁表鎖。

void folio_add_file_rmap_pud(struct folio *folio, struct page *page, struct vm_area_struct *vma)

將 PUD 對映新增到 folio 的頁面範圍

引數

struct folio *folio

要新增對映的 folio

struct page *page

要新增的第一個頁面

struct vm_area_struct *vma

新增對映的 vm 區域

描述

folio 的頁面範圍由 [page, page + HPAGE_PUD_NR) 定義

呼叫者需要持有頁表鎖。

void folio_remove_rmap_ptes(struct folio *folio, struct page *page, int nr_pages, struct vm_area_struct *vma)

從 folio 的頁面範圍中移除 PTE 對映

引數

struct folio *folio

要從中移除對映的 folio

struct page *page

要移除的第一個頁面

int nr_pages

將從對映中移除的頁面數量

struct vm_area_struct *vma

移除對映的 vm 區域

描述

folio 的頁面範圍由 [page, page + nr_pages) 定義

呼叫者需要持有頁表鎖。

void folio_remove_rmap_pmd(struct folio *folio, struct page *page, struct vm_area_struct *vma)

從 folio 的頁面範圍中移除 PMD 對映

引數

struct folio *folio

要從中移除對映的 folio

struct page *page

要移除的第一個頁面

struct vm_area_struct *vma

移除對映的 vm 區域

描述

folio 的頁面範圍由 [page, page + HPAGE_PMD_NR) 定義

呼叫者需要持有頁表鎖。

void folio_remove_rmap_pud(struct folio *folio, struct page *page, struct vm_area_struct *vma)

從 folio 的頁面範圍中移除 PUD 對映

引數

struct folio *folio

要從中移除對映的 folio

struct page *page

要移除的第一個頁面

struct vm_area_struct *vma

移除對映的 vm 區域

描述

folio 的頁面範圍由 [page, page + HPAGE_PUD_NR) 定義

呼叫者需要持有頁表鎖。

void try_to_unmap(struct folio *folio, enum ttu_flags flags)

嘗試移除 folio 的所有頁表對映。

引數

struct folio *folio

要解除對映的 folio。

enum ttu_flags flags

動作和標誌

描述

嘗試移除所有對映此 folio 的頁表項。如果需要(使用 TTU_SYNC 防止記賬競爭),呼叫者有責任檢查 folio 是否仍被對映。

上下文

呼叫者必須持有 folio 鎖。

void try_to_migrate(struct folio *folio, enum ttu_flags flags)

嘗試將所有頁表對映替換為交換條目

引數

struct folio *folio

要替換頁表項的 folio

enum ttu_flags flags

動作和標誌

描述

嘗試移除所有對映此 folio 的頁表項,並將其替換為特殊的交換條目。呼叫者必須持有 folio 鎖。

struct page *make_device_exclusive(struct mm_struct *mm, unsigned long addr, void *owner, struct folio **foliop)

將頁面標記為裝置獨佔使用

引數

struct mm_struct *mm

相關目標程序的 mm_struct

unsigned long addr

要標記為獨佔裝置訪問的虛擬地址

void *owner

傳遞給 MMU_NOTIFY_EXCLUSIVE 範圍通知器以允許過濾

struct folio **foliop

成功時 folio 指標將儲存在此處。

描述

此函式查詢給定地址處對映的頁面,獲取 folio 引用,鎖定 folio 並用特殊的裝置獨佔 PFN 交換條目替換 PTE,從而阻止透過程序頁表進行訪問。函式返回時 folio 已被鎖定和引用。

發生故障時,在呼叫 MMU 通知器後,裝置獨佔條目在 folio 鎖下被原始 PTE 替換。

僅支援匿名非 hugetlb folio,並且 VMA 必須具有寫許可權,以便我們可以將匿名頁面以可寫方式引入,從而將其標記為獨佔。呼叫者必須以讀模式持有 mmap_lock。

使用此函式程式設計裝置訪問的驅動程式必須在程式設計期間使用 mmu notifier 臨界區來持有裝置特定鎖。程式設計完成後,它應該釋放 folio 鎖和引用,此後 CPU 對頁面的訪問將撤銷獨佔訪問。

注意

  1. 此函式始終操作對映單個頁面的 PTE。PMD 大小的 THP 在將 addr 對應的單個 PTE 進行轉換之前,首先被重新對映為由 PTE 對映。

  2. 雖然阻止了透過程序頁表的併發訪問,但未處理和不支援透過其他頁面引用(例如,早期 GUP 呼叫)的併發訪問。

  3. 裝置獨佔條目被核心 mm 視為“乾淨”和“舊”。裝置驅動程式在收到 MMU 通知器通知時必須更新 folio 狀態。

返回

成功時指向已對映頁面的指標,否則為負錯誤碼。

void __rmap_walk_file(struct folio *folio, struct address_space *mapping, pgoff_t pgoff_start, unsigned long nr_pages, struct rmap_walk_control *rwc, bool locked)

遍歷檔案支援對映的反向對映,該頁面在指定頁面快取物件中以指定偏移量對映。

引數

struct folio *folio

要遍歷其對映的 folio,如果為 NULL,則會配置 rwc 中指定的回撥,以便能夠正確查詢對映。

struct address_space *mapping

我們打算遍歷其對映 VMA 的頁面快取物件。如果 folio 非 NULL,則此值應等於 folio_mapping(folio)。

pgoff_t pgoff_start

我們正在查詢的頁面在 mapping 中的偏移量。如果 folio 非 NULL,則此值應等於 folio_pgoff(folio)。

unsigned long nr_pages

對映所對映的頁面數量。如果 folio 非 NULL,則此值應等於 folio_nr_pages(folio)。

struct rmap_walk_control *rwc

描述遍歷應如何進行的反向對映遍歷控制物件。

bool locked

mapping 是否已鎖定?如果未鎖定,我們獲取鎖。

int migrate_folio(struct address_space *mapping, struct folio *dst, struct folio *src, enum migrate_mode mode)

簡單 folio 遷移。

引數

struct address_space *mapping

包含 folio 的 address_space。

struct folio *dst

要將資料遷移到的 folio。

struct folio *src

包含當前資料的 folio。

enum migrate_mode mode

如何遷移頁面。

描述

直接遷移單個 LRU folio 的通用邏輯,適用於沒有私有資料的 folio。

folio 在進入和退出時都被鎖定。

int buffer_migrate_folio(struct address_space *mapping, struct folio *dst, struct folio *src, enum migrate_mode mode)

帶有緩衝區的 folio 遷移函式。

引數

struct address_space *mapping

包含 src 的地址空間。

struct folio *dst

要遷移到的 folio。

struct folio *src

要從中遷移的 folio。

enum migrate_mode mode

如何遷移 folio。

描述

僅當底層檔案系統保證不存在對 src 的其他引用時,才能使用此函式。例如,附加的緩衝區頭僅在 folio 鎖下訪問。如果您的檔案系統無法提供此保證,則 buffer_migrate_folio_norefs() 可能更合適。

返回

成功時為 0,失敗時為負 errno。

int buffer_migrate_folio_norefs(struct address_space *mapping, struct folio *dst, struct folio *src, enum migrate_mode mode)

帶有緩衝區的 folio 遷移函式。

引數

struct address_space *mapping

包含 src 的地址空間。

struct folio *dst

要遷移到的 folio。

struct folio *src

要從中遷移的 folio。

enum migrate_mode mode

如何遷移 folio。

描述

類似於 buffer_migrate_folio(),但此變體更小心,並檢查是否也沒有緩衝區頭引用。對於緩衝區頭直接查詢和引用的對映(例如塊裝置對映),此函式是正確的選擇。

返回

成功時為 0,失敗時為負 errno。

unsigned long do_mmap(struct file *file, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, vm_flags_t vm_flags, unsigned long pgoff, unsigned long *populate, struct list_head *uf)

在當前程序地址空間中執行使用者態記憶體對映,長度為 len,保護位為 prot,mmap 標誌為 flags(由此推斷出 VMA 標誌),以及要應用的任何附加 VMA 標誌 vm_flags。如果這是檔案支援對映,則檔案在 file 中指定,頁面偏移量透過 pgoff 指定。

引數

struct file *file

可選的 struct file 指標,描述要對映的檔案(如果為檔案支援對映)。

unsigned long addr

如果非零,則提示(或如果 flags 設定了 MAP_FIXED,則指定)執行此對映的地址。有關詳細資訊,請參閱 mmap(2)。必須按頁面對齊。

unsigned long len

對映的長度。將按頁面對齊,且大小必須至少為 1 頁。

unsigned long prot

描述對映所需訪問的保護位。有關詳細資訊,請參閱 mmap(2)。

unsigned long flags

指定如何執行對映的標誌,有關詳細資訊,請參閱 mmap(2)。

vm_flags_t vm_flags

預設應設定的 VMA 標誌,否則為 0。

unsigned long pgoff

檔案支援時檔案中的頁面偏移量,否則應為 0。

unsigned long *populate

指向一個值,如果不需要填充範圍,則將其設定為 0;如果需要,則設定為要填充的位元組數。必須為非 NULL。有關在何種情況下發生範圍填充的詳細資訊,請參閱 mmap(2)。

struct list_head *uf

一個可選的列表頭指標,用於跟蹤 userfaultfd 解對映事件(如果發生)。如果提供,則由呼叫者管理。

描述

此函式不對檔案執行安全檢查,並假設如果 uf 非 NULL,呼叫者已提供一個列表頭來跟蹤 userfaultfd uf 的解對映事件。

它還簡單地透過設定 populate(必須為非 NULL)來指示是否需要記憶體填充,並期望呼叫者在適當時實際執行此任務。

此函式將呼叫特定於體系結構(如果提供且相關,則為檔案系統特定)的邏輯,以確定在不是 MAP_FIXED 的情況下放置對映的最合適的未對映區域。

需要使用者態 mmap() 行為的呼叫者應呼叫 vm_mmap(),該函式也匯出供模組使用。

那些需要此行為但安全性檢查較少、使用者態故障檔案描述符和填充行為,並且自己處理 mmap 寫鎖的呼叫者,應呼叫此函式。

請注意,如果發生適當的合併,返回的地址可能位於合併的 VMA 內,因此它不一定指定 VMA 的開始,而只指定一個長度為 len 位元組的有效對映範圍的開始,向下舍入到最接近的頁面大小。

呼叫者必須寫鎖定 current->mm->mmap_lock。

返回

錯誤,或者已執行請求對映的地址。

struct vm_area_struct *find_vma_intersection(struct mm_struct *mm, unsigned long start_addr, unsigned long end_addr)

查詢與給定區間相交的第一個 VMA。

引數

struct mm_struct *mm

程序地址空間。

unsigned long start_addr

包含的起始使用者地址。

unsigned long end_addr

排他的結束使用者地址。

返回

所提供範圍內的第一個 VMA,否則為 NULL。假設 start_addr < end_addr。

struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)

查詢給定地址的 VMA,或下一個 VMA。

引數

struct mm_struct *mm

要檢查的 mm_struct

unsigned long addr

地址

返回

與 addr 關聯的 VMA,或下一個 VMA。如果 addr 或更高地址處沒有 VMA,則可能返回 NULL

struct vm_area_struct *find_vma_prev(struct mm_struct *mm, unsigned long addr, struct vm_area_struct **pprev)

查詢給定地址的 VMA,或下一個 vma,並將 pprev 設定為前一個 VMA(如果有)。

引數

struct mm_struct *mm

要檢查的 mm_struct

unsigned long addr

地址

struct vm_area_struct **pprev

要設定為前一個 VMA 的指標

描述

請注意,此處缺少 RCU 鎖,因為使用了外部 mmap_lock()。

返回

addr 關聯的 VMA,或下一個 vma。如果 addr 或更高地址處沒有 vma,則可能返回 NULL

void __ref kmemleak_alloc(const void *ptr, size_t size, int min_count, gfp_t gfp)

註冊新分配的物件

引數

const void *ptr

指向物件開頭的指標

size_t size

物件大小

int min_count

對此物件的最小引用數。如果在記憶體掃描期間發現的引用數少於 min_count,則該物件將被報告為記憶體洩漏。如果 min_count 為 0,則該物件永遠不會被報告為洩漏。如果 min_count 為 -1,則該物件將被忽略(不掃描且不報告為洩漏)

gfp_t gfp

kmalloc() 標誌,用於 kmemleak 內部記憶體分配

描述

當分配新物件(記憶體塊)時(kmem_cache_alloc, kmalloc 等),此函式從核心分配器呼叫。

void __ref kmemleak_alloc_percpu(const void __percpu *ptr, size_t size, gfp_t gfp)

註冊新分配的 __percpu 物件

引數

const void __percpu *ptr

指向物件開頭的 __percpu 指標

size_t size

物件大小

gfp_t gfp

用於 kmemleak 內部記憶體分配的標誌

描述

當分配新物件(記憶體塊)時(alloc_percpu),此函式從核心 percpu 分配器呼叫。

void __ref kmemleak_vmalloc(const struct vm_struct *area, size_t size, gfp_t gfp)

註冊新 vmalloc 分配的物件

引數

const struct vm_struct *area

指向 vm_struct 的指標

size_t size

物件大小

gfp_t gfp

用於 kmemleak 內部記憶體分配的 __vmalloc() 標誌

描述

當分配新物件(記憶體塊)時,此函式從 vmalloc() 核心分配器呼叫。

void __ref kmemleak_free(const void *ptr)

登出之前註冊的物件

引數

const void *ptr

指向物件開頭的指標

描述

當釋放物件(記憶體塊)時(kmem_cache_free、kfree、vfree 等),此函式從核心分配器呼叫。

void __ref kmemleak_free_part(const void *ptr, size_t size)

部分登出之前註冊的物件

引數

const void *ptr

指向物件開頭或內部的指標。這也表示要釋放的範圍的開始

size_t size

要登出的大小

描述

當只釋放記憶體塊的一部分時(通常從 bootmem 分配器),此函式被呼叫。

void __ref kmemleak_free_percpu(const void __percpu *ptr)

登出之前註冊的 __percpu 物件

引數

const void __percpu *ptr

指向物件開頭的 __percpu 指標

描述

當釋放物件(記憶體塊)時(free_percpu),此函式從核心 percpu 分配器呼叫。

void __ref kmemleak_update_trace(const void *ptr)

更新物件分配堆疊跟蹤

引數

const void *ptr

指向物件開頭的指標

描述

對於實際分配位置並非總是有用的情況,覆蓋物件分配堆疊跟蹤。

void __ref kmemleak_not_leak(const void *ptr)

將已分配物件標記為假陽性

引數

const void *ptr

指向物件開頭的指標

描述

對物件呼叫此函式將導致記憶體塊不再被報告為洩漏,並且始終被掃描。

void __ref kmemleak_transient_leak(const void *ptr)

將已分配物件標記為瞬態假陽性

引數

const void *ptr

指向物件開頭的指標

描述

對物件呼叫此函式將導致記憶體塊暫時不被報告為洩漏。例如,如果物件是單鏈表的一部分並且指向它的 ->next 引用已更改,則可能會發生這種情況。

void __ref kmemleak_ignore_percpu(const void __percpu *ptr)

類似於 kmemleak_ignore,但接受 percpu 地址引數

引數

const void __percpu *ptr

物件的 percpu 地址

void __ref kmemleak_ignore(const void *ptr)

忽略已分配物件

引數

const void *ptr

指向物件開頭的指標

描述

對物件呼叫此函式將導致記憶體塊被忽略(不掃描且不報告為洩漏)。通常在已知對應塊不是洩漏且不包含對其他已分配記憶體塊的任何引用時執行此操作。

void __ref kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp)

限制已分配物件的掃描範圍

引數

const void *ptr

指向物件開頭或內部的指標。這也表示掃描區域的開始

size_t size

掃描區域的大小

gfp_t gfp

kmalloc() 標誌,用於 kmemleak 內部記憶體分配

描述

當已知物件只有某些部分包含對其他物件的引用時,使用此函式。Kmemleak 將僅掃描這些區域,從而減少誤報的數量。

void __ref kmemleak_no_scan(const void *ptr)

不掃描已分配物件

引數

const void *ptr

指向物件開頭的指標

描述

此函式通知 kmemleak 不掃描給定的記憶體塊。在已知給定物件不包含對其他物件的任何引用的情況下非常有用。Kmemleak 將不掃描此類物件,從而減少誤報的數量。

void __ref kmemleak_alloc_phys(phys_addr_t phys, size_t size, gfp_t gfp)

類似於 kmemleak_alloc,但接受物理地址引數

引數

phys_addr_t phys

物件的物理地址

size_t size

物件大小

gfp_t gfp

kmalloc() 標誌,用於 kmemleak 內部記憶體分配

void __ref kmemleak_free_part_phys(phys_addr_t phys, size_t size)

類似於 kmemleak_free_part,但接受物理地址引數

引數

phys_addr_t phys

如果是物件開頭或內部的物理地址。這也表示要釋放的範圍的開始

size_t size

要登出的大小

void __ref kmemleak_ignore_phys(phys_addr_t phys)

類似於 kmemleak_ignore,但接受物理地址引數

引數

phys_addr_t phys

物件的物理地址

void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)

為給定資源重新對映並提供記憶體對映支援

引數

struct device *dev

**res** 的宿主裝置

struct dev_pagemap *pgmap

指向 `struct dev_pagemap` 的指標

注意

1/ 在將其傳遞給此函式之前,呼叫者必須至少初始化 **pgmap** 的 `range` 和 `type` 成員。

(此行已與 P5 合併以提高可讀性)

描述

2/ `altmap` 欄位可以可選地進行初始化,在這種情況下,必須在 `pgmap->flags` 中設定 `PGMAP_ALTMAP_VALID`。

(此行已與 P7 合併以提高可讀性)

3/ `ref` 欄位可選擇提供,在這種情況下,`pgmap->ref` 在進入時必須是“活的”,並將在 `devm_memremap_pages_release()` 時或此例程失敗時被終止和回收。

(此行已與 P9 合併以提高可讀性)

4/ `range` 預期是一個可以合理地被視為“系統 RAM”範圍的主機記憶體範圍,即不是裝置 mmio 範圍,但這不是強制性的。

(此行已與 P11 合併以提高可讀性)

struct dev_pagemap *get_dev_pagemap(unsigned long pfn, struct dev_pagemap *pgmap)

為 **pfn** 獲取 `dev_pagemap` 的新活躍引用

引數

unsigned long pfn

要查詢 `page_map` 的頁幀號

struct dev_pagemap *pgmap

可選的已知 `pgmap`,已有一個引用

描述

如果 **pgmap** 為非 NULL 且涵蓋 **pfn**,則它將按原樣返回。如果 **pgmap** 為非 NULL 但不涵蓋 **pfn**,則對其的引用將被釋放。

unsigned long vma_kernel_pagesize(struct vm_area_struct *vma)

此 VMA 的頁大小粒度。

引數

struct vm_area_struct *vma

使用者對映。

描述

此 VMA 中的 Folio 將對齊到此函式返回的位元組數,並且至少為此大小。

返回

支援 VMA 時分配的 Folio 的預設大小。

bool folio_isolate_hugetlb(struct folio *folio, struct list_head *list)

嘗試隔離一個已分配的 hugetlb Folio

引數

struct folio *folio

要隔離的 Folio

struct list_head *list

成功時將 Folio 新增到的列表

描述

隔離一個已分配(引用計數 > 0)的 hugetlb Folio,將其標記為已隔離/不可遷移,並將其從活躍列表移動到給定列表。

如果 **folio** 不是已分配的 hugetlb Folio,或者它已被隔離/不可遷移,則隔離將失敗。

成功時,將額外獲取一個 Folio 引用,該引用必須使用 folio_putback_hugetlb() 釋放以撤銷隔離。

返回

如果隔離成功則返回 True,否則返回 False。

void folio_putback_hugetlb(struct folio *folio)

解除 hugetlb Folio 的隔離

引數

struct folio *folio

已隔離的 hugetlb Folio

描述

回存/解除使用 folio_isolate_hugetlb() 隔離的 hugetlb Folio:將其標記為非隔離/可遷移,並將其放回活躍列表。

將釋放透過 folio_isolate_hugetlb() 獲得的額外 Folio 引用。

void folio_mark_accessed(struct folio *folio)

將 Folio 標記為已發生活動。

引數

struct folio *folio

要標記的 Folio。

描述

此函式將執行以下轉換之一

  • 非活躍、未引用 -> 非活躍、已引用

  • 非活躍、已引用 -> 活躍、未引用

  • 活躍、未引用 -> 活躍、已引用

當新分配的 Folio 尚未可見,因此對於非原子操作是安全的時,可以使用 `__folio_set_referenced()` 替代 folio_mark_accessed()

void folio_add_lru(struct folio *folio)

將 Folio 新增到 LRU 列表。

引數

struct folio *folio

要新增到 LRU 的 Folio。

描述

將 Folio 排隊以新增到 LRU。是將頁新增到[非]活躍[檔案|匿名]列表的決定被推遲到 `folio_batch` 被排空。這使得 folio_add_lru() 的呼叫者有機會使用 folio_mark_accessed() 將 Folio 新增到活躍列表。

void folio_add_lru_vma(struct folio *folio, struct vm_area_struct *vma)

將 Folio 新增到此 VMA 的適當 LRU 列表。

引數

struct folio *folio

要新增到 LRU 的 Folio。

struct vm_area_struct *vma

Folio 被對映到的 VMA。

描述

如果 VMA 是 `mlocked` 的,**folio** 將被新增到不可回收列表。否則,它將以與 folio_add_lru() 相同的方式處理。

void deactivate_file_folio(struct folio *folio)

去啟用一個檔案 Folio。

引數

struct folio *folio

要去啟用的 Folio。

描述

此函式向 VM 提示 **folio** 是一個很好的回收候選項,例如,如果其失效由於 Folio 髒汙或正在回寫而失敗。

上下文

呼叫者持有 Folio 的引用。

void folio_mark_lazyfree(struct folio *folio)

使匿名 Folio 惰性釋放

引數

struct folio *folio

要去啟用的 Folio

描述

folio_mark_lazyfree() 將 **folio** 移動到非活躍檔案列表。這樣做是為了加速 **folio** 的回收。

void folios_put_refs(struct folio_batch *folios, unsigned int *refs)

減少一批 Folio 的引用計數。

引數

struct folio_batch *folios

folios。

unsigned int *refs

要從每個 Folio 的引用計數中減去的引用數。

描述

類似於 folio_put(),但用於一批 Folio。這比自己編寫迴圈更高效,因為它會最佳化在 Folio 被釋放時需要獲取的鎖。Folio 批處理返回時為空且可供重複使用;無需重新初始化它。如果 **refs** 為 NULL,我們將從每個 Folio 引用計數中減去一。

上下文

可以在程序或中斷上下文中呼叫,但不能在NMI上下文中呼叫。可以在持有自旋鎖時呼叫。

void release_pages(release_pages_arg arg, int nr)

批處理 `put_page()`

引數

release_pages_arg arg

要釋放的頁陣列

int nr

要對映的頁數

描述

減少 **arg** 中所有頁的引用計數。如果降至零,則將頁從 LRU 中移除並釋放。

請注意,引數可以是頁陣列、編碼頁或 Folio 指標。我們忽略任何編碼位,並將它們中的任何一個轉換為一個 Folio,然後釋放它。

void folio_batch_remove_exceptionals(struct folio_batch *fbatch)

從批處理中移除非 Folio。

引數

struct folio_batch *fbatch

要修剪的批處理

描述

`find_get_entries()` 用 Folio 和影子/交換/DAX 條目填充批處理。此函式從 **fbatch** 中移除所有非 Folio 條目而不留下空洞,以便它可以傳遞給僅處理 Folio 的批處理操作。

void zpool_register_driver(struct zpool_driver *driver)

註冊一個 zpool 實現。

引數

struct zpool_driver *driver

要註冊的驅動程式

int zpool_unregister_driver(struct zpool_driver *driver)

登出一個 zpool 實現。

引數

struct zpool_driver *driver

要登出的驅動程式。

描述

模組使用計數用於防止在使用/解除安裝驅動程式時/之後繼續使用,因此如果從模組退出函式呼叫此函式,則不應失敗;如果從模組退出函式之外呼叫,並且此函式返回失敗,則驅動程式正在使用中,必須保持可用。

bool zpool_has_pool(char *type)

檢查池驅動程式是否可用

引數

char *type

要檢查的 zpool 型別(例如 `zsmalloc`)

描述

此函式檢查 **type** 池驅動程式是否可用。如有需要,它將嘗試載入請求的模組,但不能保證呼叫後模組仍會立即載入和可用。如果此函式返回 `true`,呼叫者應假定池可用,但必須準備好處理 zpool_create_pool() 返回失敗。但是,如果此函式返回 `false`,則呼叫者應假定請求的池型別不可用;要麼請求的池型別模組不存在,要麼無法載入,並且使用此池型別呼叫 zpool_create_pool() 將失敗。

**type** 字串必須以空字元結尾。

返回

如果 **type** 池可用則為 true,否則為 false。

struct zpool *zpool_create_pool(const char *type, const char *name, gfp_t gfp)

建立一個新的 zpool

引數

const char *type

要建立的 zpool 型別(例如 `zsmalloc`)

const char *name

zpool 的名稱(例如 `zram0`,`zswap`)

gfp_t gfp

分配池時使用的 GFP 標誌。

描述

此函式建立指定型別的新 zpool。如果實現支援,將在分配記憶體時使用 GFP 標誌。如果 `ops` 引數為 NULL,則建立的 zpool 將不可回收。

實現必須保證此函式是執行緒安全的。

**type** 和 **name** 字串必須以空字元結尾。

返回

成功時返回新的 zpool,失敗時返回 NULL。

void zpool_destroy_pool(struct zpool *zpool)

銷燬一個 zpool

引數

struct zpool *zpool

要銷燬的 zpool。

描述

實現必須保證此函式是執行緒安全的,但僅限於銷燬不同的池。同一個池只能銷燬一次,並且在銷燬後不應再使用。

此函式銷燬一個現有的 zpool。該 zpool 不應在使用中。

const char *zpool_get_type(struct zpool *zpool)

獲取 zpool 的型別

引數

struct zpool *zpool

要檢查的 zpool

描述

此函式返回池的型別。

實現必須保證此函式是執行緒安全的。

返回

zpool 的型別。

int zpool_malloc(struct zpool *zpool, size_t size, gfp_t gfp, unsigned long *handle, const int nid)

分配記憶體

引數

struct zpool *zpool

要從中分配記憶體的 zpool。

size_t size

要分配的記憶體量。

gfp_t gfp

分配記憶體時使用的 GFP 標誌。

unsigned long *handle

指向要設定的控制代碼的指標

const int nid

首選的節點 ID。

描述

此函式從池中分配請求的記憶體量。如果實現支援,將在分配記憶體時使用 GFP 標誌。提供的 **handle** 將設定為已分配物件的控制代碼。分配將優先使用 **nid** 指定的 NUMA 節點。

實現必須保證此函式是執行緒安全的。

返回

成功時返回 0,錯誤時返回負值。

void zpool_free(struct zpool *zpool, unsigned long handle)

釋放之前分配的記憶體

引數

struct zpool *zpool

分配記憶體的 zpool。

unsigned long handle

要釋放的記憶體控制代碼。

描述

此函式釋放之前分配的記憶體。它不保證池會實際釋放記憶體,只保證池中的記憶體將可供池使用。

實現必須保證此函式是執行緒安全的,但僅限於釋放不同的控制代碼。同一個控制代碼只能釋放一次,並且在釋放後不應再使用。

void *zpool_obj_read_begin(struct zpool *zpool, unsigned long handle, void *local_copy)

開始從之前分配的控制代碼讀取。

引數

struct zpool *zpool

分配控制代碼的 zpool

unsigned long handle

要讀取的控制代碼

void *local_copy

如果需要,使用的本地緩衝區。

描述

此函式開始對先前分配的控制代碼進行讀取操作。如果需要,可以透過複製記憶體到 **local_copy** 緩衝區來使用它。讀取完成後,必須呼叫 zpool_obj_read_end() 來撤銷任何已執行的操作(例如釋放鎖)。

返回

指向要讀取的控制代碼記憶體的指標,如果使用了 **local_copy**,則返回的指標是 **local_copy**。

void zpool_obj_read_end(struct zpool *zpool, unsigned long handle, void *handle_mem)

結束從之前分配的控制代碼讀取。

引數

struct zpool *zpool

分配控制代碼的 zpool

unsigned long handle

要讀取的控制代碼

void *handle_mem

zpool_obj_read_begin() 返回的指標

描述

完成由 zpool_obj_read_begin() 之前啟動的讀取操作。

void zpool_obj_write(struct zpool *zpool, unsigned long handle, void *handle_mem, size_t mem_len)

寫入之前分配的控制代碼。

引數

struct zpool *zpool

分配控制代碼的 zpool

unsigned long handle

要讀取的控制代碼

void *handle_mem

要從其中複製到控制代碼的記憶體。

size_t mem_len

要寫入的記憶體長度。

u64 zpool_get_total_pages(struct zpool *zpool)

池的總大小

引數

struct zpool *zpool

要檢查的 zpool

描述

此函式返回池的總大小(以頁為單位)。

返回

zpool 的總大小(以頁為單位)。

struct cgroup_subsys_state *mem_cgroup_css_from_folio(struct folio *folio)

與 Folio 關聯的 memcg 的 css

引數

struct folio *folio

感興趣的 Folio

描述

如果 `memcg` 繫結到預設層級,則返回與 **folio** 關聯的 `memcg` 的 `css`。返回的 `css` 在 **folio** 釋放之前一直與它關聯。

如果 `memcg` 繫結到傳統層級,則返回 `root_mem_cgroup` 的 `css`。

ino_t page_cgroup_ino(struct page *page)

返回頁所計費到的 memcg 的 inode 號

引數

struct page *page

該頁

描述

查詢頁所計費到的記憶體 cgroup 的最接近的線上祖先,並返回其 inode 號;如果頁未計費到任何 cgroup,則返回 0。呼叫此函式時不需要持有頁的引用。

請注意,此函式本質上是存在競態的,因為無法阻止 cgroup inode 在 page_cgroup_ino() 返回後立即被拆除並可能重新分配,因此它只能由不關心此問題的呼叫者(例如 procfs 介面)使用。

void mod_memcg_state(struct mem_cgroup *memcg, enum memcg_stat_item idx, int val)

更新 cgroup 記憶體統計資訊

引數

struct mem_cgroup *memcg

記憶體 cgroup

enum memcg_stat_item idx

統計項 - 可以是 `enum memcg_stat_item` 或 `enum node_stat_item`

int val

要新增到計數器的增量,可以是負數

void __mod_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx, int val)

更新 lruvec 記憶體統計資訊

引數

struct lruvec *lruvec

lruvec

enum node_stat_item idx

統計項

int val

要新增到計數器的增量,可以是負數

描述

lruvec 是 NUMA 節點和 cgroup 的交集。此函式更新受此級別狀態更改影響的所有三個計數器:每節點、每 cgroup、每 lruvec。

void count_memcg_events(struct mem_cgroup *memcg, enum vm_event_item idx, unsigned long count)

在 cgroup 中統計 VM 事件

引數

struct mem_cgroup *memcg

記憶體 cgroup

enum vm_event_item idx

事件項

unsigned long count

發生的事件數量

struct mem_cgroup *get_mem_cgroup_from_mm(struct mm_struct *mm)

獲取給定 `mm_struct` 的 memcg 引用。

引數

struct mm_struct *mm

從中提取 memcg 的 mm。它可以是 NULL。

描述

獲取 `mm->memcg` 的引用並在成功時返回它。如果 mm 為 NULL,則 memcg 的選擇如下:1) 如果設定了活躍 memcg,則選擇活躍 memcg。2) 如果可用,則選擇 `current->mm->memcg`。3) 根 memcg。如果 mem_cgroup 被停用,則返回 NULL。

struct mem_cgroup *get_mem_cgroup_from_current(void)

獲取當前任務的 memcg 引用。

引數

void

無引數

struct mem_cgroup *get_mem_cgroup_from_folio(struct folio *folio)

獲取給定 Folio 的 memcg 引用。

引數

struct folio *folio

從中提取 memcg 的 Folio。

struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root, struct mem_cgroup *prev, struct mem_cgroup_reclaim_cookie *reclaim)

遍歷記憶體 cgroup 層級

引數

struct mem_cgroup *root

層級根

struct mem_cgroup *prev

之前返回的 memcg,首次呼叫時為 NULL

struct mem_cgroup_reclaim_cookie *reclaim

用於共享回收遍歷的 cookie,完整遍歷時為 NULL

描述

返回 **root** 下層級子代的引用,或 **root** 本身,或在完整往返後返回 `NULL`。

呼叫者必須在後續呼叫中將返回值作為 **prev** 傳遞以進行引用計數,或者在往返完成之前使用 mem_cgroup_iter_break() 取消層級遍歷。

回收器可以在 **reclaim** 中指定一個節點,以將層級中的 memcg 分配給所有在同一節點上同時操作的回收器。

void mem_cgroup_iter_break(struct mem_cgroup *root, struct mem_cgroup *prev)

提前中止層級遍歷

引數

struct mem_cgroup *root

層級根

struct mem_cgroup *prev

mem_cgroup_iter() 返回的最後訪問的層級成員

void mem_cgroup_scan_tasks(struct mem_cgroup *memcg, int (*fn)(struct task_struct*, void*), void *arg)

遍歷記憶體 cgroup 層級的任務

引數

struct mem_cgroup *memcg

層級根

int (*fn)(struct task_struct *, void *)

為每個任務呼叫的函式

void *arg

傳遞給 **fn** 的引數

描述

此函式遍歷附加到 **memcg** 或其任何後代的任務,併為每個任務呼叫 **fn**。如果 **fn** 返回非零值,則函式中斷迭代迴圈。否則,它將遍歷所有任務並返回 0。

此函式不得為根記憶體 cgroup 呼叫。

struct lruvec *folio_lruvec_lock(struct folio *folio)

鎖定 Folio 的 lruvec。

引數

struct folio *folio

指向 Folio 的指標。

描述

這些函式在以下任何條件下使用都是安全的:- Folio 已鎖定 - `folio_test_lru` 為假 - Folio 已凍結(引用計數為 0)

返回

此 Folio 所在的 lruvec 及其鎖處於持有狀態。

struct lruvec *folio_lruvec_lock_irq(struct folio *folio)

鎖定 Folio 的 lruvec。

引數

struct folio *folio

指向 Folio 的指標。

描述

這些函式在以下任何條件下使用都是安全的:- Folio 已鎖定 - `folio_test_lru` 為假 - Folio 已凍結(引用計數為 0)

返回

此 Folio 所在的 lruvec 及其鎖處於持有狀態且中斷已停用。

struct lruvec *folio_lruvec_lock_irqsave(struct folio *folio, unsigned long *flags)

鎖定 Folio 的 lruvec。

引數

struct folio *folio

指向 Folio 的指標。

unsigned long *flags

指向 `irqsave` 標誌的指標。

描述

這些函式在以下任何條件下使用都是安全的:- Folio 已鎖定 - `folio_test_lru` 為假 - Folio 已凍結(引用計數為 0)

返回

此 Folio 所在的 lruvec 及其鎖處於持有狀態且中斷已停用。

void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru, int zid, int nr_pages)

新增或移除 LRU 頁的計數

引數

struct lruvec *lruvec

mem_cgroup 每區域 LRU 向量

enum lru_list lru

頁所在的 LRU 列表索引

int zid

計費頁的區域 ID

int nr_pages

新增時為正值,移除時為負值

描述

此函式必須在 `lru_lock` 下呼叫,恰好在將頁新增到 LRU 列表之前或從 LRU 列表移除頁之後。

unsigned long mem_cgroup_margin(struct mem_cgroup *memcg)

計算記憶體 cgroup 的可計費空間

引數

struct mem_cgroup *memcg

記憶體 cgroup

描述

返回 **mem** 可被計費的最大記憶體量,以頁為單位。

void mem_cgroup_print_oom_context(struct mem_cgroup *memcg, struct task_struct *p)

列印與記憶體控制器相關的 OOM 資訊。

引數

struct mem_cgroup *memcg

超出限制的記憶體 cgroup

struct task_struct *p

將被殺死的任務

注意

當層級啟用時,**memcg** 和 **p** 的 `mem_cgroup` 可能不同

void mem_cgroup_print_oom_meminfo(struct mem_cgroup *memcg)

列印與記憶體控制器相關的 OOM 記憶體資訊。

引數

struct mem_cgroup *memcg

超出限制的記憶體 cgroup

struct mem_cgroup *mem_cgroup_get_oom_group(struct task_struct *victim, struct mem_cgroup *oom_domain)

獲取記憶體 cgroup 以在 OOM 後清理

引數

struct task_struct *victim

將被 OOM killer 殺死的任務

struct mem_cgroup *oom_domain

memcg OOM 情況下的 memcg,系統範圍 OOM 情況下的 NULL

描述

返回指向記憶體 cgroup 的指標,該 cgroup 必須透過殺死所有屬於它的可被 OOM 殺死的任務來清理。

呼叫者必須對返回的非 NULL `memcg` 呼叫 `mem_cgroup_put()`。

bool consume_stock(struct mem_cgroup *memcg, unsigned int nr_pages)

嘗試消耗此 CPU 上的庫存電荷。

引數

struct mem_cgroup *memcg

要從中消耗的 memcg。

unsigned int nr_pages

要計費的頁數。

描述

如果存在足夠的 `nr_pages`,則消耗快取的電荷,否則返回失敗。如果計費請求大於 `MEMCG_CHARGE_BATCH` 或本地鎖已被佔用,則也返回失敗。

成功時返回 true,否則返回 false。

int __memcg_kmem_charge_page(struct page *page, gfp_t gfp, int order)

對當前記憶體 cgroup 計費一個 kmem 頁

引數

struct page *page

要計費的頁

gfp_t gfp

回收模式

int order

分配階

描述

成功時返回 0,失敗時返回錯誤碼。

void __memcg_kmem_uncharge_page(struct page *page, int order)

解除 kmem 頁的計費

引數

struct page *page

要解除計費的頁

int order

分配階

void mem_cgroup_wb_stats(struct bdi_writeback *wb, unsigned long *pfilepages, unsigned long *pheadroom, unsigned long *pdirty, unsigned long *pwriteback)

從其 memcg 中檢索與回寫相關的統計資訊

引數

struct bdi_writeback *wb

所查詢的 `bdi_writeback`

unsigned long *pfilepages

檔案頁數的輸出引數

unsigned long *pheadroom

根據 memcg 可分配頁數的輸出引數

unsigned long *pdirty

髒頁數的輸出引數

unsigned long *pwriteback

正在回寫頁數的輸出引數

描述

確定 **wb** 的 `memcg` 中檔案頁、餘量、髒頁和回寫頁的數量。檔案頁、髒頁和回寫頁不言自明。餘量則稍微複雜一些。

一個 `memcg` 的餘量是“min(最大值, 高閾值) - 已使用”。在層級中,餘量計算為自身和祖先的最低餘量。請注意,這不考慮系統中實際可用的記憶體量。呼叫者應相應地進一步限制 **\*pheadroom**。

struct mem_cgroup *mem_cgroup_from_id(unsigned short id)

從 memcg ID 查詢 memcg

引數

unsigned short id

要查詢的 memcg ID

描述

呼叫者必須持有 rcu_read_lock()

void mem_cgroup_css_reset(struct cgroup_subsys_state *css)

重置 mem_cgroup 的狀態

引數

struct cgroup_subsys_state *css

目標 css

描述

重置與 **css** 關聯的 `mem_cgroup` 的狀態。當用戶空間請求停用預設層級但 `memcg` 因依賴關係而被固定時,會呼叫此函式。`memcg` 應該停止應用策略,並恢復到原始狀態,因為它可能會再次變得可見。

當前的實現只重置了基本配置。這需要擴充套件以覆蓋所有可見部分。

void mem_cgroup_calculate_protection(struct mem_cgroup *root, struct mem_cgroup *memcg)

檢查記憶體消耗是否在正常範圍內

引數

struct mem_cgroup *root

正在檢查的子樹的頂層祖先

struct mem_cgroup *memcg

要檢查的記憶體 cgroup

描述

警告:此函式並非無狀態!它只能作為自上而下樹迭代的一部分使用,不能用於獨立查詢。

(此行已與 P299 合併以提高可讀性)

int mem_cgroup_charge_hugetlb(struct folio *folio, gfp_t gfp)

對 hugetlb Folio 收費 memcg

引數

struct folio *folio

正在計費的 Folio

gfp_t gfp

回收模式

描述

此函式在分配大頁 Folio 時呼叫,在頁已獲得並計費到適當的 hugetlb cgroup 控制器(如果已啟用)之後。

如果 memcg 已滿,返回 `ENOMEM`。如果計費成功或跳過計費,則返回 0。

int mem_cgroup_swapin_charge_folio(struct folio *folio, struct mm_struct *mm, gfp_t gfp, swp_entry_t entry)

為換入操作對新分配的 Folio 收費。

引數

struct folio *folio

要計費的 Folio。

struct mm_struct *mm

受害者的 mm 上下文

gfp_t gfp

回收模式

swp_entry_t entry

為之分配 Folio 的交換條目

描述

此函式對為換入分配的 Folio 進行計費。請在將 Folio 新增到交換快取之前呼叫此函式。

成功時返回 0。否則,返回錯誤碼。

void mem_cgroup_replace_folio(struct folio *old, struct folio *new)

對 Folio 的替換進行計費。

引數

struct folio *old

當前流通的 Folio。

struct folio *new

替換 Folio。

描述

將 **new** 作為 **old** 的替換 Folio 進行計費。**old** 將在釋放時取消計費。

兩個 Folio 都必須鎖定,**new->mapping** 必須已設定。

void mem_cgroup_migrate(struct folio *old, struct folio *new)

將 memcg 資料從舊 Folio 傳輸到新 Folio。

引數

struct folio *old

當前流通的 Folio。

struct folio *new

替換 Folio。

描述

為遷移將 `memcg` 資料從舊 Folio 傳輸到新 Folio。舊 Folio 的資料資訊將被清除。請注意,在此過程中記憶體計數器將保持不變。

兩個 Folio 都必須鎖定,**new->mapping** 必須已設定。

bool mem_cgroup_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages, gfp_t gfp_mask)

計費套接字記憶體

引數

struct mem_cgroup *memcg

要計費的 memcg

unsigned int nr_pages

要計費的頁數

gfp_t gfp_mask

回收模式

描述

將 **nr_pages** 計費到 **memcg**。如果計費符合 **memcg** 的配置限制,則返回 `true`,否則返回 `false`。

void mem_cgroup_uncharge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages)

解除套接字記憶體計費

引數

struct mem_cgroup *memcg

要解除計費的 memcg

unsigned int nr_pages

要解除計費的頁數

int __mem_cgroup_try_charge_swap(struct folio *folio, swp_entry_t entry)

嘗試對 Folio 的交換空間收費

引數

struct folio *folio

正在新增到交換區的 Folio

swp_entry_t entry

要計費的交換條目

描述

嘗試對 **folio** 的 `memcg` 計費 **entry** 處的交換空間。

成功時返回 0,失敗時返回 `-ENOMEM`。

void __mem_cgroup_uncharge_swap(swp_entry_t entry, unsigned int nr_pages)

解除交換空間計費

引數

swp_entry_t entry

要解除計費的交換條目

unsigned int nr_pages

要解除計費的交換空間量

bool obj_cgroup_may_zswap(struct obj_cgroup *objcg)

檢查此 cgroup 是否可以 `zswap`

引數

struct obj_cgroup *objcg

物件 cgroup

描述

檢查是否已達到分層 `zswap` 限制。

此函式不檢查具體的餘量,也不是原子操作。但對於 `zswap`,只有在壓縮發生後才知道分配的大小,這種樂觀的預檢查可以避免在已經沒有空間或 `zswap` 在層級中完全停用時在壓縮上浪費週期。

void obj_cgroup_charge_zswap(struct obj_cgroup *objcg, size_t size)

計費壓縮後端記憶體

引數

struct obj_cgroup *objcg

物件 cgroup

size_t size

壓縮物件的大小

描述

obj_cgroup_may_zswap() 允許此 cgroup 進行壓縮和 `zswap` 儲存之後,此函式強制進行計費。

void obj_cgroup_uncharge_zswap(struct obj_cgroup *objcg, size_t size)

解除壓縮後端記憶體計費

引數

struct obj_cgroup *objcg

物件 cgroup

size_t size

壓縮物件的大小

描述

在頁換入時解除 `zswap` 記憶體的計費。

void shmem_recalc_inode(struct inode *inode, long alloced, long swapped)

重新計算 inode 的塊使用情況

引數

struct inode *inode

要重新計算的 inode

long alloced

分配給 inode 的頁數變化

long swapped

從 inode 交換出的頁數變化

描述

我們必須計算空閒塊,因為 `mm` 可以在我們不知情的情況下刪除未髒化的空洞頁。

但通常 `info->alloced == inode->i_mapping->nrpages + info->swapped` 所以 `mm` 釋放的是 `info->alloced - (inode->i_mapping->nrpages + info->swapped)`

unsigned int shmem_mapping_size_orders(struct address_space *mapping, pgoff_t index, loff_t write_end)

獲取給定檔案大小允許的 Folio 階。

引數

struct address_space *mapping

目標 `address_space`。

pgoff_t index

頁索引。

loff_t write_end

寫入結束位置,可能會擴充套件 inode 大小。

描述

此函式根據對映在給定索引處當前允許的檔案大小返回 Folio 的大頁階(如果支援)。索引因對映可能具有的對齊考慮而相關。返回的階可能小於傳遞的大小。

返回

頁階。

int shmem_writeout(struct folio *folio, struct writeback_control *wbc)

將 Folio 寫入交換區

引數

struct folio *folio

要寫入的 Folio

struct writeback_control *wbc

如何進行回寫

描述

將 Folio 從頁快取移動到交換快取。

int shmem_get_folio(struct inode *inode, pgoff_t index, loff_t write_end, struct folio **foliop, enum sgp_type sgp)

查詢並鎖定一個 `shmem` Folio。

引數

struct inode *inode

要搜尋的 inode

pgoff_t index

頁面索引。

loff_t write_end

寫入結束,可以擴充套件inode大小

struct folio **foliop

如果找到,則指向folio的指標

enum sgp_type sgp

SGP_* 標誌用於控制行為

描述

inodeindex處查詢頁面快取條目。如果存在folio,則返回一個已鎖定且引用計數增加的folio。

如果呼叫者修改了folio中的資料,它必須在解鎖folio之前呼叫folio_mark_dirty(),以確保folio不會被回收。在呼叫folio_mark_dirty()之前無需保留空間。

當未找到folio時,行為取決於sgp
  • 對於SGP_READ,*foliopNULL,返回0

  • 對於SGP_NOALLOC,*foliopNULL,返回-ENOENT

  • 對於所有其他標誌,將分配一個新的folio,插入頁面快取,並以鎖定狀態返回到foliop中。

上下文

可能休眠。

返回

成功返回0,否則返回負錯誤程式碼。

struct file *shmem_kernel_file_setup(const char *name, loff_t size, unsigned long flags)

獲取一個駐留在tmpfs中且必須是核心內部的未連結檔案。不會對底層inode進行LSM許可權檢查。因此,此介面的使用者必須在更高層進行LSM檢查。使用者包括big_key和shm實現。LSM檢查在key或shm級別提供,而非inode級別。

引數

const char *name

dentry的名稱(將在/proc/<pid>/maps中可見)

loff_t size

要為檔案設定的大小

unsigned long flags

VM_NORESERVE 禁止預先計算整個物件大小

struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags)

獲取一個駐留在tmpfs中的未連結檔案

引數

const char *name

dentry的名稱(將在/proc/<pid>/maps中可見)

loff_t size

要為檔案設定的大小

unsigned long flags

VM_NORESERVE 禁止預先計算整個物件大小

struct file *shmem_file_setup_with_mnt(struct vfsmount *mnt, const char *name, loff_t size, unsigned long flags)

獲取一個駐留在tmpfs中的未連結檔案

引數

struct vfsmount *mnt

檔案將被建立的tmpfs掛載點

const char *name

dentry的名稱(將在/proc/<pid>/maps中可見)

loff_t size

要為檔案設定的大小

unsigned long flags

VM_NORESERVE 禁止預先計算整個物件大小

int shmem_zero_setup(struct vm_area_struct *vma)

設定共享匿名對映

引數

struct vm_area_struct *vma

待mmap的vma由do_mmap準備

struct folio *shmem_read_folio_gfp(struct address_space *mapping, pgoff_t index, gfp_t gfp)

讀入頁快取,使用指定的頁分配標誌。

引數

struct address_space *mapping

folio的address_space

pgoff_t index

folio索引

gfp_t gfp

如果進行分配,使用的頁分配器標誌

描述

這行為類似於tmpfs的“read_cache_page_gfp(mapping, index, gfp)”,其中所有新的頁面分配都使用指定的分配標誌完成。但read_cache_page_gfp()使用->read_folio()方法:這不適合tmpfs,因為它可能在swapcache中有頁面,並且需要自行找到這些頁面;儘管drivers/gpu/drm i915和ttm依賴於此支援。

i915_gem_object_get_pages_gtt()將__GFP_NORETRY | __GFP_NOWARN與mapping_gfp_mask()混合使用,以避免不必要地導致機器OOM。

int migrate_vma_setup(struct migrate_vma *args)

準備遷移記憶體範圍

引數

struct migrate_vma *args

包含vma、start和用於遷移的pfns陣列

返回

失敗時返回負數errno,0表示遷移了0個或更多頁面且無錯誤。

描述

透過收集範圍內的每個虛擬地址所支援的所有頁面,並將它們儲存在src陣列中,從而準備遷移一段記憶體虛擬地址範圍。然後鎖定這些頁面並取消對映它們。一旦頁面被鎖定和取消對映,檢查每個頁面是否被固定。未被固定的頁面在相應的src陣列條目中設定了MIGRATE_PFN_MIGRATE標誌(由本函式設定)。然後透過重新對映和解鎖這些頁面來恢復任何被固定的頁面。

呼叫者隨後應為所有這些條目(即設定了MIGRATE_PFN_VALID和MIGRATE_PFN_MIGRATE標誌的條目)分配目標記憶體並將源記憶體複製到其中。一旦這些被分配和複製,呼叫者必須使用目標頁面的pfn值和MIGRATE_PFN_VALID更新dst陣列中每個相應的條目。目標頁面必須透過lock_page()鎖定。

請注意,除非是從裝置記憶體遷移到系統記憶體,否則呼叫者不必遷移src陣列中標記有MIGRATE_PFN_MIGRATE標誌的所有頁面。如果呼叫者無法將裝置頁面遷移回系統記憶體,則必須返回VM_FAULT_SIGBUS,這會對使用者空間程序造成嚴重後果,因此應儘可能避免。

對於CPU頁表(pte_none()或pmd_none()為true)中的空條目,我們確實在相應的源陣列中設定了MIGRATE_PFN_MIGRATE標誌,從而允許呼叫者為那些未被支援的虛擬地址分配裝置記憶體。為此,呼叫者只需分配裝置記憶體並像常規遷移一樣正確設定目標條目。請注意,這仍然可能失敗,因此在裝置驅動程式內部,您必須在呼叫migrate_vma_pages()之後檢查這些條目的遷移是否成功,就像常規遷移一樣。

之後,呼叫者必須呼叫migrate_vma_pages(),遍歷src陣列中所有設定了MIGRATE_PFN_VALID和MIGRATE_PFN_MIGRATE標誌的條目。如果dst陣列中的相應條目設定了MIGRATE_PFN_VALID標誌,則migrate_vma_pages()會將struct page資訊從源struct page遷移到目標struct page。如果遷移struct page資訊失敗,則清除src陣列中的MIGRATE_PFN_MIGRATE標誌。

此時,所有成功遷移的頁面在src陣列中都有一個設定了MIGRATE_PFN_VALID和MIGRATE_PFN_MIGRATE標誌的條目,並且dst陣列條目設定了MIGRATE_PFN_VALID標誌。

一旦migrate_vma_pages()返回,呼叫者可以檢查哪些頁面成功遷移,哪些沒有。成功遷移的頁面將在其src陣列條目中設定MIGRATE_PFN_MIGRATE標誌。

migrate_vma_pages()之後更新裝置頁表是安全的,因為目標頁面和源頁面都仍然被鎖定,並且mmap_lock以讀模式持有(因此沒有人可以取消對映正在遷移的範圍)。

一旦呼叫者完成清理工作並更新其頁表(如果選擇這樣做,這不是強制的),它最終會呼叫migrate_vma_finalize(),更新CPU頁表以指向成功遷移頁面的新頁面,或者恢復CPU頁表以指向原始源頁面。

void migrate_device_pages(unsigned long *src_pfns, unsigned long *dst_pfns, unsigned long npages)

將元資料從源頁遷移到目標頁

引數

unsigned long *src_pfns

migrate_device_range()返回的src_pfns

unsigned long *dst_pfns

驅動程式為遷移記憶體而分配的pfns陣列

unsigned long npages

範圍內的頁數

描述

相當於migrate_vma_pages()。這被呼叫以將struct page元資料從源struct page遷移到目標。struct page。

void migrate_vma_pages(struct migrate_vma *migrate)

將元資料從源頁遷移到目標頁

引數

struct migrate_vma *migrate

包含所有遷移資訊的遷移結構體

描述

這會將struct page元資料從源struct page遷移到目標struct page。這有效地完成了從源頁到目標頁的遷移。

void migrate_vma_finalize(struct migrate_vma *migrate)

恢復CPU頁表條目

引數

struct migrate_vma *migrate

包含所有遷移資訊的遷移結構體

描述

如果該頁遷移成功,則將其特殊的遷移pte條目替換為指向新頁的對映;否則,恢復為指向原始源頁的CPU頁表。

這還會解鎖頁面並將其放回lru,或者對於裝置頁面,減少額外的引用計數。

int migrate_device_range(unsigned long *src_pfns, unsigned long start, unsigned long npages)

將裝置私有pfns遷移到普通記憶體。

引數

unsigned long *src_pfns

足夠大的陣列,用於儲存遷移的源裝置私有pfns。

unsigned long start

要遷移範圍中的起始pfn。

unsigned long npages

要遷移的頁數。

描述

migrate_vma_setup()在概念上類似於migrate_vma_setup(),不同之處在於它不基於虛擬地址對映查詢頁面,而是使用一個應遷移到系統記憶體的裝置pfns範圍。

當驅動程式需要釋放裝置記憶體但不知道裝置記憶體中可能存在的每個頁面的虛擬對映時,這很有用。例如,當驅動程式正在解除安裝或從裝置解綁時,通常會出現這種情況。

migrate_vma_setup()一樣,此函式將在取消對映任何未空閒的遷移頁面之前,獲取其引用並鎖定它們。然後,驅動程式可以分配目標頁面並開始將資料從裝置複製到CPU記憶體,然後再呼叫migrate_device_pages()

int migrate_device_pfns(unsigned long *src_pfns, unsigned long npages)

將裝置私有pfns遷移到普通記憶體。

引數

unsigned long *src_pfns

預填充的要遷移的源裝置私有pfns陣列。

unsigned long npages

要遷移的頁數。

描述

migrate_device_range()類似,但支援非連續的預填充裝置頁面陣列進行遷移。

struct wp_walk

pagetable遍歷回撥的私有結構體

定義:

struct wp_walk {
    struct mmu_notifier_range range;
    unsigned long tlbflush_start;
    unsigned long tlbflush_end;
    unsigned long total;
};

成員

範圍

mmu通知器的範圍

tlbflush_start

第一個修改過的pte的地址

tlbflush_end

最後一個修改過的pte的地址 + 1

total

修改過的pte總數

int wp_pte(pte_t *pte, unsigned long addr, unsigned long end, struct mm_walk *walk)

防寫一個pte

引數

pte_t *pte

指向pte的指標

unsigned long addr

保護虛擬地址的起始

unsigned long end

保護虛擬地址的結束

struct mm_walk *walk

頁表遍歷回撥引數

描述

該函式防寫一個pte並記錄被觸及pte在虛擬地址空間中的範圍,以便進行高效的TLB重新整理。

struct clean_walk

clean_record_pte 函式的私有結構體。

定義:

struct clean_walk {
    struct wp_walk base;
    pgoff_t bitmap_pgoff;
    unsigned long *bitmap;
    pgoff_t start;
    pgoff_t end;
};

成員

基址

我們從中派生的struct wp_walk

bitmap_pgoff

bitmap中第一個位的地址空間頁面偏移量

點陣圖

點陣圖,地址空間覆蓋範圍內的每個頁面偏移量對應一位。

起始

相對於bitmap_pgoff的第一個修改過的pte的address_space頁面偏移量

結束

相對於bitmap_pgoff的最後一個修改過的pte的address_space頁面偏移量

int clean_record_pte(pte_t *pte, unsigned long addr, unsigned long end, struct mm_walk *walk)

清除pte並在點陣圖中記錄其地址空間偏移量

引數

pte_t *pte

指向pte的指標

unsigned long addr

要清除的虛擬地址的起始

unsigned long end

要清除的虛擬地址的結束

struct mm_walk *walk

頁表遍歷回撥引數

描述

該函式清除一個pte並記錄被觸及pte在虛擬地址空間中的範圍,以便進行高效的TLB重新整理。它還在點陣圖中記錄髒pte,位圖表示address_space中的頁面偏移量,以及被觸及位的第一個和最後一個。

unsigned long wp_shared_mapping_range(struct address_space *mapping, pgoff_t first_index, pgoff_t nr)

防寫地址空間範圍內的所有pte

引數

struct address_space *mapping

我們要防寫的address_space

pgoff_t first_index

範圍中的第一個頁面偏移量

pgoff_t nr

要覆蓋的增量頁面偏移量數量

注意

此函式當前跳過巨頁表條目,因為它旨在用於PTE級別的髒跟蹤。但是,它會在遇到啟用寫許可權的巨頁條目時發出警告,並且可以很容易地擴充套件以處理它們。

返回

實際防寫的pte數量。請注意,已經防寫的pte不計數在內。

unsigned long clean_record_shared_mapping_range(struct address_space *mapping, pgoff_t first_index, pgoff_t nr, pgoff_t bitmap_pgoff, unsigned long *bitmap, pgoff_t *start, pgoff_t *end)

清除並記錄地址空間範圍內的所有pte

引數

struct address_space *mapping

我們要清理的address_space

pgoff_t first_index

範圍中的第一個頁面偏移量

pgoff_t nr

要覆蓋的增量頁面偏移量數量

pgoff_t bitmap_pgoff

bitmap中第一個位的頁面偏移量

unsigned long *bitmap

指向至少nr位的點陣圖的指標。該點陣圖需要覆蓋整個範圍first_index..**first_index** + nr

pgoff_t *start

指向bitmap中第一個設定位的編號的指標。當函式設定新位時,該值會被修改。

pgoff_t *end

指向bitmap中最後一個設定位的編號的指標。未設定。當函式設定新位時,該值會被修改。

描述

當此函式返回時,不能保證CPU尚未使新的pte變髒。但是它不會清除點陣圖中未報告的任何pte。保證如下:

  • 函式開始執行時所有髒pte最終都將被記錄在點陣圖中。

  • 此後所有變髒的pte要麼保持髒狀態,要麼被記錄在點陣圖中,或者兩者兼有。

如果呼叫者需要確保所有髒pte都被捕獲並且沒有額外新增,它首先需要防寫地址空間範圍,並確保在page_mkwrite()或pfn_mkwrite()中阻塞新的寫入者。然後,在防寫之後的TLB重新整理之後捕獲所有髒位。

此函式當前跳過巨頁表條目,因為它旨在用於PTE級別的髒跟蹤。但是,它會在遇到巨頁髒條目時發出警告,並且可以很容易地擴充套件以處理它們。

返回

實際清除的髒pte數量。

bool pcpu_addr_in_chunk(struct pcpu_chunk *chunk, void *addr)

檢查地址是否由該塊提供

引數

struct pcpu_chunk *chunk

感興趣的塊

void *addr

percpu地址

返回

如果地址由該塊提供,則為真。

bool pcpu_check_block_hint(struct pcpu_block_md *block, int bits, size_t align)

根據連續性提示進行檢查

引數

struct pcpu_block_md *block

感興趣的塊

int bits

分配大小

size_t align

區域對齊方式(最大PAGE_SIZE)

描述

檢查分配是否能適應塊的連續提示。請注意,一個chunk使用與塊相同的提示,因此這也可以針對chunk的連續提示進行檢查。

void pcpu_next_md_free_region(struct pcpu_chunk *chunk, int *bit_off, int *bits)

查詢下一個提示空閒區域

引數

struct pcpu_chunk *chunk

感興趣的塊

int *bit_off

塊偏移

int *bits

空閒區域大小

描述

pcpu_for_each_md_free_region 的輔助函式。它檢查 block->contig_hint 並執行跨塊聚合以找到下一個提示。它就地修改 bit_off 和 bits,以便在迴圈中使用。

void pcpu_next_fit_region(struct pcpu_chunk *chunk, int alloc_bits, int align, int *bit_off, int *bits)

為給定分配請求查詢合適的區域

引數

struct pcpu_chunk *chunk

感興趣的塊

int alloc_bits

分配大小

int align

區域對齊方式(最大PAGE_SIZE)

int *bit_off

塊偏移

int *bits

空閒區域大小

描述

查詢下一個可用於給定大小和對齊的空閒區域。僅當存在可用於此分配的有效區域時才返回。如果分配請求適合該塊,則返回 block->first_free,以檢視請求是否可以在連續提示之前得到滿足。

void *pcpu_mem_zalloc(size_t size, gfp_t gfp)

分配記憶體

引數

size_t size

要分配的位元組數

gfp_t gfp

分配標誌

描述

分配size位元組。如果size小於PAGE_SIZE,則使用kzalloc();否則,使用vzalloc()的等效項。這是為了方便傳遞白名單標誌。返回的記憶體總是被清零的。

返回

成功時返回指向已分配區域的指標,失敗時返回NULL。

void pcpu_mem_free(void *ptr)

釋放記憶體

引數

void *ptr

要釋放的記憶體

描述

釋放ptrptr應該已使用pcpu_mem_zalloc()分配。

void pcpu_chunk_relocate(struct pcpu_chunk *chunk, int oslot)

將chunk放置到適當的chunk槽位中

引數

struct pcpu_chunk *chunk

感興趣的塊

int oslot

它之前所在的槽位

描述

此函式在分配或釋放改變了chunk之後被呼叫。根據改變後的狀態確定新的槽位,並將chunk移動到該槽位。請注意,保留的chunk絕不會被放置在chunk槽位中。

上下文

pcpu_lock。

void pcpu_block_update(struct pcpu_block_md *block, int start, int end)

根據空閒區域更新塊

引數

struct pcpu_block_md *block

感興趣的塊

int start

塊內起始偏移量

int end

塊內結束偏移量

描述

根據已知空閒區域更新塊。區域[start, end)預期是塊內空閒區域的全部。如果連續提示相等,則選擇最佳起始偏移量。

void pcpu_chunk_refresh_hint(struct pcpu_chunk *chunk, bool full_scan)

更新塊的元資料

引數

struct pcpu_chunk *chunk

感興趣的塊

bool full_scan

是否應該從頭開始掃描

描述

遍歷元資料塊以找到最大的連續區域。在分配路徑上可以避免完全掃描,因為這會在我們破壞連續提示時觸發。這樣做,scan_hint將在contig_hint之前,或者在scan_hint == contig_hint時在之後。在釋放時無法阻止這種情況,因為我們希望找到可能跨塊的最大區域。

void pcpu_block_refresh_hint(struct pcpu_chunk *chunk, int index)

引數

struct pcpu_chunk *chunk

感興趣的塊

int index

元資料塊的索引

描述

從first_free開始掃描該塊,並相應地更新塊元資料。

void pcpu_block_update_hint_alloc(struct pcpu_chunk *chunk, int bit_off, int bits)

在分配路徑上更新提示

引數

struct pcpu_chunk *chunk

感興趣的塊

int bit_off

塊偏移

int bits

請求大小

描述

更新分配路徑的元資料。僅當chunk的連續提示被破壞時,才需要透過完全掃描來重新整理元資料。如果塊的連續提示被破壞,則需要進行塊級掃描。

void pcpu_block_update_hint_free(struct pcpu_chunk *chunk, int bit_off, int bits)

在釋放路徑上更新塊提示

引數

struct pcpu_chunk *chunk

感興趣的塊

int bit_off

塊偏移

int bits

請求大小

描述

更新分配路徑的元資料。這透過利用塊的連續提示來避免盲目塊重新整理。如果失敗,它將向前和向後掃描以確定空閒區域的範圍。這限制在塊的邊界。

如果一個頁面變為空閒、一個塊變為空閒或空閒區域跨越塊,則會觸發塊更新。這種權衡是為了最大限度地減少遍歷塊元資料以更新 chunk_md->contig_hint。chunk_md->contig_hint 可能最多相差一個頁面,但它永遠不會超過可用空間。如果連續提示包含在一個塊中,它將是準確的。

bool pcpu_is_populated(struct pcpu_chunk *chunk, int bit_off, int bits, int *next_off)

判斷區域是否已填充

引數

struct pcpu_chunk *chunk

感興趣的塊

int bit_off

塊偏移

int bits

區域大小

int *next_off

下一個開始搜尋的偏移量的返回值

描述

對於原子分配,檢查支援頁面是否已填充。

返回

如果支援頁面已填充,則為布林值。next_index 用於跳過 pcpu_find_block_fit 中未填充的塊。

int pcpu_find_block_fit(struct pcpu_chunk *chunk, int alloc_bits, size_t align, bool pop_only)

找到要開始搜尋的塊索引

引數

struct pcpu_chunk *chunk

感興趣的塊

int alloc_bits

分配單元中的請求大小

size_t align

區域對齊方式(最大PAGE_SIZE位元組)

bool pop_only

僅使用已填充區域

描述

給定一個塊和一個分配規範,找到開始搜尋空閒區域的偏移量。這會遍歷點陣圖元資料塊,以找到保證符合要求的偏移量。它並不完全是首次適應,因為如果分配不適合塊或塊的連續提示,它就會被跳過。這傾向於謹慎,以防止過度迭代。糟糕的對齊可能會導致分配器跳過具有有效空閒區域的塊和塊。

返回

點陣圖中開始搜尋的偏移量。如果未找到偏移量,則為-1。

int pcpu_alloc_area(struct pcpu_chunk *chunk, int alloc_bits, size_t align, int start)

從一個pcpu_chunk分配一個區域

引數

struct pcpu_chunk *chunk

感興趣的塊

int alloc_bits

分配單元中的請求大小

size_t align

區域對齊方式(最大PAGE_SIZE)

int start

bit_off 開始搜尋

描述

此函式接收一個start偏移量,以便開始搜尋以適應具有align對齊方式的alloc_bits分配。它需要掃描分配對映,因為如果它符合塊的連續提示,start將是block->first_free。這是在破壞連續提示之前嘗試填充分配。如果確認有效的空閒區域,分配和邊界對映會相應更新。

返回

成功時返回chunk中已分配地址的偏移量。如果未找到匹配區域,則返回-1。

int pcpu_free_area(struct pcpu_chunk *chunk, int off)

釋放相應的偏移量

引數

struct pcpu_chunk *chunk

感興趣的塊

int off

地址相對於chunk的偏移量

描述

此函式使用邊界點陣圖確定要釋放的分配大小,並清除分配對映。

返回

已釋放的位元組數。

struct pcpu_chunk *pcpu_alloc_first_chunk(unsigned long tmp_addr, int map_size)

建立服務於第一個塊的塊

引數

unsigned long tmp_addr

服務區域的起始地址

int map_size

服務區域的大小

描述

此函式負責建立服務於第一個塊的塊。base_addr是tmp_addr頁對齊向下舍入的地址,而區域結束是頁對齊向上舍入的地址。跟蹤偏移量以確定服務區域。所有這些都是為了滿足點陣圖分配器,避免部分塊。

返回

服務於tmp_addrmap_size大小區域的塊。

void pcpu_chunk_populated(struct pcpu_chunk *chunk, int page_start, int page_end)

填充後整理

引數

struct pcpu_chunk *chunk

被填充的pcpu_chunk

int page_start

起始頁

int page_end

結束頁

描述

範圍[page_start,**page_end**)中的頁面已填充到chunk中。相應地更新記賬資訊。每次成功填充後必須呼叫。

void pcpu_chunk_depopulated(struct pcpu_chunk *chunk, int page_start, int page_end)

取消填充後整理

引數

struct pcpu_chunk *chunk

被取消填充的pcpu_chunk

int page_start

起始頁

int page_end

結束頁

描述

範圍[page_start,**page_end**)中的頁面已從chunk中取消填充。相應地更新記賬資訊。每次成功取消填充後必須呼叫。

確定包含指定地址的塊

引數

void *addr

需要確定其塊的地址。

描述

這是一個內部函式,處理除靜態分配之外的所有情況。靜態percpu地址值絕不應傳遞給分配器。

返回

找到的塊的地址。

void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved, gfp_t gfp)

percpu 分配器

引數

size_t size

要分配區域的位元組大小

size_t align

區域對齊方式(最大PAGE_SIZE)

bool reserved

如果可用,從保留塊分配

gfp_t gfp

分配標誌

描述

分配大小為size位元組、對齊方式為align的percpu區域。如果gfp不包含GFP_KERNEL,則分配是原子性的。如果gfp包含__GFP_NOWARN,則在無效或失敗的分配請求上不會觸發警告。

返回

成功時返回指向已分配區域的percpu指標,失敗時返回NULL。

void pcpu_balance_free(bool empty_only)

管理空閒塊的數量

引數

bool empty_only

僅當沒有已填充頁面時才釋放塊

描述

如果empty_only為false,則無論已填充頁面的數量如何,都回收所有完全空閒的塊。否則,僅回收沒有已填充頁面的塊。

上下文

pcpu_lock(可暫時釋放)

void pcpu_balance_populated(void)

管理已填充頁面的數量

引數

void

無引數

描述

維護一定數量的已填充頁面以滿足原子分配。有可能會在物理記憶體不足時呼叫此函式,從而觸發OOM killer。我們應該避免這樣做,直到實際分配導致失敗,因為請求可能從已支援的區域提供服務。

上下文

pcpu_lock(可暫時釋放)

void pcpu_reclaim_populated(void)

掃描待取消填充的塊並釋放空閒頁面

引數

void

無引數

描述

掃描待取消填充列表中的塊,並嘗試將未使用的已填充頁面釋放回系統。取消填充的塊被擱置,以防止除非必要時才重新填充這些頁面。完全空閒的塊被重新整合並相應地釋放(保留1個)。如果低於空閒已填充頁面閾值,則如果塊有空閒頁面,則重新整合該塊。每個塊都以相反的順序掃描,以使已填充頁面靠近塊的起始處。

上下文

pcpu_lock(可暫時釋放)

void pcpu_balance_workfn(struct work_struct *work)

管理空閒塊和已填充頁面的數量

引數

struct work_struct *work

未使用

描述

對於每種塊型別,管理完全空閒塊的數量和已填充頁面的數量。一個重要的考慮因素是頁面何時被釋放以及它們如何對全域性計數做出貢獻。

void free_percpu(void __percpu *ptr)

釋放percpu區域

引數

void __percpu *ptr

指向要釋放區域的指標

描述

釋放percpu區域ptr

上下文

可以在原子上下文呼叫。

bool is_kernel_percpu_address(unsigned long addr)

測試地址是否來自靜態percpu區域

引數

unsigned long addr

待測試地址

描述

測試addr是否屬於核心靜態percpu區域。模組靜態percpu區域不考慮在內。對於那些,請使用is_module_percpu_address()。

返回

如果addr來自核心靜態percpu區域,則為true,否則為false

phys_addr_t per_cpu_ptr_to_phys(void *addr)

將已翻譯的percpu地址轉換為物理地址

引數

void *addr

要轉換為物理地址的地址

描述

給定透過percpu訪問宏之一獲取的addr(可解引用地址),此函式將其轉換為物理地址。呼叫者負責確保在函式完成之前addr保持有效。

percpu分配器為第一個塊進行了特殊設定,目前支援線性地址空間嵌入或vmalloc對映,從第二個塊開始,由後端分配器(當前為vm或km)提供轉換。

地址可以簡單地翻譯,而無需檢查它是否落在第一個塊中。但當前程式碼更好地反映了percpu分配器實際工作的方式,並且驗證可以發現percpu分配器本身以及per_cpu_ptr_to_phys()呼叫者中的錯誤。因此我們保留了當前程式碼。

返回

addr的物理地址。

struct pcpu_alloc_info *pcpu_alloc_alloc_info(int nr_groups, int nr_units)

分配percpu分配資訊

引數

int nr_groups

組的數量

int nr_units

單元的數量

描述

分配ai,它足夠大,可容納nr_groups個組,每個組包含nr_units個單元。返回的ai的groups[0].cpu_map指向cpu_map陣列,該陣列長度足夠容納nr_units,並用NR_CPUS填充。初始化其他組的cpu_map指標是呼叫者的責任。

返回

成功時返回指向已分配的pcpu_alloc_info的指標,失敗時返回NULL。

void pcpu_free_alloc_info(struct pcpu_alloc_info *ai)

釋放percpu分配資訊

引數

struct pcpu_alloc_info *ai

要釋放的pcpu_alloc_info

描述

釋放由pcpu_alloc_alloc_info()分配的ai

void pcpu_dump_alloc_info(const char *lvl, const struct pcpu_alloc_info *ai)

列印pcpu_alloc_info的資訊

引數

const char *lvl

日誌級別

const struct pcpu_alloc_info *ai

要轉儲的分配資訊

描述

使用日誌級別lvl列印ai的資訊。

void pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai, void *base_addr)

初始化第一個percpu塊

引數

const struct pcpu_alloc_info *ai

描述percpu區域形狀的pcpu_alloc_info

void *base_addr

對映地址

描述

初始化包含核心靜態percpu區域的第一個percpu塊。此函式應從arch percpu區域設定路徑中呼叫。

ai包含了初始化第一個塊並啟動動態percpu分配器所需的所有資訊。

ai->static_size 是靜態percpu區域的大小。

ai->reserved_size,如果非零,則指定在第一個塊的靜態區域之後保留的位元組數。這會保留第一個塊,使其僅透過保留的percpu分配可用。這主要用於在定址模型對符號重定位的偏移範圍有限的架構上為模組percpu靜態區域提供服務,以保證模組percpu符號落在可重定位範圍內。

ai->dyn_size 確定第一個塊中可用於動態分配的位元組數。ai->static_size + ai->reserved_size + ai->dyn_sizeai->unit_size 之間的區域未被使用。

ai->unit_size 指定單元大小,並且必須對齊到PAGE_SIZE,且大於或等於ai->static_size + ai->reserved_size + ai->dyn_size

ai->atom_size 是分配原子大小,用作vm區域的對齊方式。

ai->alloc_size 是分配大小,並且總是ai->atom_size的倍數。如果ai->unit_size大於ai->atom_size,則此值大於ai->atom_size

ai->nr_groupsai->groups 描述了 percpu 區域的虛擬記憶體佈局。應該放在一起的單元被放在同一個組中。動態 VM 區域將根據這些分組進行分配。如果 ai->nr_groups 為零,則假定只有一個組包含所有單元。

呼叫者應該已經將第一個塊對映到base_addr並複製靜態資料到每個單元。

第一個塊將始終包含一個靜態區域和一個動態區域。然而,靜態區域不受任何塊的管理。如果第一個塊還包含一個保留區域,則它由兩個塊提供服務——一個用於保留區域,一個用於動態區域。它們共享相同的VM,但在區域分配圖中使用了偏移區域。服務於動態區域的塊在塊槽中迴圈,並且像任何其他塊一樣可用於動態分配。

struct pcpu_alloc_info *pcpu_build_alloc_info(size_t reserved_size, size_t dyn_size, size_t atom_size, pcpu_fc_cpu_distance_fn_t cpu_distance_fn)

構建alloc_info時考慮CPU之間的距離

引數

size_t reserved_size

保留percpu區域的位元組大小

size_t dyn_size

動態分配的最小空閒位元組大小

size_t atom_size

分配原子大小

pcpu_fc_cpu_distance_fn_t cpu_distance_fn

確定CPU之間距離的回撥,可選

描述

此函式根據所需的percpu大小、分配原子大小以及CPU之間的距離,確定單元的分組、它們到CPU的對映以及其他引數。

組總是原子大小的倍數,並且雙向 LOCAL_DISTANCE 的 CPU 會被分組在一起,並在同一個組中共享單元空間。返回的配置保證不同節點的 CPU 在不同的組中,並且已分配虛擬地址空間的使用率 >= 75%。

返回

成功時,返回指向新allocation_info的指標。失敗時,返回ERR_PTR值。

int pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size, size_t atom_size, pcpu_fc_cpu_distance_fn_t cpu_distance_fn, pcpu_fc_cpu_to_node_fn_t cpu_to_nd_fn)

將第一個percpu塊嵌入到bootmem中

引數

size_t reserved_size

保留percpu區域的位元組大小

size_t dyn_size

動態分配的最小空閒位元組大小

size_t atom_size

分配原子大小

pcpu_fc_cpu_distance_fn_t cpu_distance_fn

確定CPU之間距離的回撥,可選

pcpu_fc_cpu_to_node_fn_t cpu_to_nd_fn

將CPU轉換為其節點的 callback,可選

描述

這是一個有助於簡化設定嵌入式第一個percpu塊的輔助函式,可以在預期呼叫pcpu_setup_first_chunk()的地方呼叫。

如果此函式用於設定第一個資料塊,它透過呼叫 pcpu_fc_alloc 進行分配並按原樣使用,不對映到 vmalloc 區域。分配始終是 atom_size 的整數倍,並與 atom_size 對齊。

這使得第一個資料塊可以利用線性物理對映(通常使用更大的頁大小)。請注意,這可能導致 NUMA 機器上 cpu->unit 對映非常稀疏,從而需要較大的 vmalloc 地址空間。如果 vmalloc 空間沒有比節點記憶體地址之間的距離大幾個數量級(例如 32 位 NUMA 機器),請勿使用此分配器。

dyn_size 指定最小動態區域大小。

如果所需大小小於最小或指定單元大小,剩餘部分將使用 pcpu_fc_free 返回。

返回

成功時返回 0,失敗時返回 -errno。

int pcpu_page_first_chunk(size_t reserved_size, pcpu_fc_cpu_to_node_fn_t cpu_to_nd_fn)

使用 PAGE_SIZE 頁面對映第一個資料塊

引數

size_t reserved_size

保留percpu區域的位元組大小

pcpu_fc_cpu_to_node_fn_t cpu_to_nd_fn

將CPU轉換為其節點的 callback,可選

描述

這是一個輔助函式,用於簡化設定頁面重新對映的第一個 percpu 資料塊,可以在預期呼叫 pcpu_setup_first_chunk() 的地方呼叫。

這是基本的分配器。靜態 percpu 區域逐頁分配到 vmalloc 區域。

返回

成功時返回 0,失敗時返回 -errno。

long copy_from_user_nofault(void *dst, const void __user *src, size_t size)

安全地嘗試從使用者空間位置讀取

引數

void *dst

指向接收資料的緩衝區的指標

const void __user *src

要讀取的地址。這必須是一個使用者地址。

size_t size

資料塊的大小

描述

安全地將資料從使用者地址 src 讀取到 **dst** 處的緩衝區。如果發生核心故障,請處理並返回 -EFAULT。

long copy_to_user_nofault(void __user *dst, const void *src, size_t size)

安全地嘗試寫入使用者空間位置

引數

void __user *dst

要寫入的地址

const void *src

指向要寫入資料的指標

size_t size

資料塊的大小

描述

安全地將資料從 **src** 處的緩衝區寫入 **dst** 地址。如果發生核心故障,請處理並返回 -EFAULT。

long strncpy_from_user_nofault(char *dst, const void __user *unsafe_addr, long count)
  • 從不安全的使用者地址複製以 NUL 結尾的字串。

引數

char *dst

目標地址,位於核心空間。此緩衝區長度必須至少為 count 位元組。

const void __user *unsafe_addr

不安全的使用者地址。

long count

要複製的最大位元組數,包括尾隨的 NUL 字元。

描述

將以 NUL 結尾的字串從不安全的使用者地址複製到核心緩衝區。

成功時,返回字串的長度,包括尾隨的 NUL 字元。

如果訪問失敗,返回 -EFAULT(可能已複製部分資料並添加了尾隨的 NUL 字元)。

如果 count 小於字串的長度,則複製 count-1 位元組,將 **dst** 緩衝區的最後一個位元組設定為 NUL,並返回 count

long strnlen_user_nofault(const void __user *unsafe_addr, long count)
  • 獲取使用者字串的大小,包括最後的 NUL 字元。

引數

const void __user *unsafe_addr

要測量的字串。

long count

最大計數(包括 NUL)

描述

獲取使用者空間中以 NUL 結尾的字串的大小,不會引發頁面錯誤。

返回字串的大小,包括終止 NUL 字元。

如果字串過長,返回一個大於 count 的數字。使用者必須檢查返回值是否“大於 count”。發生異常(或無效計數)時,返回 0。

與 strnlen_user 不同,此函式可用於 IRQ 處理程式等,因為它停用了頁面錯誤。

bool writeback_throttling_sane(struct scan_control *sc)

常規的髒頁限流機制是否可用?

引數

struct scan_control *sc

所涉及的 scan_control

描述

balance_dirty_pages() 中的常規髒頁限流機制在舊版 memcg 下完全失效,而是使用 shrink_folio_list() 中的直接停滯進行限流,這缺少了公平性、自適應暫停、頻寬比例分配和可配置性等所有優點。

此函式測試當前正在進行的 vmscan 是否可以假定正常的髒頁限流機制正在執行。

unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru, int zone_idx)

返回給定 LRU 列表上的頁數。

引數

struct lruvec *lruvec

LRU 向量

enum lru_list lru

要使用的 LRU

int zone_idx

要考慮的區域(使用 MAX_NR_ZONES - 1 表示整個 LRU 列表)

long remove_mapping(struct address_space *mapping, struct folio *folio)

嘗試從其對映中移除一個 folio。

引數

struct address_space *mapping

地址空間。

struct folio *folio

要移除的 folio。

描述

如果 folio 是髒的、正在回寫中,或者有其他引用,則移除將失敗。

返回

從對映中移除的頁數。如果 folio 無法移除,則返回 0。

上下文

呼叫者應該對該 folio 有一個引用計數並持有其鎖。

void folio_putback_lru(struct folio *folio)

將先前隔離的 folio 放回適當的 LRU 列表。

引數

struct folio *folio

要返回到 LRU 列表的 folio。

描述

將先前隔離的 folio 新增到適當的 LRU 列表。由於其他原因,該 folio 可能仍然無法被回收。

上下文

lru_lock 不得被持有,中斷必須啟用。

bool folio_isolate_lru(struct folio *folio)

嘗試從 LRU 列表中隔離一個 folio。

引數

struct folio *folio

要從 LRU 列表中隔離的 folio。

描述

從 LRU 列表中隔離一個 folio 並調整與該 folio 所在的 LRU 列表相對應的 vmstat 統計資訊。

該 folio 的 LRU 標誌將被清除。如果它在活動列表中,其 Active 標誌將被設定。如果它在不可回收列表中,其 Unevictable 標誌將被設定。在釋放頁面之前,呼叫者可能需要清除這些標誌。

  1. 呼叫時必須增加 folio 的引用計數。這與 isolate_lru_folios()(在沒有穩定引用的情況下呼叫)存在根本區別。

  2. lru_lock 不得被持有。

  3. 中斷必須啟用。

上下文

返回

如果 folio 已從 LRU 列表中移除,則為 true。如果 folio 不在 LRU 列表中,則為 false。

void check_move_unevictable_folios(struct folio_batch *fbatch)

將可回收的 folios 移動到相應的區域 LRU 列表

引數

struct folio_batch *fbatch

要檢查的 LRU folios 批次。

描述

檢查 folios 的可回收性,如果可回收的 folio 位於不可回收 LRU 列表中,則將其移動到相應的可回收 LRU 列表。此函式僅應用於 LRU folios。

void __remove_pages(unsigned long pfn, unsigned long nr_pages, struct vmem_altmap *altmap)

移除頁面段

引數

unsigned long pfn

起始頁框(必須與節的起始地址對齊)

unsigned long nr_pages

要移除的頁數(必須是節大小的倍數)

struct vmem_altmap *altmap

備用裝置頁面對映,如果使用預設 memmap,則為 NULL

描述

通用輔助函式,用於移除正在移除的記憶體部分的節對映和 sysfs 條目。呼叫者需要透過呼叫 offline_pages() 確保頁面被標記為保留狀態,並正確調整區域。

void try_offline_node(int nid)

引數

int nid

節點 ID

描述

如果節點的所有記憶體段和 CPU 都已移除,則使節點離線。

注意

呼叫者必須在此呼叫之前呼叫 lock_device_hotplug() 以序列化熱插拔和線上/離線操作。

void __remove_memory(u64 start, u64 size)

如果每個記憶體塊都處於離線狀態,則移除記憶體

引數

u64 start

要移除區域的物理地址

u64 size

要移除區域的大小

注意

呼叫者必須在此呼叫之前呼叫 lock_device_hotplug() 以序列化熱插拔和線上/離線操作,如 try_offline_node() 所要求的那樣。

unsigned long mmu_interval_read_begin(struct mmu_interval_notifier *interval_sub)

針對 VA 範圍開始一個讀取側臨界區

引數

struct mmu_interval_notifier *interval_sub

間隔訂閱

描述

mmu_iterval_read_begin()/mmu_iterval_read_retry() 為訂閱的 VA 範圍實現了類似於 seqcount 的碰撞重試機制。如果在臨界區期間 mm 呼叫了無效化,則 mmu_interval_read_retry() 將返回 true。

這對於獲取影子 PTE 很有用,其中 SPTE 的拆除或設定需要阻塞上下文。由此形成的臨界區可以休眠,並且所需的“user_lock”也可以是休眠鎖。

呼叫者需要提供一個“user_lock”來序列化拆除和設定操作。

返回值應傳遞給 mmu_interval_read_retry()。

int mmu_notifier_register(struct mmu_notifier *subscription, struct mm_struct *mm)

在 mm 上註冊一個通知器

引數

struct mmu_notifier *subscription

要附加的通知器

struct mm_struct *mm

要附加通知器的 mm

描述

呼叫此註冊函式時,不得持有 mmap_lock 或任何其他與 VM 相關的鎖。還必須確保在執行時 mm_users 不會降至零,以避免與 mmu_notifier_release 發生競爭條件,因此 mm 必須是 current->mm,或者 mm 應該安全地固定(例如使用 get_task_mm())。如果 mm 不是 current->mm,則在 mmu_notifier_register 返回後,應透過呼叫 mmput 釋放 mm_users 鎖定。

必須始終呼叫 mmu_notifier_unregister() 或 mmu_notifier_put() 來登出通知器。

當呼叫者獲取到 mmu_notifier 時,subscription->mm 指標將保持有效,並且可以透過 mmget_not_zero() 轉換為活動的 mm 指標。

struct mmu_notifier *mmu_notifier_get_locked(const struct mmu_notifier_ops *ops, struct mm_struct *mm)

返回 mm 和操作的單一 struct mmu_notifier

引數

const struct mmu_notifier_ops *ops

用於訂閱的操作結構

struct mm_struct *mm

也要附加通知器的 mm

描述

此函式透過 ops->alloc_notifier() 分配一個新的 mmu_notifier,或者返回列表中已存在的通知器。ops 指標的值用於確定兩個通知器何時相同。

每次呼叫 mmu_notifier_get() 都必須與呼叫 mmu_notifier_put() 配對。呼叫者必須持有 mm->mmap_lock 的寫入側鎖。

當呼叫者獲取到 mmu_notifier 時,mm 指標將保持有效,並且可以透過 mmget_not_zero() 轉換為活動的 mm 指標。

void mmu_notifier_put(struct mmu_notifier *subscription)

釋放通知器上的引用

引數

struct mmu_notifier *subscription

要操作的通知器

描述

此函式必須與每個 mmu_notifier_get() 配對,它釋放透過 get 獲取的引用。如果這是最後一個引用,則釋放通知器的過程將非同步執行。

與 mmu_notifier_unregister() 不同,get/put 流程只在 mm_struct 被銷燬時呼叫 ops->release。相反,free_notifier 總是被呼叫以釋放使用者持有的任何資源。

由於 ops->release 不保證被呼叫,使用者必須確保所有 SPTE 都已丟棄,並且在呼叫 mmu_notifier_put() 之前無法建立新的 SPTE。

此函式可以從 ops->release 回撥中呼叫,但是呼叫者仍然必須確保它與 mmu_notifier_get() 成對呼叫。

呼叫此函式的模組必須在其 __exit 函式中呼叫 mmu_notifier_synchronize(),以確保非同步工作完成。

int mmu_interval_notifier_insert(struct mmu_interval_notifier *interval_sub, struct mm_struct *mm, unsigned long start, unsigned long length, const struct mmu_interval_notifier_ops *ops)

插入一個間隔通知器

引數

struct mmu_interval_notifier *interval_sub

要註冊的間隔訂閱

struct mm_struct *mm

要附加到的 mm_struct

unsigned long start

要監控的起始虛擬地址

unsigned long length

要監控範圍的長度

const struct mmu_interval_notifier_ops *ops

在匹配事件發生時呼叫的間隔通知器操作

描述

此函式訂閱間隔通知器以接收來自 mm 的通知。返回後,每當發生與給定範圍相交的事件時,將呼叫與 mmu_interval_notifier 相關的操作。

返回時,range_notifier 可能尚未出現在間隔樹中。呼叫者必須透過 mmu_interval_read_begin() 使用常規間隔通知器讀取流程,為該範圍建立 SPTE。

void mmu_interval_notifier_remove(struct mmu_interval_notifier *interval_sub)

移除一個間隔通知器

引數

struct mmu_interval_notifier *interval_sub

要登出的間隔訂閱

描述

此函式必須與 mmu_interval_notifier_insert() 配對使用。它不能從任何 ops 回撥中呼叫。

此函式返回後,ops 回撥將不再在其他 CPU 上執行,將來也不會再被呼叫。

void mmu_notifier_synchronize(void)

確保所有 mmu_notifiers 都已釋放

引數

void

無引數

描述

此函式確保所有從 mmu_notifier_put() 發出的未完成非同步 SRU 工作都已完成。返回後,與未使用的 mmu_notifier 關聯的任何 mmu_notifier_ops 將不再被呼叫。

在使用之前,呼叫者必須確保其所有 mmu_notifier 都已透過 mmu_notifier_put() 完全釋放。

使用 mmu_notifier_put() API 的模組應在其 __exit 函式中呼叫此函式,以避免模組解除安裝時的競爭條件。

size_t balloon_page_list_enqueue(struct balloon_dev_info *b_dev_info, struct list_head *pages)

將頁面列表插入到 balloon 頁面列表中。

引數

struct balloon_dev_info *b_dev_info

將要插入新頁面的 balloon 裝置描述符

struct list_head *pages

要排隊的頁面 - 使用 balloon_page_alloc 分配。

描述

驅動程式必須在最終將 balloon 頁面從客戶機系統中移除之前,呼叫此函式以正確地將其入隊。

返回

已入隊的頁數。

size_t balloon_page_list_dequeue(struct balloon_dev_info *b_dev_info, struct list_head *pages, size_t n_req_pages)

從 balloon 的頁面列表中移除頁面並返回頁面列表。

引數

struct balloon_dev_info *b_dev_info

將要從中獲取頁面的 balloon 裝置描述符。

struct list_head *pages

指向將返回給呼叫者的頁面列表的指標。

size_t n_req_pages

請求的頁數。

描述

驅動程式必須在最終將先前入隊的 balloon 頁面釋放回客戶機系統之前,呼叫此函式以正確地將其解除分配。此函式嘗試從已 balloon 的頁面中移除 n_req_pages 個頁面,並在 **pages** 列表中將其返回給呼叫者。

請注意,即使 balloon 不為空,此函式也可能無法出隊某些頁面——因為頁面列表可能由於隔離頁面的壓縮而暫時為空。

返回

已新增到 pages 列表中的頁數。

vm_fault_t vmf_insert_pfn_pmd(struct vm_fault *vmf, pfn_t pfn, bool write)

插入一個 pmd 大小的 pfn

引數

struct vm_fault *vmf

描述故障的結構體

pfn_t pfn

要插入的 pfn

bool write

是否為寫入故障

描述

插入一個 pmd 大小的 pfn。有關更多資訊,請參閱 vmf_insert_pfn()

返回

vm_fault_t 值。

vm_fault_t vmf_insert_pfn_pud(struct vm_fault *vmf, pfn_t pfn, bool write)

插入一個 pud 大小的 pfn

引數

struct vm_fault *vmf

描述故障的結構體

pfn_t pfn

要插入的 pfn

bool write

是否為寫入故障

描述

插入一個 pud 大小的 pfn。有關更多資訊,請參閱 vmf_insert_pfn()

返回

vm_fault_t 值。

vm_fault_t vmf_insert_folio_pud(struct vm_fault *vmf, struct folio *folio, bool write)

插入一個由 pud 條目對映的 pud 大小 folio

引數

struct vm_fault *vmf

描述故障的結構體

struct folio *folio

要插入的 folio

bool write

是否為寫入故障

返回

vm_fault_t 值。

int io_mapping_map_user(struct io_mapping *iomap, struct vm_area_struct *vma, unsigned long addr, unsigned long pfn, unsigned long size)

將 I/O 對映重新對映到使用者空間

引數

struct io_mapping *iomap

源 io_mapping

struct vm_area_struct *vma

要對映到的使用者 VMA

unsigned long addr

要開始的目標使用者地址

unsigned long pfn

核心記憶體的物理地址

unsigned long size

對映區域的大小

注意

僅在呼叫時持有 MM 訊號量才安全。