英語

Linux核心API

列表管理函式

void INIT_LIST_HEAD(struct list_head *list)

初始化list_head結構

引數

struct list_head *list

要初始化的list_head結構。

描述

初始化list_head使其指向自身。如果是列表頭,則結果是一個空列表。

void list_add(struct list_head *new, struct list_head *head)

新增一個新條目

引數

struct list_head *new

要新增的新條目

struct list_head *head

在其後新增的列表頭

描述

在指定的頭部之後插入一個新條目。 這對於實現堆疊很有用。

void list_add_tail(struct list_head *new, struct list_head *head)

新增一個新條目

引數

struct list_head *new

要新增的新條目

struct list_head *head

在其前新增的列表頭

描述

在指定的頭部之前插入一個新條目。 這對於實現佇列很有用。

void list_del(struct list_head *entry)

從列表中刪除條目。

引數

struct list_head *entry

要從列表中刪除的元素。

注意

在此之後,list_empty() 在條目上不會返回true,該條目處於未定義狀態。

void list_replace(struct list_head *old, struct list_head *new)

用新條目替換舊條目

引數

struct list_head *old

要替換的元素

struct list_head *new

要插入的新元素

描述

如果 old 為空,則將被覆蓋。

void list_replace_init(struct list_head *old, struct list_head *new)

用新條目替換舊條目並初始化舊條目

引數

struct list_head *old

要替換的元素

struct list_head *new

要插入的新元素

描述

如果 old 為空,則將被覆蓋。

void list_swap(struct list_head *entry1, struct list_head *entry2)

用entry2替換entry1,並在entry2的位置重新新增entry1

引數

struct list_head *entry1

放置entry2的位置

struct list_head *entry2

放置entry1的位置

void list_del_init(struct list_head *entry)

從列表中刪除條目並重新初始化它。

引數

struct list_head *entry

要從列表中刪除的元素。

void list_move(struct list_head *list, struct list_head *head)

從一個列表刪除並作為另一個列表的頭部新增

引數

struct list_head *list

要移動的條目

struct list_head *head

將位於我們的條目之前的頭部

void list_move_tail(struct list_head *list, struct list_head *head)

從一個列表刪除並作為另一個列表的尾部新增

引數

struct list_head *list

要移動的條目

struct list_head *head

將跟隨我們的條目的頭部

void list_bulk_move_tail(struct list_head *head, struct list_head *first, struct list_head *last)

將列表的一個子段移動到它的尾部

引數

struct list_head *head

將跟隨我們的條目的頭部

struct list_head *first

要移動的第一個條目

struct list_head *last

要移動的最後一個條目,可以與第一個條目相同

描述

first 和包括 last 之間的所有條目移動到 head 之前。所有三個條目必須屬於同一個連結串列。

int list_is_first(const struct list_head *list, const struct list_head *head)
  • 測試 list 是否為列表 head 中的第一個條目

引數

const struct list_head *list

要測試的條目

const struct list_head *head

列表的頭部

int list_is_last(const struct list_head *list, const struct list_head *head)

測試 list 是否為列表 head 中的最後一個條目

引數

const struct list_head *list

要測試的條目

const struct list_head *head

列表的頭部

int list_is_head(const struct list_head *list, const struct list_head *head)

測試 list 是否為列表 head

引數

const struct list_head *list

要測試的條目

const struct list_head *head

列表的頭部

int list_empty(const struct list_head *head)

測試列表是否為空

引數

const struct list_head *head

要測試的列表。

void list_del_init_careful(struct list_head *entry)

從列表中刪除條目並重新初始化它。

引數

struct list_head *entry

要從列表中刪除的元素。

描述

這與 list_del_init() 相同,除了設計用於與 list_empty_careful() 一起使用,以保證其他記憶體操作的順序。

list_del_init_careful() 之前完成的任何記憶體操作都保證在 list_empty_careful() 測試後可見。

int list_empty_careful(const struct list_head *head)

測試列表是否為空且未被修改

引數

const struct list_head *head

要測試的列表

描述

測試列表是否為空 _and_ 檢查是否沒有其他CPU可能正在修改任何成員(next或prev)

注意

如果沒有同步,使用 list_empty_careful() 只能在可以對列表條目執行的唯一活動是 list_del_init() 的情況下是安全的。例如,如果另一個CPU可以重新 list_add() 它,則不能使用它。

void list_rotate_left(struct list_head *head)

將列表向左旋轉

引數

struct list_head *head

列表的頭部

void list_rotate_to_front(struct list_head *list, struct list_head *head)

將列表旋轉到特定專案。

引數

struct list_head *list

所需的列表的新頭部。

struct list_head *head

列表的頭部。

描述

旋轉列表,使 list 成為列表的新頭部。

int list_is_singular(const struct list_head *head)

測試列表是否只有一個條目。

引數

const struct list_head *head

要測試的列表。

void list_cut_position(struct list_head *list, struct list_head *head, struct list_head *entry)

將列表切割成兩個

引數

struct list_head *list

一個用於新增所有已刪除條目的新列表

struct list_head *head

一個包含條目的列表

struct list_head *entry

頭部中的一個條目,可以是頭部本身,如果是這樣,我們將不會切割列表

描述

此助手將 head 的初始部分(直到幷包括 entry)從 head 移動到 list。您應該將已知位於 head 上的元素傳遞給 entrylist 應該是一個空列表或一個您不介意丟失其資料的列表。

void list_cut_before(struct list_head *list, struct list_head *head, struct list_head *entry)

在給定條目之前將連結串列剪下成兩部分

引數

struct list_head *list

一個用於新增所有已刪除條目的新列表

struct list_head *head

一個包含條目的列表

struct list_head *entry

head 中的一個條目,可以是 head 本身

描述

此輔助函式將 **head** 的初始部分(直到但不包括 **entry**)從 **head** 移動到 **list**。 你應該傳入一個你確定在 **head** 上的元素 **entry**。**list** 應該是一個空連結串列或者一個你不在意丟失資料的連結串列。 如果 **entry** == **head**,則 **head** 上的所有條目都會移動到 **list**。

void list_splice(const struct list_head *list, struct list_head *head)

連線兩個連結串列,此函式設計用於棧

引數

const struct list_head *list

要新增的新連結串列。

struct list_head *head

在第一個連結串列中新增的位置。

void list_splice_tail(struct list_head *list, struct list_head *head)

連線兩個連結串列,每個連結串列都是一個佇列

引數

struct list_head *list

要新增的新連結串列。

struct list_head *head

在第一個連結串列中新增的位置。

void list_splice_init(struct list_head *list, struct list_head *head)

連線兩個連結串列並重新初始化空連結串列。

引數

struct list_head *list

要新增的新連結串列。

struct list_head *head

在第一個連結串列中新增的位置。

描述

**list** 處的連結串列被重新初始化

void list_splice_tail_init(struct list_head *list, struct list_head *head)

連線兩個連結串列並重新初始化空連結串列

引數

struct list_head *list

要新增的新連結串列。

struct list_head *head

在第一個連結串列中新增的位置。

描述

每個連結串列都是一個佇列。**list** 處的連結串列被重新初始化

list_entry

list_entry (ptr, type, member)

獲取此條目的結構體

引數

ptr

struct list_head 指標。

type

嵌入此結構的結構體型別。

member

結構體中 list_head 的名稱。

list_first_entry

list_first_entry (ptr, type, member)

從連結串列中獲取第一個元素

引數

ptr

從中獲取元素的連結串列頭。

type

嵌入此結構的結構體型別。

member

結構體中 list_head 的名稱。

描述

請注意,預期連結串列不為空。

list_last_entry

list_last_entry (ptr, type, member)

從連結串列中獲取最後一個元素

引數

ptr

從中獲取元素的連結串列頭。

type

嵌入此結構的結構體型別。

member

結構體中 list_head 的名稱。

描述

請注意,預期連結串列不為空。

list_first_entry_or_null

list_first_entry_or_null (ptr, type, member)

從連結串列中獲取第一個元素

引數

ptr

從中獲取元素的連結串列頭。

type

嵌入此結構的結構體型別。

member

結構體中 list_head 的名稱。

描述

請注意,如果連結串列為空,則返回 NULL。

list_next_entry

list_next_entry (pos, member)

獲取連結串列中的下一個元素

引數

pos

型別 * 指向遊標

member

結構體中 list_head 的名稱。

list_next_entry_circular

list_next_entry_circular (pos, head, member)

獲取連結串列中的下一個元素

引數

pos

型別 * 指向遊標。

head

從中獲取元素的連結串列頭。

member

結構體中 list_head 的名稱。

描述

如果 pos 是最後一個元素,則迴繞(返回第一個元素)。請注意,預期連結串列不為空。

list_prev_entry

list_prev_entry (pos, member)

獲取連結串列中的上一個元素

引數

pos

型別 * 指向遊標

member

結構體中 list_head 的名稱。

list_prev_entry_circular

list_prev_entry_circular (pos, head, member)

獲取連結串列中的上一個元素

引數

pos

型別 * 指向遊標。

head

從中獲取元素的連結串列頭。

member

結構體中 list_head 的名稱。

描述

如果 pos 是第一個元素,則迴繞(返回最後一個元素)。請注意,預期連結串列不為空。

list_for_each

list_for_each (pos, head)

迭代連結串列

引數

pos

struct list_head 用作循環遊標。

head

連結串列的頭部。

list_for_each_rcu

list_for_each_rcu (pos, head)

以 RCU 安全的方式迭代連結串列

引數

pos

struct list_head 用作循環遊標。

head

連結串列的頭部。

list_for_each_continue

list_for_each_continue (pos, head)

繼續迭代連結串列

引數

pos

struct list_head 用作循環遊標。

head

連結串列的頭部。

描述

繼續迭代連結串列,在當前位置之後繼續。

list_for_each_prev

list_for_each_prev (pos, head)

向後迭代連結串列

引數

pos

struct list_head 用作循環遊標。

head

連結串列的頭部。

list_for_each_safe

list_for_each_safe (pos, n, head)

迭代連結串列,防止刪除連結串列條目

引數

pos

struct list_head 用作循環遊標。

n

另一個 struct list_head 用作臨時儲存

head

連結串列的頭部。

list_for_each_prev_safe

list_for_each_prev_safe (pos, n, head)

向後迭代連結串列,防止刪除連結串列條目

引數

pos

struct list_head 用作循環遊標。

n

另一個 struct list_head 用作臨時儲存

head

連結串列的頭部。

size_t list_count_nodes(struct list_head *head)

計算連結串列中的節點數

引數

struct list_head *head

連結串列的頭部。

list_entry_is_head

list_entry_is_head (pos, head, member)

測試條目是否指向連結串列的頭部

引數

pos

型別 * 指向遊標

head

連結串列的頭部。

member

結構體中 list_head 的名稱。

list_for_each_entry

list_for_each_entry (pos, head, member)

迭代給定型別的連結串列

引數

pos

用作循環遊標的 型別 *。

head

連結串列的頭部。

member

結構體中 list_head 的名稱。

list_for_each_entry_reverse

list_for_each_entry_reverse (pos, head, member)

向後迭代給定型別的連結串列。

引數

pos

用作循環遊標的 型別 *。

head

連結串列的頭部。

member

結構體中 list_head 的名稱。

list_prepare_entry

list_prepare_entry (pos, head, member)

準備一個 pos 條目以用於 list_for_each_entry_continue()

引數

pos

用作起始點的 型別 *

head

列表的頭部

member

結構體中 list_head 的名稱。

描述

準備一個 pos 條目,用作 list_for_each_entry_continue() 中的起始點。

list_for_each_entry_continue

list_for_each_entry_continue (pos, head, member)

繼續迭代給定型別的連結串列

引數

pos

用作循環遊標的 型別 *。

head

連結串列的頭部。

member

結構體中 list_head 的名稱。

描述

繼續迭代給定型別的連結串列,在當前位置之後繼續。

list_for_each_entry_continue_reverse

list_for_each_entry_continue_reverse (pos, head, member)

從給定的點向後迭代

引數

pos

用作循環遊標的 型別 *。

head

連結串列的頭部。

member

結構體中 list_head 的名稱。

描述

開始向後迭代給定型別的連結串列,在當前位置之後繼續。

list_for_each_entry_from

list_for_each_entry_from (pos, head, member)

從當前點迭代給定型別的連結串列

引數

pos

用作循環遊標的 型別 *。

head

連結串列的頭部。

member

結構體中 list_head 的名稱。

描述

迭代給定型別的連結串列,從當前位置繼續。

list_for_each_entry_from_reverse

list_for_each_entry_from_reverse (pos, head, member)

從當前點向後迭代給定型別的連結串列

引數

pos

用作循環遊標的 型別 *。

head

連結串列的頭部。

member

結構體中 list_head 的名稱。

描述

向後迭代給定型別的連結串列,從當前位置繼續。

list_for_each_entry_safe

list_for_each_entry_safe (pos, n, head, member)

迭代給定型別的連結串列,防止刪除連結串列條目

引數

pos

用作循環遊標的 型別 *。

n

另一個 型別 * 用作臨時儲存

head

連結串列的頭部。

member

結構體中 list_head 的名稱。

list_for_each_entry_safe_continue

list_for_each_entry_safe_continue (pos, n, head, member)

繼續連結串列迭代,防止刪除

引數

pos

用作循環遊標的 型別 *。

n

另一個 型別 * 用作臨時儲存

head

連結串列的頭部。

member

結構體中 list_head 的名稱。

描述

迭代給定型別的連結串列,在當前點之後繼續,防止刪除連結串列條目。

list_for_each_entry_safe_from

list_for_each_entry_safe_from (pos, n, head, member)

從當前點迭代連結串列,防止刪除

引數

pos

用作循環遊標的 型別 *。

n

另一個 型別 * 用作臨時儲存

head

連結串列的頭部。

member

結構體中 list_head 的名稱。

描述

迭代給定型別的連結串列,從當前點開始,防止刪除連結串列條目。

list_for_each_entry_safe_reverse

list_for_each_entry_safe_reverse (pos, n, head, member)

向後迭代連結串列,防止刪除

引數

pos

用作循環遊標的 型別 *。

n

另一個 型別 * 用作臨時儲存

head

連結串列的頭部。

member

結構體中 list_head 的名稱。

描述

向後迭代給定型別的連結串列,防止刪除連結串列條目。

list_safe_reset_next

list_safe_reset_next (pos, n, member)

重置過時的 list_for_each_entry_safe 迴圈

引數

pos

list_for_each_entry_safe 迴圈中使用的循環遊標

n

list_for_each_entry_safe 中使用的臨時儲存

member

結構體中 list_head 的名稱。

描述

如果列表可能同時被修改,通常 list_safe_reset_next 不安全使用(例如,在迴圈體中釋放鎖)。一個例外是,如果遊標元素 (pos) 固定在列表中,並且在重新獲取鎖並在完成迴圈體的當前迭代之前呼叫 list_safe_reset_next。

int hlist_unhashed(const struct hlist_node *h)

節點是否已從連結串列中移除並重新初始化?

引數

const struct hlist_node *h

要檢查的節點

描述

請注意,並非所有移除函式都會使節點處於未雜湊狀態。例如,hlist_nulls_del_init_rcu() 會使節點處於未雜湊狀態,但 hlist_nulls_del() 不會。

int hlist_unhashed_lockless(const struct hlist_node *h)

hlist_unhashed 的無鎖版本

引數

const struct hlist_node *h

要檢查的節點

描述

必須在無鎖上下文中使用此 hlist_unhashed() 變體,以避免潛在的載入撕裂。 READ_ONCE() 與下面定義的 hlist 輔助函式中的各種 WRITE_ONCE() 配對。

int hlist_empty(const struct hlist_head *h)

指定的 hlist_head 結構是否為空 hlist?

引數

const struct hlist_head *h

要檢查的結構。

void hlist_del(struct hlist_node *n)

從其連結串列中刪除指定的 hlist_node

引數

struct hlist_node *n

要刪除的節點。

描述

請注意,此函式使節點處於雜湊狀態。 使用 hlist_del_init() 或類似函式來取消雜湊 **n**。

void hlist_del_init(struct hlist_node *n)

從其連結串列中刪除指定的 hlist_node 並初始化

引數

struct hlist_node *n

要刪除的節點。

描述

請注意,此函式使節點處於未雜湊狀態。

void hlist_add_head(struct hlist_node *n, struct hlist_head *h)

將新條目新增到 hlist 的開頭

引數

struct hlist_node *n

要新增的新條目

struct hlist_head *h

hlist 頭,將在其後新增

描述

在指定的頭部之後插入一個新條目。 這對於實現堆疊很有用。

void hlist_add_before(struct hlist_node *n, struct hlist_node *next)

在指定的條目之前新增新條目

引數

struct hlist_node *n

要新增的新條目

struct hlist_node *next

hlist 節點,將在其之前新增,必須為非 NULL

void hlist_add_behind(struct hlist_node *n, struct hlist_node *prev)

在指定的條目之後新增新條目

引數

struct hlist_node *n

要新增的新條目

struct hlist_node *prev

hlist 節點,將在其之後新增,必須為非 NULL

void hlist_add_fake(struct hlist_node *n)

建立一個由單個無頭節點組成的偽造 hlist

引數

struct hlist_node *n

從中建立一個偽造列表的節點

描述

這使 n 看起來像它自己在一個無頭 hlist 上的前身。 這樣做的目的是允許像 hlist_del() 在沒有列表的情況下正常工作。

bool hlist_fake(struct hlist_node *h)

此節點是偽造的 hlist 嗎?

引數

struct hlist_node *h

要檢查是否為自引用偽造 hlist 的節點。

bool hlist_is_singular_node(struct hlist_node *n, struct hlist_head *h)

節點是否為指定 hlist 的唯一元素?

引數

struct hlist_node *n

要檢查奇異性的節點。

struct hlist_head *h

可能為奇異列表的標頭。

描述

檢查節點是否為標頭的唯一節點,而無需訪問標頭,從而避免不必要的快取未命中。

void hlist_move_list(struct hlist_head *old, struct hlist_head *new)

移動一個 hlist

引數

struct hlist_head *old

舊列表的 hlist_head。

struct hlist_head *new

新列表的 hlist_head。

描述

將列表從一個列表頭移動到另一個列表頭。如果第一個條目存在,則修復 pprev 引用。

void hlist_splice_init(struct hlist_head *from, struct hlist_node *last, struct hlist_head *to)

將所有條目從一個列表移動到另一個列表

引數

struct hlist_head *from

將從中移動條目的 hlist_head

struct hlist_node *last

from 列表上的最後一個條目

struct hlist_head *to

將條目移動到的 hlist_head

描述

to 可以為空,from 必須至少包含 last

hlist_for_each_entry

hlist_for_each_entry (pos, head, member)

迭代給定型別的連結串列

引數

pos

用作循環遊標的 型別 *。

head

連結串列的頭部。

member

結構體中 hlist_node 的名稱。

hlist_for_each_entry_continue

hlist_for_each_entry_continue (pos, member)

在當前點之後繼續迭代 hlist

引數

pos

用作循環遊標的 型別 *。

member

結構體中 hlist_node 的名稱。

hlist_for_each_entry_from

hlist_for_each_entry_from (pos, member)

從當前點繼續迭代 hlist

引數

pos

用作循環遊標的 型別 *。

member

結構體中 hlist_node 的名稱。

hlist_for_each_entry_safe

hlist_for_each_entry_safe (pos, n, head, member)

迭代給定型別的連結串列,防止刪除連結串列條目

引數

pos

用作循環遊標的 型別 *。

n

要用作臨時儲存的 struct hlist_node

head

連結串列的頭部。

member

結構體中 hlist_node 的名稱。

size_t hlist_count_nodes(struct hlist_head *head)

計算 hlist 中的節點數

引數

struct hlist_head *head

您的 hlist 的頭。

基本 C 庫函式

在編寫驅動程式時,通常無法使用 C 庫中的例程。 一些函式已被發現普遍有用,並在下面列出。 這些函式的行為可能與 ANSI 定義的行為略有不同,並且這些偏差在文字中註明。

字串轉換

unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)

將字串轉換為無符號長長整型

引數

const char *cp

字串的開頭

char **endp

指向已解析字串結尾的指標將放置在此處

unsigned int base

要使用的進位制

描述

此函式有注意事項。請改用 kstrtoull。

unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base)

將字串轉換為無符號長整型

引數

const char *cp

字串的開頭

char **endp

指向已解析字串結尾的指標將放置在此處

unsigned int base

要使用的進位制

描述

此函式有注意事項。請改用 kstrtoul。

long simple_strtol(const char *cp, char **endp, unsigned int base)

將字串轉換為帶符號長整型

引數

const char *cp

字串的開頭

char **endp

指向已解析字串結尾的指標將放置在此處

unsigned int base

要使用的進位制

描述

此函式有注意事項。請改用 kstrtol。

long long simple_strtoll(const char *cp, char **endp, unsigned int base)

將字串轉換為帶符號長長整型

引數

const char *cp

字串的開頭

char **endp

指向已解析字串結尾的指標將放置在此處

unsigned int base

要使用的進位制

描述

此函式有注意事項。請改用 kstrtoll。

int vsnprintf(char *buf, size_t size, const char *fmt_str, va_list args)

格式化字串並將其放入緩衝區

引數

char *buf

要將結果放入的緩衝區

size_t size

緩衝區的大小,包括尾隨空空格

const char *fmt_str

要使用的格式字串

va_list args

格式字串的引數

描述

此函式通常遵循 C99 vsnprintf,但有一些擴充套件和一些限制

  • ``n`` 不受支援

  • ``p*`` 由 pointer() 處理

有關更廣泛的描述,請參閱 pointer() 或 如何正確獲取 printk 格式說明符

進行更改時,請同時更新這兩個位置的文件

返回值是為給定輸入生成的字元數,不包括尾隨的“0”,按照 ISO C99。如果您想獲得寫入 buf 的確切字元數作為返回值(不包括尾隨的“0”),請使用 vscnprintf()。如果返回值大於或等於 size,則生成的字串將被截斷。

如果您尚未處理 va_list,請考慮使用 snprintf()

int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)

格式化字串並將其放入緩衝區

引數

char *buf

要將結果放入的緩衝區

size_t size

緩衝區的大小,包括尾隨空空格

const char *fmt

要使用的格式字串

va_list args

格式字串的引數

描述

返回值是已寫入 buf 的字元數,不包括尾隨的“0”。如果 size == 0,則該函式返回 0。

如果您尚未處理 va_list,請考慮使用 scnprintf()

有關 C99 的格式字串擴充套件,請參閱 vsnprintf() 文件。

int snprintf(char *buf, size_t size, const char *fmt, ...)

格式化字串並將其放入緩衝區

引數

char *buf

要將結果放入的緩衝區

size_t size

緩衝區的大小,包括尾隨空空格

const char *fmt

要使用的格式字串

...

格式字串的引數

描述

返回值是為給定輸入生成的字元數,不包括尾隨的空字元,按照 ISO C99。如果返回值大於或等於 size,則生成的字串將被截斷。

有關 C99 的格式字串擴充套件,請參閱 vsnprintf() 文件。

int scnprintf(char *buf, size_t size, const char *fmt, ...)

格式化字串並將其放入緩衝區

引數

char *buf

要將結果放入的緩衝區

size_t size

緩衝區的大小,包括尾隨空空格

const char *fmt

要使用的格式字串

...

格式字串的引數

描述

返回值是寫入 buf 的字元數,不包括尾隨的“0”。如果 size == 0,則該函式返回 0。

int vsprintf(char *buf, const char *fmt, va_list args)

格式化字串並將其放入緩衝區

引數

char *buf

要將結果放入的緩衝區

const char *fmt

要使用的格式字串

va_list args

格式字串的引數

描述

該函式返回寫入 buf 的字元數。請使用 vsnprintf()vscnprintf(),以避免緩衝區溢位。

如果您尚未處理 va_list,請考慮使用 sprintf()

有關 C99 的格式字串擴充套件,請參閱 vsnprintf() 文件。

int sprintf(char *buf, const char *fmt, ...)

格式化字串並將其放入緩衝區

引數

char *buf

要將結果放入的緩衝區

const char *fmt

要使用的格式字串

...

格式字串的引數

描述

該函式返回寫入 buf 的字元數。為了避免緩衝區溢位,請使用 snprintf()scnprintf()

有關 C99 的格式字串擴充套件,請參閱 vsnprintf() 文件。

int vbin_printf(u32 *bin_buf, size_t size, const char *fmt_str, va_list args)

解析格式化字串並將 args 的二進位制值放入緩衝區

引數

u32 *bin_buf

用於放置 args 二進位制值的緩衝區

size_t size

緩衝區的大小(以字(32 位)為單位,而不是字元)

const char *fmt_str

要使用的格式字串

va_list args

格式字串的引數

描述

格式遵循 C99 vsnprintf,除了 n 被忽略,並且其引數被跳過。

返回值是為給定輸入生成的字(32 位)的數量。

注意

如果返回值大於 size,則生成的 bin_buf 對於 bstr_printf() 無效。

int bstr_printf(char *buf, size_t size, const char *fmt_str, const u32 *bin_buf)

從二進位制引數格式化字串,並將其放入緩衝區

引數

char *buf

要將結果放入的緩衝區

size_t size

緩衝區的大小,包括尾隨空空格

const char *fmt_str

要使用的格式字串

const u32 *bin_buf

格式化字串的二進位制引數

描述

此函式類似於 C99 vsnprintf,但不同之處在於 vsnprintf 從堆疊獲取引數,而 bstr_printf 從 bin_buf 獲取引數,bin_buf 是由 vbin_printf 生成的二進位制緩衝區。

格式遵循 C99 vsnprintf,但有一些擴充套件

有關詳細資訊,請參閱 vsnprintf 註釋。

返回值是為給定輸入生成的字元數,不包括尾隨的“0”,按照 ISO C99。如果您想獲得寫入 buf 的確切字元數作為返回值(不包括尾隨的“0”),請使用 vscnprintf()。如果返回值大於或等於 size,則生成的字串將被截斷。

int vsscanf(const char *buf, const char *fmt, va_list args)

將緩衝區反格式化為引數列表

引數

const char *buf

輸入緩衝區

const char *fmt

緩衝區的格式

va_list args

引數

int sscanf(const char *buf, const char *fmt, ...)

將緩衝區反格式化為引數列表

引數

const char *buf

輸入緩衝區

const char *fmt

緩衝區的格式化

...

生成的引數

int kstrtoul(const char *s, unsigned int base, unsigned long *res)

將字串轉換為無符號長整型

引數

const char *s

字串的開頭。字串必須以 null 結尾,並且還可以在其終止 null 之前包含單個換行符。第一個字元也可以是加號,但不能是減號。

unsigned int base

要使用的數字基數。支援的最大基數為 16。如果基數給出為 0,則字串的基數將自動使用傳統語義進行檢測 - 如果它以 0x 開頭,則該數字將被解析為十六進位制(不區分大小寫),如果它以 0 開頭,它將被解析為八進位制數。否則它將被解析為十進位制。

unsigned long *res

成功時,將轉換結果寫入的位置。

描述

成功時返回 0,溢位時返回 -ERANGE,解析錯誤時返回 -EINVAL。優於 simple_strtoul()。必須檢查返回程式碼。

int kstrtol(const char *s, unsigned int base, long *res)

將字串轉換為 long

引數

const char *s

字串的開頭。字串必須以 null 結尾,並且還可以在其終止 null 之前包含單個換行符。第一個字元也可以是加號或減號。

unsigned int base

要使用的數字基數。支援的最大基數為 16。如果基數給出為 0,則字串的基數將自動使用傳統語義進行檢測 - 如果它以 0x 開頭,則該數字將被解析為十六進位制(不區分大小寫),如果它以 0 開頭,它將被解析為八進位制數。否則它將被解析為十進位制。

long *res

成功時,將轉換結果寫入的位置。

描述

成功時返回 0,溢位時返回 -ERANGE,解析錯誤時返回 -EINVAL。優於 simple_strtol()。必須檢查返回程式碼。

int kstrtoull(const char *s, unsigned int base, unsigned long long *res)

將字串轉換為無符號長長整型

引數

const char *s

字串的開頭。字串必須以 null 結尾,並且還可以在其終止 null 之前包含單個換行符。第一個字元也可以是加號,但不能是減號。

unsigned int base

要使用的數字基數。支援的最大基數為 16。如果基數給出為 0,則字串的基數將自動使用傳統語義進行檢測 - 如果它以 0x 開頭,則該數字將被解析為十六進位制(不區分大小寫),如果它以 0 開頭,它將被解析為八進位制數。否則它將被解析為十進位制。

unsigned long long *res

成功時,將轉換結果寫入的位置。

描述

成功時返回 0,溢位時返回 -ERANGE,解析錯誤時返回 -EINVAL。優於 simple_strtoull()。必須檢查返回程式碼。

int kstrtoll(const char *s, unsigned int base, long long *res)

將字串轉換為 long long

引數

const char *s

字串的開頭。字串必須以 null 結尾,並且還可以在其終止 null 之前包含單個換行符。第一個字元也可以是加號或減號。

unsigned int base

要使用的數字基數。支援的最大基數為 16。如果基數給出為 0,則字串的基數將自動使用傳統語義進行檢測 - 如果它以 0x 開頭,則該數字將被解析為十六進位制(不區分大小寫),如果它以 0 開頭,它將被解析為八進位制數。否則它將被解析為十進位制。

long long *res

成功時,將轉換結果寫入的位置。

描述

成功時返回 0,溢位時返回 -ERANGE,解析錯誤時返回 -EINVAL。優於 simple_strtoll()。必須檢查返回程式碼。

int kstrtouint(const char *s, unsigned int base, unsigned int *res)

將字串轉換為無符號整數

引數

const char *s

字串的開頭。字串必須以 null 結尾,並且還可以在其終止 null 之前包含單個換行符。第一個字元也可以是加號,但不能是減號。

unsigned int base

要使用的數字基數。支援的最大基數為 16。如果基數給出為 0,則字串的基數將自動使用傳統語義進行檢測 - 如果它以 0x 開頭,則該數字將被解析為十六進位制(不區分大小寫),如果它以 0 開頭,它將被解析為八進位制數。否則它將被解析為十進位制。

unsigned int *res

成功時,將轉換結果寫入的位置。

描述

成功時返回 0,溢位時返回 -ERANGE,解析錯誤時返回 -EINVAL。優於 simple_strtoul()。必須檢查返回程式碼。

int kstrtoint(const char *s, unsigned int base, int *res)

將字串轉換為整數

引數

const char *s

字串的開頭。字串必須以 null 結尾,並且還可以在其終止 null 之前包含單個換行符。第一個字元也可以是加號或減號。

unsigned int base

要使用的數字基數。支援的最大基數為 16。如果基數給出為 0,則字串的基數將自動使用傳統語義進行檢測 - 如果它以 0x 開頭,則該數字將被解析為十六進位制(不區分大小寫),如果它以 0 開頭,它將被解析為八進位制數。否則它將被解析為十進位制。

int *res

成功時,將轉換結果寫入的位置。

描述

成功時返回 0,溢位時返回 -ERANGE,解析錯誤時返回 -EINVAL。優於 simple_strtol()。必須檢查返回程式碼。

int kstrtobool(const char *s, bool *res)

將常見的使用者輸入轉換為布林值

引數

const char *s

輸入字串

bool *res

結果

描述

當第一個字元是 ‘YyTt1NnFf0’ 或 [oO][NnFf](表示“on”和“off”)時,此例程返回 0。否則,它將返回 -EINVAL。在找到匹配項時,將更新 res 指向的值。

int string_get_size(u64 size, u64 blk_size, const enum string_size_units units, char *buf, int len)

以指定的單位獲取大小

引數

u64 size

要以塊為單位轉換的大小

u64 blk_size

塊的大小(以位元組為單位使用 1)

const enum string_size_units units

要使用的單位(1000 或 1024 的冪),是否包含空格分隔符

char *buf

要格式化的緩衝區

int len

緩衝區長度

描述

此函式返回格式化為 3 位有效數字的字串,給出所需單位的大小。buf 至少應有 9 個位元組的空間,並且始終以零結尾。

返回值:將要寫入的輸出字元數(如果輸出被截斷,則可能大於 len)。

int parse_int_array_user(const char __user *from, size_t count, int **array)

將字串拆分為整數序列

引數

const char __user *from

要讀取的使用者空間緩衝區

size_t count

要讀取的最大位元組數

int **array

返回指向整數序列的指標

描述

成功時,array 將被分配和初始化,其中包含從 from 提取的整數序列,以及一個開始該序列並指定整數計數的附加元素。

呼叫者負責在不再需要 array 時釋放它。

int string_unescape(char *src, char *dst, size_t size, unsigned int flags)

取消給定字串中的跳脫字元

引數

char *src

源緩衝區(已轉義)

char *dst

目標緩衝區(未轉義)

size_t size

目標緩衝區的大小(0 表示無限制)

unsigned int flags

標誌的組合。

描述

該函式取消給定字串中的跳脫字元。

由於輸出的大小將與輸入的大小相同或更小,因此可以在原地執行轉換。

呼叫者必須提供有效的源指標和目標指標。請注意,目標緩衝區將始終以 NULL 結尾。源字串也必須以 NULL 結尾。支援的標誌有

UNESCAPE_SPACE:
        '\f' - form feed
        '\n' - new line
        '\r' - carriage return
        '\t' - horizontal tab
        '\v' - vertical tab
UNESCAPE_OCTAL:
        '\NNN' - byte with octal value NNN (1 to 3 digits)
UNESCAPE_HEX:
        '\xHH' - byte with hexadecimal value HH (1 to 2 digits)
UNESCAPE_SPECIAL:
        '\"' - double quote
        '\\' - backslash
        '\a' - alert (BEL)
        '\e' - escape
UNESCAPE_ANY:
        all previous together

返回

返回處理到目標緩衝區的字元數,不包括尾部的 ‘0’。

int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz, unsigned int flags, const char *only)

引用給定記憶體緩衝區中的字元

引數

const char *src

源緩衝區(未轉義)

size_t isz

源緩衝區大小

char *dst

目標緩衝區(已轉義)

size_t osz

目標緩衝區大小

unsigned int flags

標誌的組合

const char *only

以 NULL 結尾的字串,其中包含用於限制所選轉義類的字元。如果 only 中包含的字元通常不會被 flags 中選擇的類轉義,則它們將以未轉義的形式複製到 dst

描述

轉義位元組緩衝區的過程包括幾個部分。它們按以下順序應用。

  1. 該字元與 only 字串中的一個不匹配,因此必須原樣輸出。

  2. 該字元與可列印和 ASCII 類匹配(如果需要),如果匹配,則將其傳遞到輸出。

  3. 該字元與可列印或 ASCII 類匹配(如果需要),如果匹配,則將其傳遞到輸出。

  4. 檢查該字元是否屬於 flags 給出的類。ESCAPE_OCTALESCAPE_HEX 最後執行,因為它們覆蓋任何字元。請注意,它們實際上不能一起使用,否則 ESCAPE_HEX 將被忽略。

呼叫者必須提供有效的源指標和目標指標。請注意,目標緩衝區不會以 NULL 結尾,因此如果需要,呼叫者必須附加它。支援的標誌有

%ESCAPE_SPACE: (special white space, not space itself)
        '\f' - form feed
        '\n' - new line
        '\r' - carriage return
        '\t' - horizontal tab
        '\v' - vertical tab
%ESCAPE_SPECIAL:
        '\"' - double quote
        '\\' - backslash
        '\a' - alert (BEL)
        '\e' - escape
%ESCAPE_NULL:
        '\0' - null
%ESCAPE_OCTAL:
        '\NNN' - byte with octal value NNN (3 digits)
%ESCAPE_ANY:
        all previous together
%ESCAPE_NP:
        escape only non-printable characters, checked by isprint()
%ESCAPE_ANY_NP:
        all previous together
%ESCAPE_HEX:
        '\xHH' - byte with hexadecimal value HH (2 digits)
%ESCAPE_NA:
        escape only non-ascii characters, checked by isascii()
%ESCAPE_NAP:
        escape only non-printable or non-ascii characters
%ESCAPE_APPEND:
        append characters from @only to be escaped by the given classes

當提供 ESCAPE_NPESCAPE_NAESCAPE_NAP 之一時,ESCAPE_APPEND 將有助於將附加字元傳遞給跳脫字元。

一個值得注意的警告是,ESCAPE_NAPESCAPE_NPESCAPE_NA 的優先順序高於其餘標誌(ESCAPE_NAP 優先順序最高)。如果不使用 ESCAPE_OCTALESCAPE_HEX,則使用它們中的任何一個都沒有意義,因為它們涵蓋了大多數其他字元類。ESCAPE_NAP 除了上述內容外,還可以使用 ESCAPE_SPACEESCAPE_SPECIAL

返回

對於給定的輸入和標誌,將生成的轉義輸出的總大小。 要檢查輸出是否被截斷,請將返回值與 osz 進行比較。 當且僅當 ret < osz 時,dst 中才剩餘空間用於 '0' 終止符。

char **kasprintf_strarray(gfp_t gfp, const char *prefix, size_t n)

分配和填充順序字串陣列

引數

gfp_t gfp

slab 分配器的標誌

const char *prefix

要使用的字首

size_t n

要分配和填充的行數

描述

使用模式 “s-````zu” 分配和填充 n 個字串,其中字首由呼叫者提供。 呼叫者負責在使用後使用 kfree_strarray() 釋放它們。

返回字串陣列,如果無法分配記憶體,則返回 NULL。

void kfree_strarray(char **array, size_t n)

釋放陣列中包含的多個動態分配的字串以及陣列本身

引數

char **array

要釋放的字串的動態分配陣列。

size_t n

要釋放的字串數(從陣列的開頭開始)。

描述

傳遞非 NULL arrayn == 0 以及 NULL array 是有效的用例。如果 array 為 NULL,則該函式不執行任何操作。

char *skip_spaces(const char *str)

str 中刪除前導空格。

引數

const char *str

要剝離的字串。

描述

返回指向 str 中第一個非空格字元的指標。

char *strim(char *s)

s 中刪除前導和尾隨空格。

引數

char *s

要剝離的字串。

描述

請注意,第一個尾隨空格將替換為給定字串 s 中的 NUL-終止符。 返回指向 s 中第一個非空格字元的指標。

bool sysfs_streq(const char *s1, const char *s2)

如果字串相等,則返回 true,模尾隨換行符

引數

const char *s1

一個字串

const char *s2

另一個字串

描述

當且僅當兩個字串相等時,此例程才返回 true,將 NUL 和換行符加 NUL 都視為等效的字串終止。 它適用於 sysfs 輸入字串,這些字串通常以換行符結尾,但與不帶換行符的值進行比較。

int match_string(const char *const *array, size_t n, const char *string)

匹配陣列中給定的字串

引數

const char * const *array

字串陣列

size_t n

陣列中字串的數量,對於 NULL 終止的陣列,則為 -1

const char *string

要匹配的字串

描述

此例程將在字串陣列中查詢字串,直到陣列中的第 n 個元素或直到第一個 NULL 元素。

從歷史上看,n 的值為 -1 用於在 NULL 終止的陣列中搜索。 但是,該函式在完成搜尋時沒有做出區分:要麼比較了 n 個元素,要麼找到了第一個 NULL 元素。

返回

如果匹配,則為 arraystring 的索引,否則為 -EINVAL

int __sysfs_match_string(const char *const *array, size_t n, const char *str)

匹配陣列中給定的字串

引數

const char * const *array

字串陣列

size_t n

陣列中字串的數量,對於 NULL 終止的陣列,則為 -1

const char *str

要匹配的字串

描述

返回 arraystr 的索引或 -EINVAL,就像 match_string() 一樣。 使用 sysfs_streq 而不是 strcmp 進行匹配。

此例程將在字串陣列中查詢字串,直到陣列中的第 n 個元素或直到第一個 NULL 元素。

從歷史上看,n 的值為 -1 用於在 NULL 終止的陣列中搜索。 但是,該函式在完成搜尋時沒有做出區分:要麼比較了 n 個元素,要麼找到了第一個 NULL 元素。

char *strreplace(char *str, char old, char new)

替換字串中字元的所有出現項。

引數

char *str

要操作的字串。

char old

要替換的字元。

char new

old 將替換為的字元。

描述

在給定的字串 str 中,將每個 old 字元替換為 new 字元。

返回

指向字串 str 本身的指標。

void memcpy_and_pad(void *dest, size_t dest_len, const void *src, size_t count, int pad)

將一個緩衝區複製到另一個緩衝區並進行填充

引數

void *dest

要複製到的位置

size_t dest_len

目標緩衝區大小

const void *src

要從其複製的位置

size_t count

要複製的位元組數

int pad

如果目標中剩餘空間,則用於填充的字元。

字串操作

unsafe_memcpy

unsafe_memcpy (dst, src, bytes, justification)

memcpy 實現,沒有 FORTIFY 邊界檢查

引數

dst

要寫入的目標記憶體地址

src

要從中讀取的源記憶體地址

bytes

要從 src 寫入到 dst 的位元組數

justification

描述為什麼需要使用的自由文字或註釋

描述

這應該用於編譯器無法正確執行的極端情況,或者在 API 之間的轉換期間等等。 它應該很少使用,並且包含一個理由位置,詳細說明邊界檢查發生的位置以及為什麼無法採用現有解決方案。

char *strncpy(char *const p, const char *q, __kernel_size_t size)

將字串複製到記憶體,但不能保證 NUL 填充

引數

char * const p

指向副本目標的指標

const char *q

指向要複製的 NUL 終止的源字串的指標

__kernel_size_t size

要在 p 處寫入的位元組

描述

如果 strlen(q) >= size,則對 q 的複製將在 size 位元組後停止,並且 p 將不會 NUL 終止

如果 strlen(q) < size,則在複製 q 之後,會將尾隨 NUL 位元組寫入 p,直到寫入總共 size 個位元組。

請勿使用此函式。 雖然 FORTIFY_SOURCE 嘗試避免過度讀取 q,但它無法防禦將未終止的結果寫入 p。 使用 strncpy() 仍然模稜兩可且脆弱。 請改用其他方法,以便對 p 內容的期望是明確的

p 需要

填充到 size

未填充

NUL 終止

strscpy_pad()

strscpy()

未 NUL 終止

strtomem_pad()

strtomem()

請注意 strscpy*() 用於檢測截斷的不同返回值,以及 strtomem*() 對目標的期望,即當它是一個字元陣列時,標記為 __nonstring。

__kernel_size_t strnlen(const char *const p, __kernel_size_t maxlen)

返回 NUL 終止的字串中字元的邊界計數

引數

const char * const p

指向要計數的 NUL 終止的字串的指標。

__kernel_size_t maxlen

要計數的最大字元數。

描述

返回 p 中的字元數(不包括最終的 NUL),或者如果到那裡為止未找到 NUL,則返回 maxlen

strlen

strlen (p)

返回 NUL 終止的字串中字元的計數

引數

p

指向要計數的 NUL 終止的字串的指標。

描述

除非在編譯時知道字串長度,否則不要使用此函式。 當 p 未終止時,此函式可能會崩潰或返回意外的計數,從而可能導致記憶體內容暴露。 首選 strnlen()

返回 p 中的字元數(不包括最終的 NUL)。

size_t strlcat(char *const p, const char *const q, size_t avail)

將字串追加到現有字串

引數

char * const p

指向要追加到的 NUL-終止 字串的指標

const char * const q

指向要從中追加的 NUL-終止 字串的指標

size_t avail

p 中的最大可用位元組數

描述

p 處的 NUL-終止 字串之後追加 NUL-終止 字串 q,但不會寫入超出 avail 位元組的總數,可能會截斷來自 q 的副本。 只有當 NUL 已經存在於 pavail 位元組中時,p 才會保持 NUL-終止。 如果是這樣,則從 q 複製的生成的位元組數最多為 “avail - strlen(p) - 1”。

請勿使用此函式。 雖然 FORTIFY_SOURCE 嘗試避免讀取和寫入溢位,但這隻有在編譯器知道 pq 的大小的情況下才有可能。 首選透過 scnprintf()、seq_buf 或類似方法使用格式設定來構建字串。

返回 _would_ 已包含在 p 中的總位元組數,無論截斷與否,類似於 snprintf()。 如果返回值 >= avail,則字串已被截斷。

char *strcat(char *const p, const char *q)

將字串追加到現有字串

引數

char * const p

指向要追加到的 NUL 終止的字串的指標

const char *q

指向要從中追加的 NUL 終止的源字串的指標

描述

請勿使用此函式。 雖然 FORTIFY_SOURCE 嘗試避免讀取和寫入溢位,但這隻有在編譯器知道目標緩衝區大小的情況下才有可能。 首選透過 scnprintf() 或類似方法使用格式設定來構建字串。 至少,使用 strncat()

返回 p

char *strncat(char *const p, const char *const q, __kernel_size_t count)

將字串追加到現有字串

引數

char * const p

指向要追加到的 NUL 終止的字串的指標

const char * const q

指向要從中追加的源字串的指標

__kernel_size_t count

要從 q 讀取的最大位元組數

描述

p 處的 NUL 終止的字串之後,從 q 追加最多 count 個位元組(在第一個 NUL 位元組處停止)。 p 將被 NUL 終止。

不要使用此函式。雖然 FORTIFY_SOURCE 嘗試避免讀取和寫入溢位,但這隻有在編譯器知道 pq 的大小時才有可能。 建議使用格式化構建字串,透過 scnprintf() 或類似函式。

返回 p

char *strcpy(char *const p, const char *const q)

將一個字串複製到另一個字串緩衝區中

引數

char * const p

指向副本目標的指標

const char * const q

指向要複製的 NUL 終止的源字串的指標

描述

不要使用此函式。 雖然 FORTIFY_SOURCE 嘗試避免溢位,但這隻有在編譯器知道 qp 的大小時才有可能。 建議使用 strscpy(),但請注意它用於檢測截斷的不同返回值。

返回 p

int strncasecmp(const char *s1, const char *s2, size_t len)

不區分大小寫,長度限制的字串比較

引數

const char *s1

一個字串

const char *s2

另一個字串

size_t len

要比較的最大字元數

char *stpcpy(char *__restrict__ dest, const char *__restrict__ src)

將字串從 src 複製到 dest,返回指向 dest 新末尾的指標,包括 src 的 NUL-終止符。 可能會超出 dest 的範圍。

引數

char *__restrict__ dest

指向要複製到的字串的末尾。 必須足夠大以接收副本。

const char *__restrict__ src

指向要複製的字串的開頭。 不得與 dest 重疊。

描述

stpcpy 與 strcpy 的一個關鍵區別是:返回值是指向 dest 中新的 NUL-終止 字元的指標。(對於 strcpy,返回值是指向 dest 開頭的指標)。此介面被認為是不安全的,因為它不對輸入執行邊界檢查。 因此,不建議使用它。 相反,提供其定義是為了防止編譯器將其他 libcalls 降低到 stpcpy。

int strcmp(const char *cs, const char *ct)

比較兩個字串

引數

const char *cs

一個字串

const char *ct

另一個字串

int strncmp(const char *cs, const char *ct, size_t count)

比較兩個長度受限的字串

引數

const char *cs

一個字串

const char *ct

另一個字串

size_t count

要比較的最大位元組數

char *strchr(const char *s, int c)

查詢字串中第一次出現的字元

引數

const char *s

要搜尋的字串

int c

要搜尋的字元

描述

請注意,NUL-終止符 被認為是字串的一部分,可以搜尋。

char *strchrnul(const char *s, int c)

在字串中查詢並返回一個字元,或字串的結尾

引數

const char *s

要搜尋的字串

int c

要搜尋的字元

描述

返回指向 s 中第一次出現 ‘c’ 的指標。如果未找到 c,則返回指向 s 末尾的空位元組的指標。

char *strrchr(const char *s, int c)

查詢字串中最後一次出現的字元

引數

const char *s

要搜尋的字串

int c

要搜尋的字元

char *strnchr(const char *s, size_t count, int c)

在長度限制的字串中查詢字元

引數

const char *s

要搜尋的字串

size_t count

要搜尋的字元數

int c

要搜尋的字元

描述

請注意,NUL-終止符 被認為是字串的一部分,可以搜尋。

size_t strspn(const char *s, const char *accept)

計算 s 的初始子字串的長度,該子字串僅包含 accept 中的字母

引數

const char *s

要搜尋的字串

const char *accept

要搜尋的字串

size_t strcspn(const char *s, const char *reject)

計算 s 的初始子字串的長度,該子字串不包含 reject 中的字母

引數

const char *s

要搜尋的字串

const char *reject

要避免的字串

char *strpbrk(const char *cs, const char *ct)

查詢一組字元的第一次出現

引數

const char *cs

要搜尋的字串

const char *ct

要搜尋的字元

char *strsep(char **s, const char *ct)

將字串拆分為標記

引數

char **s

要搜尋的字串

const char *ct

要搜尋的字元

描述

strsep() 更新 s 以指向標記之後,準備好進行下一次呼叫。

它也會返回空標記,其行為與該名稱的 libc 函式完全相同。 事實上,它是從 glibc2 偷來的,並且經過了簡化。 相同的語義,更苗條的形狀。 ;)

void *memset(void *s, int c, size_t count)

用給定的值填充記憶體區域

引數

void *s

指向該區域的開頭。

int c

用於填充該區域的位元組

size_t count

該區域的大小。

描述

不要使用 memset() 訪問 IO 空間,而應使用 memset_io()。

void *memset16(uint16_t *s, uint16_t v, size_t count)

用 uint16_t 填充記憶體區域

引數

uint16_t *s

指向該區域的開頭。

uint16_t v

用於填充該區域的值

size_t count

要儲存的值的數量

描述

memset() 的不同之處在於,它使用 uint16_t 而不是位元組填充。 請記住,count 是要儲存的 uint16_ts 的數量,而不是位元組數。

void *memset32(uint32_t *s, uint32_t v, size_t count)

用 uint32_t 填充記憶體區域

引數

uint32_t *s

指向該區域的開頭。

uint32_t v

用於填充該區域的值

size_t count

要儲存的值的數量

描述

memset() 的不同之處在於,它使用 uint32_t 而不是位元組填充。 請記住,count 是要儲存的 uint32_ts 的數量,而不是位元組數。

void *memset64(uint64_t *s, uint64_t v, size_t count)

用 uint64_t 填充記憶體區域

引數

uint64_t *s

指向該區域的開頭。

uint64_t v

用於填充該區域的值

size_t count

要儲存的值的數量

描述

memset() 的不同之處在於,它使用 uint64_t 而不是位元組填充。 請記住,count 是要儲存的 uint64_ts 的數量,而不是位元組數。

void *memcpy(void *dest, const void *src, size_t count)

將一個記憶體區域複製到另一個記憶體區域

引數

void *dest

要複製到的位置

const void *src

要從其複製的位置

size_t count

該區域的大小。

描述

您不應使用此函式訪問 IO 空間,而應使用 memcpy_toio() 或 memcpy_fromio()。

void *memmove(void *dest, const void *src, size_t count)

將一個記憶體區域複製到另一個記憶體區域

引數

void *dest

要複製到的位置

const void *src

要從其複製的位置

size_t count

該區域的大小。

描述

memcpy() 不同,memmove() 可以處理重疊區域。

__visible int memcmp(const void *cs, const void *ct, size_t count)

比較兩個記憶體區域

引數

const void *cs

一個記憶體區域

const void *ct

另一個記憶體區域

size_t count

該區域的大小。

int bcmp(const void *a, const void *b, size_t len)

當且僅當緩衝區具有相同內容時才返回 0。

引數

const void *a

指向第一個緩衝區的指標。

const void *b

指向第二個緩衝區的指標。

size_t len

緩衝區的大小。

描述

非零返回值的符號或大小沒有特定含義,並且架構可以實現它們自己更有效的 bcmp()。 因此,雖然此特定實現是對 memcmp 的簡單(尾部)呼叫,但不要依賴除返回值是否為零或非零之外的任何內容。

void *memscan(void *addr, int c, size_t size)

在記憶體區域中查詢字元。

引數

void *addr

記憶體區域

int c

要查詢的位元組

size_t size

該區域的大小。

描述

返回 **c** 首次出現的地址,如果未找到 **c**,則返回區域後 1 位元組

char *strstr(const char *s1, const char *s2)

在以 NUL 結尾的字串中查詢第一個子字串

引數

const char *s1

要搜尋的字串

const char *s2

要搜尋的字串

char *strnstr(const char *s1, const char *s2, size_t len)

在長度受限的字串中查詢第一個子字串

引數

const char *s1

要搜尋的字串

const char *s2

要搜尋的字串

size_t len

要搜尋的最大字元數

void *memchr(const void *s, int c, size_t n)

在記憶體區域中查詢字元。

引數

const void *s

記憶體區域

int c

要查詢的位元組

size_t n

該區域的大小。

描述

返回 **c** 首次出現的地址,如果未找到 **c**,則返回 NULL

void *memchr_inv(const void *start, int c, size_t bytes)

在記憶體區域中查詢不匹配的字元。

引數

const void *start

記憶體區域

int c

查詢除 c 以外的字元

size_t bytes

該區域的大小。

描述

返回除 **c** 以外的第一個字元的地址,如果整個緩衝區僅包含 **c**,則返回 NULL

void *memdup_array_user(const void __user *src, size_t n, size_t size)

從使用者空間複製陣列

引數

const void __user *src

使用者空間中的源地址

size_t n

要複製的陣列元素的數量

size_t size

一個數組元素的大小

返回

失敗時返回 ERR_PTR()。結果在物理上是連續的,需要使用 kfree() 釋放。

void *vmemdup_array_user(const void __user *src, size_t n, size_t size)

從使用者空間複製陣列

引數

const void __user *src

使用者空間中的源地址

size_t n

要複製的陣列元素的數量

size_t size

一個數組元素的大小

返回

失敗時返回 ERR_PTR()。結果可能在物理上不連續。使用 kvfree() 釋放。

strscpy

strscpy (dst, src, ...)

將 C 字串複製到具有大小限制的緩衝區中

引數

dst

要將字串複製到的位置

src

要從哪裡複製字串

...

目標緩衝區的大小(可選)

描述

將源字串 **src** 複製到目標 **dst** 緩衝區中,或儘可能多地複製。如果字串緩衝區重疊,則行為未定義。除非目標 **dst** 緩衝區的大小為零,否則始終以 NUL 結尾。

只有當 **dst** 不是陣列,或者複製需要小於 sizeof(**dst**) 時,才需要大小引數 **...** 。

優於 strncpy(),因為它始終返回有效字串,並且不會不必要地強制目標緩衝區的尾部填充零。如果需要填充,請使用 strscpy_pad()

返回 **dst** 中複製的字元數(不包括尾隨的 NUL),如果 **size** 為 0 或從 **src** 複製被截斷,則返回 -E2BIG。

strscpy_pad

strscpy_pad (dst, src, ...)

將 C 字串複製到具有大小限制的緩衝區中

引數

dst

要將字串複製到的位置

src

要從哪裡複製字串

...

目標緩衝區的大小

描述

將字串複製到目標緩衝區中,或儘可能多地複製。如果字串緩衝區重疊,則行為未定義。除非目標緩衝區的大小為零,否則始終以 NUL 結尾。

如果源字串短於目標緩衝區,則緩衝區中剩餘的位元組將填充 NUL 位元組。

有關為什麼可能需要考慮使用“strscpy”函式的完整說明,請參閱 strscpy() 的函式文件字串。

返回

  • 複製的字元數(不包括尾隨的 NULs

  • 如果 count 為 0 或 **src** 被截斷,則返回 -E2BIG。

bool mem_is_zero(const void *s, size_t n)

檢查記憶體區域是否全部為 0。

引數

const void *s

記憶體區域

size_t n

區域的大小

返回

如果記憶體區域全部為 0,則為 True。

sysfs_match_string

sysfs_match_string (_a, _s)

匹配陣列中給定的字串

引數

_a

字串陣列

_s

要匹配的字串

描述

__sysfs_match_string() 的助手。自動計算 **a** 的大小。

bool strstarts(const char *str, const char *prefix)

**str** 是否以 **prefix** 開頭?

引數

const char *str

要檢查的字串

const char *prefix

要查詢的字首。

void memzero_explicit(void *s, size_t count)

用 0 填充記憶體區域(例如,敏感金鑰資料)。

引數

void *s

指向該區域的開頭。

size_t count

該區域的大小。

注意

通常使用 memset() 就可以了 (!),但在需要在作用域末尾清除 _local_ 資料的情況下,應使用 memzero_explicit(),以防止編譯器最佳化掉清零操作。

描述

memzero_explicit() 不需要特定於體系結構的版本,因為它只是隱式地呼叫 memset()

const char *kbasename(const char *path)

返回路徑名的最後一部分。

引數

const char *path

從中提取檔名的路徑。

strtomem_pad

strtomem_pad (dest, src, pad)

將以 NUL 結尾的字串複製到非 NUL 結尾的緩衝區

引數

dest

目標字元陣列的指標(標記為 __nonstring)

src

指向以 NUL 結尾的字串的指標

pad

複製後,用於填充 **dest** 剩餘位元組的填充字元

描述

這是 strncpy() 用法的替代方法,其中目標不是以 NUL 結尾的字串,但對源大小進行邊界檢查,並使用顯式填充字元。如果不需要填充,請使用 strtomem()

請注意,**dest** 的大小不是引數,因為編譯器必須能夠發現 **dest** 的長度。

strtomem

strtomem (dest, src)

將以 NUL 結尾的字串複製到非 NUL 結尾的緩衝區

引數

dest

目標字元陣列的指標(標記為 __nonstring)

src

指向以 NUL 結尾的字串的指標

描述

這是 strncpy() 用法的替代方法,其中目標不是以 NUL 結尾的字串,但對源大小進行邊界檢查,並且沒有尾隨填充。如果需要填充,請使用 strtomem_pad()

請注意,**dest** 的大小不是引數,因為編譯器必須能夠發現 **dest** 的長度。

memtostr

memtostr (dest, src)

將可能不是以 NUL 結尾的字串複製到以 NUL 結尾的字串

引數

dest

指向以 NUL 結尾的目標字串的指標

src

指向字元陣列的指標(可能標記為 __nonstring)

描述

這是 strncpy() 用法的替代方法,其中源不是以 NUL 結尾的字串。

請注意,**dest** 和 **src** 的大小必須在編譯時已知。

memtostr_pad

memtostr_pad (dest, src)

將可能不是以 NUL 結尾的字串複製到以 NUL 結尾的字串,並在目標中填充 NUL

引數

dest

指向以 NUL 結尾的目標字串的指標

src

指向字元陣列的指標(可能標記為 __nonstring)

描述

這是 strncpy() 用法的替代方法,其中源不是以 NUL 結尾的字串。

請注意,**dest** 和 **src** 的大小必須在編譯時已知。

memset_after

memset_after (obj, v, member)

在結構成員之後設定一個值到結構的末尾

引數

obj

目標結構例項的地址

v

要重複寫入的位元組值

member

在此結構成員之後開始寫入位元組

描述

這非常適合清除給定成員之後的填充。

memset_startat

memset_startat (obj, v, member)

從成員的起始位置到結構體的末尾設定一個值

引數

obj

目標結構例項的地址

v

要重複寫入的位元組值

member

要開始寫入的結構成員

描述

請注意,如果前一個成員和目標成員之間存在填充,則應使用 memset_after() 來清除前一個填充。

size_t str_has_prefix(const char *str, const char *prefix)

測試字串是否具有給定的字首

引數

const char *str

要測試的字串

const char *prefix

用於檢視 **str** 是否以此開頭的字串

描述

測試字串字首的常用方法是

strncmp(str, prefix, sizeof(prefix) - 1)

但這可能會因拼寫錯誤或字首是指標而不是常量而導致錯誤。請改用 str_has_prefix()

返回

  • 如果 **str** 以 **prefix** 開頭,則返回 strlen(**prefix**)

  • 如果 **str** 不以 **prefix** 開頭,則返回 0

char *kstrdup(const char *s, gfp_t gfp)

分配空間並複製現有字串

引數

const char *s

要複製的字串

gfp_t gfp

在分配記憶體時 kmalloc() 呼叫中使用的 GFP 掩碼

返回

新分配的 **s** 副本,如果出錯,則返回 NULL

const char *kstrdup_const(const char *s, gfp_t gfp)

有條件地複製現有的 const 字串

引數

const char *s

要複製的字串

gfp_t gfp

在分配記憶體時 kmalloc() 呼叫中使用的 GFP 掩碼

注意

由 kstrdup_const 分配的字串應由 kfree_const 釋放,並且不得傳遞給 krealloc()。

返回

如果源字串位於 .rodata 節中,則返回源字串,否則回退到 kstrdup。

char *kstrndup(const char *s, size_t max, gfp_t gfp)

分配空間並複製現有字串

引數

const char *s

要複製的字串

size_t max

從 **s** 中最多讀取 **max** 個字元

gfp_t gfp

在分配記憶體時 kmalloc() 呼叫中使用的 GFP 掩碼

注意

如果大小已知,請改用 kmemdup_nul()

返回

新分配的 **s** 副本,如果出錯,則返回 NULL

void *kmemdup(const void *src, size_t len, gfp_t gfp)

複製記憶體區域

引數

const void *src

要複製的記憶體區域

size_t len

記憶體區域長度

gfp_t gfp

要使用的 GFP 掩碼

返回

src 的新分配的副本,或者在出錯情況下為 NULL,結果是物理上連續的。使用 kfree() 釋放。

char *kmemdup_nul(const char *s, size_t len, gfp_t gfp)

從非空終止的資料建立 NUL 終止的字串

引數

const char *s

要字串化的資料

size_t len

資料的大小

gfp_t gfp

在分配記憶體時 kmalloc() 呼叫中使用的 GFP 掩碼

返回

帶有 NUL 終止符的 s 的新分配副本,或者在出錯情況下為 NULL

void *memdup_user(const void __user *src, size_t len)

從使用者空間複製記憶體區域

引數

const void __user *src

使用者空間中的源地址

size_t len

要複製的位元組數

返回

失敗時返回 ERR_PTR()。結果在物理上是連續的,需要使用 kfree() 釋放。

void *vmemdup_user(const void __user *src, size_t len)

從使用者空間複製記憶體區域

引數

const void __user *src

使用者空間中的源地址

size_t len

要複製的位元組數

返回

失敗時返回 ERR_PTR()。結果可能在物理上不連續。使用 kvfree() 釋放。

char *strndup_user(const char __user *s, long n)

從使用者空間複製現有字串

引數

const char __user *s

要複製的字串

long n

要複製的最大位元組數,包括尾隨的 NUL。

返回

s 的新分配副本,或者在出錯情況下為 ERR_PTR()

void *memdup_user_nul(const void __user *src, size_t len)

從使用者空間複製記憶體區域並進行 NUL 終止

引數

const void __user *src

使用者空間中的源地址

size_t len

要複製的位元組數

返回

失敗時返回 ERR_PTR()

基本核心庫函式

Linux 核心提供了更多基本的實用函式。

位操作

void set_bit(long nr, volatile unsigned long *addr)

原子地設定記憶體中的一位

引數

long nr

要設定的位

volatile unsigned long *addr

開始計數的地址

描述

這是一個寬鬆的原子操作(沒有隱含的記憶體屏障)。

請注意,nr 可能幾乎任意大;此函式不限於對單個字量進行操作。

void clear_bit(long nr, volatile unsigned long *addr)

清除記憶體中的一位

引數

long nr

要清除的位

volatile unsigned long *addr

開始計數的地址

描述

這是一個寬鬆的原子操作(沒有隱含的記憶體屏障)。

void change_bit(long nr, volatile unsigned long *addr)

切換記憶體中的一位

引數

long nr

要更改的位

volatile unsigned long *addr

開始計數的地址

描述

這是一個寬鬆的原子操作(沒有隱含的記憶體屏障)。

請注意,nr 可能幾乎任意大;此函式不限於對單個字量進行操作。

bool test_and_set_bit(long nr, volatile unsigned long *addr)

設定一位並返回其舊值

引數

long nr

要設定的位

volatile unsigned long *addr

開始計數的地址

描述

這是一個原子的完全有序的操作(隱含完全記憶體屏障)。

bool test_and_clear_bit(long nr, volatile unsigned long *addr)

清除一位並返回其舊值

引數

long nr

要清除的位

volatile unsigned long *addr

開始計數的地址

描述

這是一個原子的完全有序的操作(隱含完全記憶體屏障)。

bool test_and_change_bit(long nr, volatile unsigned long *addr)

更改一位並返回其舊值

引數

long nr

要更改的位

volatile unsigned long *addr

開始計數的地址

描述

這是一個原子的完全有序的操作(隱含完全記憶體屏障)。

void ___set_bit(unsigned long nr, volatile unsigned long *addr)

設定記憶體中的一位

引數

unsigned long nr

要設定的位

volatile unsigned long *addr

開始計數的地址

描述

set_bit() 不同,此函式是非原子的。如果在同一記憶體區域上併發呼叫它,則效果可能是隻有一個操作成功。

void ___clear_bit(unsigned long nr, volatile unsigned long *addr)

清除記憶體中的一位

引數

unsigned long nr

要清除的位

volatile unsigned long *addr

開始計數的地址

描述

clear_bit() 不同,此函式是非原子的。如果在同一記憶體區域上併發呼叫它,則效果可能是隻有一個操作成功。

void ___change_bit(unsigned long nr, volatile unsigned long *addr)

切換記憶體中的一位

引數

unsigned long nr

要更改的位

volatile unsigned long *addr

開始計數的地址

描述

change_bit() 不同,此函式是非原子的。如果在同一記憶體區域上併發呼叫它,則效果可能是隻有一個操作成功。

bool ___test_and_set_bit(unsigned long nr, volatile unsigned long *addr)

設定一位並返回其舊值

引數

unsigned long nr

要設定的位

volatile unsigned long *addr

開始計數的地址

描述

此操作是非原子的。如果此操作的兩個例項發生競爭,一個例項可能看似成功,但實際上失敗。

bool ___test_and_clear_bit(unsigned long nr, volatile unsigned long *addr)

清除一位並返回其舊值

引數

unsigned long nr

要清除的位

volatile unsigned long *addr

開始計數的地址

描述

此操作是非原子的。如果此操作的兩個例項發生競爭,一個例項可能看似成功,但實際上失敗。

bool ___test_and_change_bit(unsigned long nr, volatile unsigned long *addr)

更改一位並返回其舊值

引數

unsigned long nr

要更改的位

volatile unsigned long *addr

開始計數的地址

描述

此操作是非原子的。如果此操作的兩個例項發生競爭,一個例項可能看似成功,但實際上失敗。

bool _test_bit(unsigned long nr, volatile const unsigned long *addr)

確定是否設定了某個位

引數

unsigned long nr

要測試的位號

const volatile unsigned long *addr

開始計數的地址

bool _test_bit_acquire(unsigned long nr, volatile const unsigned long *addr)

使用獲取語義確定是否設定了某個位

引數

unsigned long nr

要測試的位號

const volatile unsigned long *addr

開始計數的地址

void clear_bit_unlock(long nr, volatile unsigned long *addr)

清除記憶體中的一位,用於解鎖

引數

long nr

要設定的位

volatile unsigned long *addr

開始計數的地址

描述

此操作是原子的,並提供釋放屏障語義。

void __clear_bit_unlock(long nr, volatile unsigned long *addr)

清除記憶體中的一位

引數

long nr

要清除的位

volatile unsigned long *addr

開始計數的地址

描述

這是一個非原子操作,但意味著在記憶體操作之前釋放屏障。如果其他 CPU 無法併發修改字中的其他位,則可以使用它進行解鎖。

bool test_and_set_bit_lock(long nr, volatile unsigned long *addr)

設定一位並返回其舊值,用於鎖定

引數

long nr

要設定的位

volatile unsigned long *addr

開始計數的地址

描述

如果返回值為 0,則此操作是原子的,並提供獲取屏障語義。它可用於實現位鎖。

bool xor_unlock_is_negative_byte(unsigned long mask, volatile unsigned long *addr)

XOR 記憶體中的單個位元組,並測試它是否為負數,用於解鎖。

引數

unsigned long mask

更改在此掩碼中設定的位。

volatile unsigned long *addr

包含要更改的位元組的字的地址。

描述

更改由 addr 指向的字中的某些位 0-6。此操作是原子的,並提供釋放屏障語義。用於最佳化一些通常與解鎖或寫回結束配對的 folio 操作。位 7 用作 PG_waiters 以指示是否有人在等待解鎖。

返回

是否設定了位元組的最高位。

點陣圖操作

點陣圖提供一個位數組,使用一個無符號長整型陣列實現。 給定點陣圖中有效位的數量_不需要_是 BITS_PER_LONG 的精確倍數。

點陣圖的最後一個,部分使用的字中可能未使用的位是“無關緊要的”。 該實現沒有特別努力地將它們保持為零。 它確保它們的值不會影響任何操作的結果。 返回布林值(例如,bitmap_empty)或標量(例如,bitmap_weight)結果的點陣圖操作會小心地過濾掉這些未使用的位,以避免影響其結果。

在小端架構上,點陣圖的位元組順序更自然。 有關此順序的最佳解釋,請參見大端標頭檔案 include/asm-ppc64/bitops.h 和 include/asm-s390/bitops.h。

linux/types.h 中的 DECLARE_BITMAP(name,bits) 宏可用於宣告一個名為 “name” 的陣列,該陣列具有足夠的無符號長整型來包含從 0 到 “bits” - 1 的所有位位置。

在點陣圖是單個無符號長整型的情況下,可用的點陣圖操作及其大致含義如下

當 `nbits` 在編譯時已知且最多為 `BITS_PER_LONG` 時,生成的程式碼效率更高。

bitmap_zero(dst, nbits)                     *dst = 0UL
bitmap_fill(dst, nbits)                     *dst = ~0UL
bitmap_copy(dst, src, nbits)                *dst = *src
bitmap_and(dst, src1, src2, nbits)          *dst = *src1 & *src2
bitmap_or(dst, src1, src2, nbits)           *dst = *src1 | *src2
bitmap_xor(dst, src1, src2, nbits)          *dst = *src1 ^ *src2
bitmap_andnot(dst, src1, src2, nbits)       *dst = *src1 & ~(*src2)
bitmap_complement(dst, src, nbits)          *dst = ~(*src)
bitmap_equal(src1, src2, nbits)             Are *src1 and *src2 equal?
bitmap_intersects(src1, src2, nbits)        Do *src1 and *src2 overlap?
bitmap_subset(src1, src2, nbits)            Is *src1 a subset of *src2?
bitmap_empty(src, nbits)                    Are all bits zero in *src?
bitmap_full(src, nbits)                     Are all bits set in *src?
bitmap_weight(src, nbits)                   Hamming Weight: number set bits
bitmap_weight_and(src1, src2, nbits)        Hamming Weight of and'ed bitmap
bitmap_weight_andnot(src1, src2, nbits)     Hamming Weight of andnot'ed bitmap
bitmap_set(dst, pos, nbits)                 Set specified bit area
bitmap_clear(dst, pos, nbits)               Clear specified bit area
bitmap_find_next_zero_area(buf, len, pos, n, mask)  Find bit free area
bitmap_find_next_zero_area_off(buf, len, pos, n, mask, mask_off)  as above
bitmap_shift_right(dst, src, n, nbits)      *dst = *src >> n
bitmap_shift_left(dst, src, n, nbits)       *dst = *src << n
bitmap_cut(dst, src, first, n, nbits)       Cut n bits from first, copy rest
bitmap_replace(dst, old, new, mask, nbits)  *dst = (*old & ~(*mask)) | (*new & *mask)
bitmap_scatter(dst, src, mask, nbits)       *dst = map(dense, sparse)(src)
bitmap_gather(dst, src, mask, nbits)        *dst = map(sparse, dense)(src)
bitmap_remap(dst, src, old, new, nbits)     *dst = map(old, new)(src)
bitmap_bitremap(oldbit, old, new, nbits)    newbit = map(old, new)(oldbit)
bitmap_onto(dst, orig, relmap, nbits)       *dst = orig relative to relmap
bitmap_fold(dst, orig, sz, nbits)           dst bits = orig bits mod sz
bitmap_parse(buf, buflen, dst, nbits)       Parse bitmap dst from kernel buf
bitmap_parse_user(ubuf, ulen, dst, nbits)   Parse bitmap dst from user buf
bitmap_parselist(buf, dst, nbits)           Parse bitmap dst from kernel buf
bitmap_parselist_user(buf, dst, nbits)      Parse bitmap dst from user buf
bitmap_find_free_region(bitmap, bits, order)  Find and allocate bit region
bitmap_release_region(bitmap, pos, order)   Free specified bit region
bitmap_allocate_region(bitmap, pos, order)  Allocate specified bit region
bitmap_from_arr32(dst, buf, nbits)          Copy nbits from u32[] buf to dst
bitmap_from_arr64(dst, buf, nbits)          Copy nbits from u64[] buf to dst
bitmap_to_arr32(buf, src, nbits)            Copy nbits from buf to u32[] dst
bitmap_to_arr64(buf, src, nbits)            Copy nbits from buf to u64[] dst
bitmap_get_value8(map, start)               Get 8bit value from map at start
bitmap_set_value8(map, value, start)        Set 8bit value to map at start
bitmap_read(map, start, nbits)              Read an nbits-sized value from
                                            map at start
bitmap_write(map, value, start, nbits)      Write an nbits-sized value to
                                            map at start

請注意,`bitmap_zero()` 和 `bitmap_fill()` 在無符號長整型區域上操作,也就是說,點陣圖後面的位直到無符號長整型邊界也會被清零或填充。考慮使用 `bitmap_clear()` 或 `bitmap_set()` 來分別顯式地進行清零或填充。

此外,asm/bitops.h 中的以下操作也適用於點陣圖。

set_bit(bit, addr)                  *addr |= bit
clear_bit(bit, addr)                *addr &= ~bit
change_bit(bit, addr)               *addr ^= bit
test_bit(bit, addr)                 Is bit set in *addr?
test_and_set_bit(bit, addr)         Set bit and return old value
test_and_clear_bit(bit, addr)       Clear bit and return old value
test_and_change_bit(bit, addr)      Change bit and return old value
find_first_zero_bit(addr, nbits)    Position first zero bit in *addr
find_first_bit(addr, nbits)         Position first set bit in *addr
find_next_zero_bit(addr, nbits, bit)
                                    Position next zero bit in *addr >= bit
find_next_bit(addr, nbits, bit)     Position next set bit in *addr >= bit
find_next_and_bit(addr1, addr2, nbits, bit)
                                    Same as find_next_bit, but in
                                    (*addr1 & *addr2)
void __bitmap_shift_right(unsigned long *dst, const unsigned long *src, unsigned shift, unsigned nbits)

點陣圖中位的邏輯右移

引數

unsigned long *dst

目標點陣圖

const unsigned long *src

源點陣圖

unsigned shift

移動的位數

unsigned nbits

點陣圖大小,以位為單位

描述

右移(除法)意味著將位從 MS -> LS 位方向移動。零被饋送到空出的 MS 位置,並且從底部移出的 LS 位會丟失。

void __bitmap_shift_left(unsigned long *dst, const unsigned long *src, unsigned int shift, unsigned int nbits)

點陣圖中位的邏輯左移

引數

unsigned long *dst

目標點陣圖

const unsigned long *src

源點陣圖

unsigned int shift

移動的位數

unsigned int nbits

點陣圖大小,以位為單位

描述

左移(乘法)意味著將位從 LS -> MS 方向移動。零被饋送到空出的 LS 位位置,並且從頂部移出的 MS 位會丟失。

void bitmap_cut(unsigned long *dst, const unsigned long *src, unsigned int first, unsigned int cut, unsigned int nbits)

從點陣圖中刪除位區域並右移剩餘位

引數

unsigned long *dst

目標點陣圖,可能與 src 重疊

const unsigned long *src

源點陣圖

unsigned int first

要刪除的區域的起始位

unsigned int cut

要刪除的位數

unsigned int nbits

點陣圖大小,以位為單位

描述

僅當 src 的第 n 位被設定並且 n 小於 first 時,才設定 dst 的第 n 位;或者,如果對於任何 m 使得 first <= n < nbits,並且 m = n + cut,則 src 的第 m 位被設定。

用圖片表示,例如對於大端 32 位體系結構

src 點陣圖是

31                                   63
|                                    |
10000000 11000001 11110010 00010101  10000000 11000001 01110010 00010101
                |  |              |                                    |
               16  14             0                                   32

如果 cut 為 3,並且 first 為 14,則 src 中位 14-16 被切除,並且 dst

31                                   63
|                                    |
10110000 00011000 00110010 00010101  00010000 00011000 00101110 01000010
                   |              |                                    |
                   14 (bit 17     0                                   32
                       from @src)

請注意,dstsrc 可能部分或全部重疊。

這是以顯而易見的方式實現的,對於每個移動的位都有一個移位和進位步驟。最佳化留給編譯器作為練習。

unsigned long bitmap_find_next_zero_area_off(unsigned long *map, unsigned long size, unsigned long start, unsigned int nr, unsigned long align_mask, unsigned long align_offset)

查詢一個連續對齊的零區域

引數

unsigned long *map

搜尋的基礎地址

unsigned long size

點陣圖大小,以位為單位

unsigned long start

開始搜尋的位號

unsigned int nr

我們要查詢的零位的數量

unsigned long align_mask

零區域的對齊掩碼

unsigned long align_offset

零區域的對齊偏移量。

描述

align_mask 應該比 2 的冪小 1; 效果是此函式找到的所有零區域的位偏移量加上 align_offset 是該 2 的冪的倍數。

void bitmap_remap(unsigned long *dst, const unsigned long *src, const unsigned long *old, const unsigned long *new, unsigned int nbits)

將一對點陣圖定義的對映應用於另一個位圖

引數

unsigned long *dst

重新對映的結果

const unsigned long *src

要重新對映的子集

const unsigned long *old

定義對映的域

const unsigned long *new

定義對映的範圍

unsigned int nbits

每個點陣圖中的位數

描述

oldnew 定義位位置的對映,使得 old 中第 n 個設定位的任何位置都對映到 new 中第 n 個設定位的。在更一般的情況下,允許 new 的權重 'w' 小於 old 的權重,將 old 中第 n 個設定位的位置對映到 new 中第 m 個設定位的位置,其中 m == n % w。

如果 oldnew 點陣圖中的任何一個為空,或者如果 srcdst 指向相同的位置,則此例程將 src 複製到 dst

old 中未設定位的位置對映到它們自身(恆等對映)。

將上述指定的對映應用於 src,並將結果放入 dst 中,清除先前在 dst 中設定的任何位。

例如,假設 old 設定了位 4 到 7,而 new 設定了位 12 到 15。 這定義了位位置 4 到 12、5 到 13、6 到 14 和 7 到 15 的對映,以及所有其他位位置不變。 所以如果說 src 進入這個例程時設定了位 1、5 和 7,那麼 dst 應該離開時設定了位 1、13 和 15。

int bitmap_bitremap(int oldbit, const unsigned long *old, const unsigned long *new, int bits)

將一對點陣圖定義的對映應用於單個位

引數

int oldbit

要對映的位位置

const unsigned long *old

定義對映的域

const unsigned long *new

定義對映的範圍

int bits

每個點陣圖中的位數

描述

oldnew 定義位位置的對映,使得 old 中第 n 個設定位的任何位置都對映到 new 中第 n 個設定位的。在更一般的情況下,允許 new 的權重 'w' 小於 old 的權重,將 old 中第 n 個設定位的位置對映到 new 中第 m 個設定位的位置,其中 m == n % w。

old 中未設定位的位置對映到它們自身(恆等對映)。

將上述指定的對映應用於位位置 oldbit,返回新的位位置。

例如,假設 old 設定了位 4 到 7,而 new 設定了位 12 到 15。 這定義了位位置 4 到 12、5 到 13、6 到 14 和 7 到 15 的對映,以及所有其他位位置不變。 所以如果說 oldbit 是 5,那麼這個例程返回 13。

void bitmap_from_arr32(unsigned long *bitmap, const u32 *buf, unsigned int nbits)

將 u32 位陣列的內容複製到點陣圖

引數

unsigned long *bitmap

無符號長整型陣列,目標點陣圖

const u32 *buf

u32 陣列(主機位元組序),源點陣圖

unsigned int nbits

bitmap 中的位數

void bitmap_to_arr32(u32 *buf, const unsigned long *bitmap, unsigned int nbits)

將點陣圖的內容複製到 u32 位陣列

引數

u32 *buf

u32 陣列(主機位元組序),目標點陣圖

const unsigned long *bitmap

無符號長整型陣列,源點陣圖

unsigned int nbits

bitmap 中的位數

void bitmap_from_arr64(unsigned long *bitmap, const u64 *buf, unsigned int nbits)

將 u64 位陣列的內容複製到點陣圖

引數

unsigned long *bitmap

無符號長整型陣列,目標點陣圖

const u64 *buf

u64 陣列(主機位元組序),源點陣圖

unsigned int nbits

bitmap 中的位數

void bitmap_to_arr64(u64 *buf, const unsigned long *bitmap, unsigned int nbits)

將點陣圖的內容複製到 u64 位陣列

引數

u64 *buf

u64 陣列(主機位元組序),目標點陣圖

const unsigned long *bitmap

無符號長整型陣列,源點陣圖

unsigned int nbits

bitmap 中的位數

int bitmap_pos_to_ord(const unsigned long *buf, unsigned int pos, unsigned int nbits)

查詢點陣圖中給定位置的設定位的序號

引數

const unsigned long *buf

指向點陣圖的指標

unsigned int pos

buf 中的位位置 (0 <= pos < nbits)

unsigned int nbits

buf 中有效位位置的數量

描述

buf (長度為 nbits) 中位置 pos 處的位對映到它是哪個設定位的序號。 如果未設定或如果 pos 不是有效的位位置,則對映到 -1。

例如,如果僅在 buf 中設定了位 4 到 7,則 pos 值 4 到 7 將分別對映到 0 到 3,其他 pos 值將對映到 -1。 當 pos 值 7 在此示例中對映到(返回)ord 值 3 時,這意味著位 7 是 buf 中第 3 個(從第 0 個開始)設定的位。

位位置 0 到 bitsbuf 中的有效位置。

void bitmap_onto(unsigned long *dst, const unsigned long *orig, const unsigned long *relmap, unsigned int bits)

相對於另一個位圖轉換一個位圖

引數

unsigned long *dst

生成的轉換後的點陣圖

const unsigned long *orig

原始的未轉換的點陣圖

const unsigned long *relmap

相對於哪個點陣圖轉換

unsigned int bits

每個點陣圖中的位數

描述

設定 dst 的第 n 位,當且僅當存在一些 m,使得 relmap 的第 n 位被設定,orig 的第 m 位被設定,並且 relmap 的第 n 位也是 relmap 的第 m 個 _設定_ 位。 (如果您第一次閱讀時就理解了上一句話,那麼您目前的職位有點屈才了。)

換句話說,使用對映 { | relmap 的第 n 位是 relmap 的第 m 個設定位 } 將 orig 對映到(滿射)dst 上。

orig 中,任何高於位號 W 的設定位(其中 W 是 relmap 的權重(設定位數))都不會對映到任何地方。 特別是,如果對於 orig 中設定的所有位 m,m >= W,那麼 dst 最終將為空。 在不希望出現這種空結果的情況下,避免它的一種方法是使用下面的 bitmap_fold() 運算子,首先將 orig 點陣圖摺疊到它自身上,以便其所有設定位 x 都在範圍 0 <= x < W 中。 bitmap_fold() 運算子透過為 orig 中設定的每個位 (m) 設定 dst 中的位 (m % W) 來實現這一點。

bitmap_onto() 的示例 [1]

假設 relmap 設定了位 30-39,而 orig 設定了位 1、3、5、7、9 和 11。 然後,從此例程返回時,dst 將設定位 31、33、35、37 和 39。

orig 中的第 0 位被設定時,意味著開啟 dst 中對應的位,該位對應於 relmap 中第一個被開啟的位(如果有的話)。 由於上面的例子中第 0 位是關閉的,所以我們在 dst 中保持該位(第 30 位)關閉。

orig 中的第 1 位被設定時(如上面的例子所示),意味著開啟 dst 中對應的位,該位對應於 relmap 中第二個被開啟的位。 在上面的例子中,relmap 中第二個被開啟的位是第 31 位,所以我們打開了 dst 中的第 31 位。

類似地,我們打開了 dst 中的第 33、35、37 和 39 位,因為它們是 relmap 中第 4、6、8 和 10 個被設定的位,並且 orig 的第 4、6、8 和 10 位(即第 3、5、7 和 9 位)也被設定了。

orig 中的第 11 位被設定時,意味著開啟 dst 中對應的位,該位對應於 relmap 中第十二個被開啟的位。 在上面的例子中,relmap 中只有十個位被開啟(30..39),因此 orig 中的第 11 位被設定對 dst 沒有影響。

bitmap_fold() + bitmap_onto() 的示例 [2]

假設 relmap 有這十個位被設定

40 41 42 43 45 48 53 61 74 95

(對於好奇的人,這是 40 加上斐波那契數列的前十項。)

此外,假設我們使用以下程式碼,呼叫 bitmap_fold() 然後呼叫 bitmap_onto,如上所述,以避免 dst 結果為空的可能性

unsigned long *tmp;     // a temporary bitmap's bits

bitmap_fold(tmp, orig, bitmap_weight(relmap, bits), bits);
bitmap_onto(dst, tmp, relmap, bits);

然後,下表顯示了對於各種 origdst 的各種值將會是什麼。 我列出了每個設定位的從零開始的位置。 tmp 列顯示了中間結果,該結果是透過使用 bitmap_fold()orig 點陣圖對十(relmap 的權重)取模計算得出的。

orig

tmp

dst

0

0

40

1

1

41

9

9

95

10

0

40 [1]

1 3 5 7

1 3 5 7

41 43 48 61

0 1 2 3 4

0 1 2 3 4

40 41 42 43 45

0 9 18 27

0 9 8 7

40 61 74 95

0 10 20 30

0

40

0 11 22 33

0 1 2 3

40 41 42 43

0 12 24 36

0 2 4 6

40 42 45 53

78 102 211

1 2 8

41 42 74 [1]

如果 origrelmap 中的任何一個是空的(沒有設定位),則 dst 將返回為空。

如果(如上所述)orig 中唯一設定的位位於 m 位置,其中 m >= W(其中 W 是 relmap 的權重),則 dst 將再次返回為空。

dst 中未被上述規則設定的所有位都將被清除。

void bitmap_fold(unsigned long *dst, const unsigned long *orig, unsigned int sz, unsigned int nbits)

將較大的點陣圖摺疊成較小的點陣圖,對指定的大小取模

引數

unsigned long *dst

生成的較小點陣圖

const unsigned long *orig

原始的較大點陣圖

unsigned int sz

指定的大小

unsigned int nbits

每個點陣圖中的位數

描述

對於 orig 中的每個位 oldbit,在 dst 中設定位 oldbit mod sz。 清除 dst 中的所有其他位。 請參閱 bitmap_onto() 的註釋和示例 [2],以瞭解為什麼以及如何使用此方法。

unsigned long bitmap_find_next_zero_area(unsigned long *map, unsigned long size, unsigned long start, unsigned int nr, unsigned long align_mask)

查詢一個連續對齊的零區域

引數

unsigned long *map

搜尋的基礎地址

unsigned long size

點陣圖大小,以位為單位

unsigned long start

開始搜尋的位號

unsigned int nr

我們要查詢的零位的數量

unsigned long align_mask

零區域的對齊掩碼

描述

align_mask 應該是 2 的冪減 1; 效果是此函式找到的所有零區域的位偏移量都是該 2 的冪的倍數。 align_mask 為 0 表示不需要對齊。

bool bitmap_or_equal(const unsigned long *src1, const unsigned long *src2, const unsigned long *src3, unsigned int nbits)

檢查兩個點陣圖的或運算是否等於第三個點陣圖

引數

const unsigned long *src1

指向點陣圖 1 的指標

const unsigned long *src2

指向將與點陣圖 1 進行或運算的點陣圖 2 的指標

const unsigned long *src3

指向點陣圖 3 的指標。 與 *src1 | *src2 的結果進行比較

unsigned int nbits

每個點陣圖中的位數

返回

如果 (*src1 | *src2) == *src3,則為 True,否則為 False

void bitmap_scatter(unsigned long *dst, const unsigned long *src, const unsigned long *mask, unsigned int nbits)

根據給定的掩碼分散點陣圖

引數

unsigned long *dst

分散的點陣圖

const unsigned long *src

收集的點陣圖

const unsigned long *mask

表示要分配給分散點陣圖中的位的掩碼

unsigned int nbits

每個點陣圖中的位數

描述

根據給定的 mask 分散具有順序位的點陣圖。

或以二進位制形式 src mask dst 0000000001011010 0001001100010011 0000001100000010

(位 0、1、2、3、4、5 被複制到位 0、1、4、8、9、12)

操作的更“視覺化”的描述

src:  0000000001011010
                ||||||
         +------+|||||
         |  +----+||||
         |  |+----+|||
         |  ||   +-+||
         |  ||   |  ||
mask: ...v..vv...v..vv
      ...0..11...0..10
dst:  0000001100000010

bitmap_scatter()bitmap_gather() 之間存在關係。 請參閱 bitmap_gather() 以瞭解點陣圖收集的詳細操作。 TL;DR:bitmap_gather() 可以被視為 bitmap_scatter() 操作的“反向”。

示例

如果 src 點陣圖 = 0x005a,且 mask = 0x1313,則 dst 將為 0x0302。

void bitmap_gather(unsigned long *dst, const unsigned long *src, const unsigned long *mask, unsigned int nbits)

根據給定的掩碼收集點陣圖

引數

unsigned long *dst

收集的點陣圖

const unsigned long *src

分散的點陣圖

const unsigned long *mask

表示要從分散點陣圖中提取的位的掩碼

unsigned int nbits

每個點陣圖中的位數

描述

根據給定的 mask 收集具有稀疏位的點陣圖。

或以二進位制形式 src mask dst 0000001100000010 0001001100010011 0000000000011010

(位 0、1、4、8、9、12 被複制到位 0、1、2、3、4、5)

操作的更“視覺化”的描述

mask: ...v..vv...v..vv
src:  0000001100000010
         ^  ^^   ^   0
         |  ||   |  10
         |  ||   > 010
         |  |+--> 1010
         |  +--> 11010
         +----> 011010
dst:  0000000000011010

bitmap_gather()bitmap_scatter() 之間存在關係。 請參閱 bitmap_scatter() 以瞭解點陣圖分散的詳細操作。 TL;DR:bitmap_scatter() 可以被視為 bitmap_gather() 操作的“反向”。

假設 scattered 是使用 bitmap_scatter(scattered, src, mask, n) 計算得出的。 操作 bitmap_gather(result, scattered, mask, n) 會導致結果等於或等效於 src。

結果可能是“等效的”,因為 bitmap_scatter()bitmap_gather() 不是雙射的。 結果和 src 值是等效的,因為呼叫 bitmap_scatter(res, src, mask, n) 和呼叫 bitmap_scatter(res, result, mask, n) 將導致相同的 res 值。

示例

如果 src 點陣圖 = 0x0302,且 mask = 0x1313,則 dst 將為 0x001a。

void bitmap_release_region(unsigned long *bitmap, unsigned int pos, int order)

釋放已分配的點陣圖區域

引數

unsigned long *bitmap

對應於點陣圖的無符號長整型陣列

unsigned int pos

要釋放的位區域的起始位置

int order

要釋放的區域大小(位數的以 2 為底的對數)

描述

這是 __bitmap_find_free_region() 的補充,並釋放找到的區域(透過在點陣圖中清除它)。

int bitmap_allocate_region(unsigned long *bitmap, unsigned int pos, int order)

分配點陣圖區域

引數

unsigned long *bitmap

對應於點陣圖的無符號長整型陣列

unsigned int pos

要分配的位區域的起始位置

int order

區域大小(位數的以 2 為底的對數)

描述

分配(設定位)點陣圖的指定區域。

返回

成功時返回 0,如果指定的區域不是空閒的(並非所有位都為零),則返回 -EBUSY

int bitmap_find_free_region(unsigned long *bitmap, unsigned int bits, int order)

查詢連續對齊的記憶體區域

引數

unsigned long *bitmap

對應於點陣圖的無符號長整型陣列

unsigned int bits

點陣圖中位的數量

int order

要查詢的區域大小(位數的以 2 為底的對數)

描述

bitmap 中查詢一個空閒(零)位區域,該點陣圖有 bits 位,並分配它們(將它們設定為 1)。 僅考慮長度為 2 的冪(order)的區域,該區域與 2 的冪對齊,這使得搜尋演算法更快。

返回

已分配區域在點陣圖中的位偏移量,或者失敗時為 -errno。

BITMAP_FROM_U64

BITMAP_FROM_U64 (n)

以適合點陣圖的格式表示 u64 值。

引數

n

u64 值

描述

Linux 點陣圖在內部是無符號長整型陣列,即在 32 位環境中是 32 位整數,在 64 位環境中是 64 位整數。

在 Linux ABI 中,有四種位元組序和字長的組合:LE64、BE64、LE32 和 BE32。

在 64 位核心上,64 位 LE 和 BE 數字自然地在點陣圖中排序,因此不需要任何特殊處理。

在 32 位核心上,32 位 LE ABI 在記憶體中將 64 位數的低字排在高字之前,而 32 位 BE 將高字排在低字之前。 另一方面,位圖表示為 32 位字的陣列,因此位 N 的位置可以計算為:字 #(N/32) 和該字中的位 #(N``32``)。 例如,位 #42 位於第二個字的第 10 個位置。 它匹配 32 位 LE ABI,我們可以簡單地讓編譯器像通常那樣將 64 位值儲存在記憶體中。 但是對於 BE,我們需要手動交換高字和低字。

考慮到所有這些,宏 BITMAP_FROM_U64() 顯式地重新排序 u64 的高位部分和低位部分。 對於 LE32,它不執行任何操作,對於 BE 環境,它會交換高字和低字,正如點陣圖所期望的那樣。

void bitmap_from_u64(unsigned long *dst, u64 mask)

檢查並交換 u64 中的字。

引數

unsigned long *dst

目標點陣圖

u64 mask

源點陣圖

描述

在 32 位大端核心中,當使用 (u32 *)(:c:type:`val`)[*] 讀取 u64 掩碼時,我們將得到錯誤的字。 也就是說,(u32 *)(:c:type:`val`)[0] 獲取高 32 位,但我們期望 u64 的低 32 位。

unsigned long bitmap_read(const unsigned long *map, unsigned long start, unsigned long nbits)

從記憶體區域讀取 n 位的值

引數

const unsigned long *map

點陣圖記憶體區域的地址

unsigned long start

n 位值的位偏移量

unsigned long nbits

值的位數,非零,最大為 BITS_PER_LONG

返回

位於 map 記憶體區域內 start 位偏移量處的 nbits 位的值。 對於 nbits = 0 和 nbits > BITS_PER_LONG,返回值未定義。

void bitmap_write(unsigned long *map, unsigned long value, unsigned long start, unsigned long nbits)

在記憶體區域中寫入 n 位的值

引數

unsigned long *map

點陣圖記憶體區域的地址

unsigned long value

要寫入的值,限制為 nbits

unsigned long start

n 位值的位偏移量

unsigned long nbits

值的位數,非零,最大為 BITS_PER_LONG。

描述

如果像 nbits 那樣實現了 bitmap_write(),則會呼叫 nbits 次 __assign_bit(),即忽略超出 nbits 的位

for (bit = 0; bit < nbits; bit++)

__assign_bit(start + bit, bitmap, val & BIT(bit));

對於 nbits == 0 和 nbits > BITS_PER_LONG 的情況,不執行任何寫入操作。

命令列解析

int get_option(char **str, int *pint)

從選項字串解析整數

引數

char **str

選項字串

int *pint

(可選輸出) 從 str 解析的整數值

從選項字串讀取一個整數;如果可用,也接受隨後的逗號。

pint 為 NULL 時,該函式可以用作字串中當前選項的驗證器。

返回值:0 - 字串中沒有整數 1 - 找到整數,沒有後續逗號 2 - 找到整數,包括後續逗號 3 - 找到連字元,表示範圍

沒有整數的前導連字元不是整數情況,但為了簡化,我們消耗它。

char *get_options(const char *str, int nints, int *ints)

將字串解析為整數列表

引數

const char *str

要解析的字串

int nints

整數陣列的大小

int *ints

整數陣列(必須至少為一個元素留出空間)

此函式解析包含逗號分隔的整數列表、連字元分隔的 _正_ 整數範圍或兩者的組合的字串。 當陣列已滿或無法從字串中檢索到更多數字時,解析停止。

nints 為 0 時,該函式僅驗證給定的 str 並返回如下所述的可解析整數的數量。

返回

第一個元素由範圍中收集的整數的數量填充。 其餘的是從 str 解析的內容。

返回值是導致解析結束的字串中的字元(如果 str 完全可解析,則通常為空終止符)。

unsigned long long memparse(const char *ptr, char **retptr)

將帶有記憶體字尾的字串解析為數字

引數

const char *ptr

解析開始的位置

char **retptr

(輸出) 解析完成後指向下一個字元的可選指標

將字串解析為數字。儲存在 ptr 處的數字可能帶有 K、M、G、T、P、E 字尾。

錯誤指標

IS_ERR_VALUE

IS_ERR_VALUE (x)

檢測錯誤指標。

引數

x

要檢查的指標。

描述

IS_ERR() 類似,但如果未使用結果,則不會生成編譯器警告。

void *ERR_PTR(long error)

建立錯誤指標。

引數

long error

負錯誤程式碼。

描述

error 編碼為指標值。使用者應將結果視為不透明的,不要假設有關錯誤編碼方式的任何資訊。

返回

一個指標,其值中編碼了 error

long PTR_ERR(__force const void *ptr)

從錯誤指標提取錯誤程式碼。

引數

__force const void *ptr

一個錯誤指標。

返回

ptr 中的錯誤程式碼。

bool IS_ERR(__force const void *ptr)

檢測錯誤指標。

引數

__force const void *ptr

要檢查的指標。

返回

如果 ptr 是錯誤指標,則為 true,否則為 false。

bool IS_ERR_OR_NULL(__force const void *ptr)

檢測錯誤指標或空指標。

引數

__force const void *ptr

要檢查的指標。

描述

IS_ERR() 類似,但對於空指標也返回 true。

void *ERR_CAST(__force const void *ptr)

將錯誤值指標顯式轉換為另一種指標型別

引數

__force const void *ptr

要轉換的指標。

描述

以一種明確表明正在進行的方式,將錯誤值指標顯式轉換為另一種指標型別。

int PTR_ERR_OR_ZERO(__force const void *ptr)

如果指標具有錯誤程式碼,則從中提取錯誤程式碼。

引數

__force const void *ptr

一個潛在的錯誤指標。

描述

可以在返回錯誤程式碼的函式內部使用的便捷函式,用於傳播作為錯誤指標接收的錯誤。例如,return PTR_ERR_OR_ZERO(ptr); 替換

if (IS_ERR(ptr))
        return PTR_ERR(ptr);
else
        return 0;

返回

如果 ptr 是錯誤指標,則返回 ptr 中的錯誤程式碼;否則返回 0。

排序

void sort_r(void *base, size_t num, size_t size, cmp_r_func_t cmp_func, swap_r_func_t swap_func, const void *priv)

對元素陣列進行排序

引數

void *base

指向要排序的資料的指標

size_t num

元素數量

size_t size

每個元素的大小

cmp_r_func_t cmp_func

指向比較函式的指標

swap_r_func_t swap_func

指向交換函式的指標或 NULL

const void *priv

傳遞給比較函式的第三個引數

描述

此函式對給定的陣列執行堆排序。如果需要執行超出記憶體複製的操作(例如,修復指標或輔助資料),您可以提供 swap_func 函式,但內建的交換避免了緩慢的 retpoline,因此速度明顯更快。

比較函式必須遵守特定的數學屬性,以確保正確和穩定的排序: - 反對稱性:cmp_func(a, b) 必須返回與 cmp_func(b, a) 相反的符號。 - 傳遞性:如果 cmp_func(a, b) <= 0 且 cmp_func(b, c) <= 0,則 cmp_func(a, c) <= 0。

平均和最壞情況下的排序時間均為 O(n log n)。雖然快速排序平均速度稍快,但它存在可利用的 O(n*n) 最壞情況行為和額外的記憶體要求,使其不太適合核心使用。

void sort_r_nonatomic(void *base, size_t num, size_t size, cmp_r_func_t cmp_func, swap_r_func_t swap_func, const void *priv)

對元素陣列進行排序,帶有 cond_resched

引數

void *base

指向要排序的資料的指標

size_t num

元素數量

size_t size

每個元素的大小

cmp_r_func_t cmp_func

指向比較函式的指標

swap_r_func_t swap_func

指向交換函式的指標或 NULL

const void *priv

傳遞給比較函式的第三個引數

描述

與 sort_r 相同,但對於較大的陣列,首選此函式,因為它會定期執行 cond_resched()。

void list_sort(void *priv, struct list_head *head, list_cmp_func_t cmp)

對列表進行排序

引數

void *priv

私有資料,對 list_sort() 不透明,傳遞給 cmp

struct list_head *head

要排序的列表

list_cmp_func_t cmp

元素比較函式

描述

如果 a 應排在 b 之後(如果希望升序排序,則為 “a > b”),則比較函式 cmp 必須返回 > 0,如果 a 應排在 b 之前應保留其原始順序,則返回 <= 0。它總是使用輸入中第一個出現的元素 a 呼叫,並且 list_sort 是一種穩定排序,因此沒有必要區分 a < ba == b 的情況。

比較函式必須遵守特定的數學屬性,以確保正確和穩定的排序: - 反對稱性:cmp(a, b) 必須返回與 cmp(b, a) 相反的符號。 - 傳遞性:如果 cmp(a, b) <= 0 且 cmp(b, c) <= 0,則 cmp(a, c) <= 0。

這與兩種樣式的 cmp 函式相容: - 返回 <0 / =0 / >0 的傳統樣式,或 - 返回布林值 0/1。後者提供了在比較中節省幾個週期的機會(例如,在 block/blk-mq.c 中由 plug_ctx_cmp() 使用)。

編寫多字比較的好方法是

if (a->high != b->high)
        return a->high > b->high;
if (a->middle != b->middle)
        return a->middle > b->middle;
return a->low > b->low;

此歸併排序儘可能渴望,同時始終執行至少 2:1 平衡合併。給定兩個大小為 2^k 的掛起子列表,只要我們有 2^k 個後續元素,它們就會合併為大小為 2^(k+1) 的列表。

因此,只要 3*2^k 個元素可以放入快取中,它就會避免快取抖動。不如完全渴望的自下而上歸併排序那麼好,但它確實減少了 0.2*n 次比較,因此在所有內容都適合 L1 的常見情況下速度更快。

合併由“count”控制,即掛起列表中的元素數量。這是一個非常簡單的程式碼,但相當微妙。

每次我們遞增“count”時,我們都會設定一位(位 k)並清除位 k-1 .. 0。每次發生這種情況(除了每次位數的第一次,當 count 遞增到 2^k 時),我們將兩個大小為 2^k 的列表合併為一個大小為 2^(k+1) 的列表。

當 count 達到 2^k 的奇數倍時,即當我們在較小列表中掛起 2^k 個元素時,會準確發生此合併,因此可以安全地合併兩個大小為 2^k 的列表。

在此發生兩次後,我們建立了兩個大小為 2^(k+1) 的列表,這些列表將在我們建立第三個大小為 2^(k+1) 的列表之前合併為大小為 2^(k+2) 的列表,因此永遠不會超過兩個掛起列表。

大小為 2^k 的掛起列表的數量由“count”的位 k 的狀態加上兩個額外的資訊確定

  • 位 k-1 的狀態(當 k == 0 時,認為位 -1 始終設定),以及

  • 高階位是零還是非零(即 count >= 2^(k+1))。

我們區分六種狀態。“x”表示一些任意位,“y”表示一些任意非零位: 0: 00x:大小為 2^k 的 0 個掛起列表;大小 < 2^k 的 x 個掛起列表 1: 01x:大小為 2^k 的 0 個掛起列表;大小 < 2^k 的 2^(k-1) + x 個掛起列表 2: x10x:大小為 2^k 的 0 個掛起列表;大小 < 2^k 的 2^k + x 個掛起列表 3: x11x:大小為 2^k 的 1 個掛起列表;大小 < 2^k 的 2^(k-1) + x 個掛起列表 4: y00x:大小為 2^k 的 1 個掛起列表;大小 < 2^k 的 2^k + x 個掛起列表 5: y01x:大小為 2^k 的 2 個掛起列表;大小 < 2^k 的 2^(k-1) + x 個掛起列表(合併並迴圈回到狀態 2)

我們在 2->3 和 4->5 轉換中獲得大小為 2^k 的列表(因為在更高有效位非零時設定了位 k-1),並在 5->2 轉換中合併它們。特別注意,就在 5->2 轉換之前,所有較低階位都是 11(狀態 3),因此每個較小的大小都有一個列表。

當我們到達輸入的末尾時,我們將所有掛起列表從最小到最大合併。如果您處理上述案例 2 到 5,您可以看到我們與大小為 2^k 的列表合併的元素數量從 2^(k-1)(當 x == 0 時的案例 3 和 5)到 2^(k+1) - 1(當 x == 2^(k-1) - 1 時的案例 5 的第二次合併)不等。

文字搜尋

簡介

文字搜尋基礎設施為線性和非線性資料提供文字搜尋功能。 各個搜尋演算法在模組中實現並由使用者選擇。

架構

  User
  +----------------+
  |        finish()|<--------------(6)-----------------+
  |get_next_block()|<--------------(5)---------------+ |
  |                |                     Algorithm   | |
  |                |                    +------------------------------+
  |                |                    |  init()   find()   destroy() |
  |                |                    +------------------------------+
  |                |       Core API           ^       ^          ^
  |                |      +---------------+  (2)     (4)        (8)
  |             (1)|----->| prepare()     |---+       |          |
  |             (3)|----->| find()/next() |-----------+          |
  |             (7)|----->| destroy()     |----------------------+
  +----------------+      +---------------+

(1) User configures a search by calling textsearch_prepare() specifying
    the search parameters such as the pattern and algorithm name.
(2) Core requests the algorithm to allocate and initialize a search
    configuration according to the specified parameters.
(3) User starts the search(es) by calling textsearch_find() or
    textsearch_next() to fetch subsequent occurrences. A state variable
    is provided to the algorithm to store persistent variables.
(4) Core eventually resets the search offset and forwards the find()
    request to the algorithm.
(5) Algorithm calls get_next_block() provided by the user continuously
    to fetch the data to be searched in block by block.
(6) Algorithm invokes finish() after the last call to get_next_block
    to clean up any leftovers from get_next_block. (Optional)
(7) User destroys the configuration by calling textsearch_destroy().
(8) Core notifies the algorithm to destroy algorithm specific
    allocations. (Optional)

用法

在執行搜尋之前,必須透過呼叫 textsearch_prepare() 來建立配置,指定搜尋演算法、要查詢的模式和標誌。作為標誌,您可以設定 TS_IGNORECASE 以執行不區分大小寫的匹配。但這可能會降低演算法的效能,因此您應該自行承擔使用它的風險。返回的配置可以任意次數地使用,甚至可以並行使用,只要為每個例項提供單獨的 struct ts_state 變數。

實際搜尋是透過呼叫 textsearch_find_continuous() 來執行線性資料搜尋,或者透過提供自己的 get_next_block() 實現並呼叫 textsearch_find() 來執行。如果未找到匹配項,這兩個函式都返回模式的第一次出現的位置,或者返回 UINT_MAX。無論資料的線性如何,都可以透過呼叫 textsearch_next() 來查詢後續出現的位置。

完成使用配置後,必須透過 textsearch_destroy 將其返回。

示例

int pos;
struct ts_config *conf;
struct ts_state state;
const char *pattern = "chicken";
const char *example = "We dance the funky chicken";

conf = textsearch_prepare("kmp", pattern, strlen(pattern),
                          GFP_KERNEL, TS_AUTOLOAD);
if (IS_ERR(conf)) {
    err = PTR_ERR(conf);
    goto errout;
}

pos = textsearch_find_continuous(conf, &state, example, strlen(example));
if (pos != UINT_MAX)
    panic("Oh my god, dancing chickens at %d\n", pos);

textsearch_destroy(conf);
int textsearch_register(struct ts_ops *ops)

註冊一個 textsearch 模組

引數

struct ts_ops *ops

操作查詢表

描述

文字搜尋模組必須呼叫此函式來宣告它們的存在。指定的 &**ops** 必須將 name 設定為唯一的識別符號,並且必須實現回撥函式 find()、init()、get_pattern() 和 get_pattern_len()。

如果另一個模組已經註冊了相同的名稱,則返回 0 或 -EEXISTS。

int textsearch_unregister(struct ts_ops *ops)

登出一個 textsearch 模組

引數

struct ts_ops *ops

操作查詢表

描述

文字搜尋模組必須呼叫此函式來宣告它們已消失,例如當模組被解除安裝時。ops 引數必須與註冊期間的引數相同。

成功時返回 0,如果未找到匹配的 textsearch 註冊,則返回 -ENOENT。

unsigned int textsearch_find_continuous(struct ts_config *conf, struct ts_state *state, const void *data, unsigned int len)

在連續/線性資料中搜索模式

引數

struct ts_config *conf

搜尋配置

struct ts_state *state

搜尋狀態

const void *data

要搜尋的資料

unsigned int len

資料的長度

描述

textsearch_find() 的簡化版本,用於連續/線性資料。呼叫 textsearch_next() 來檢索後續匹配項。

返回模式首次出現的位置,如果未找到任何匹配項,則返回 UINT_MAX

struct ts_config *textsearch_prepare(const char *algo, const void *pattern, unsigned int len, gfp_t gfp_mask, int flags)

準備搜尋

引數

const char *algo

搜尋演算法的名稱

const void *pattern

模式資料

unsigned int len

模式長度

gfp_t gfp_mask

分配掩碼

int flags

搜尋標誌

描述

查詢搜尋演算法模組,併為指定的模式建立新的文字搜尋配置。

根據指定的引數返回新的文字搜尋配置或 ERR_PTR()。如果傳遞零長度模式,此函式將返回 EINVAL。

注意

各種搜尋演算法之間的模式格式可能不相容。

各種搜尋演算法之間的模式格式可能不相容。

void textsearch_destroy(struct ts_config *conf)

銷燬搜尋配置

引數

struct ts_config *conf

搜尋配置

描述

釋放配置的所有引用並釋放記憶體。

unsigned int textsearch_next(struct ts_config *conf, struct ts_state *state)

繼續搜尋模式

引數

struct ts_config *conf

搜尋配置

struct ts_state *state

搜尋狀態

描述

繼續搜尋以查詢模式的更多出現。必須呼叫 textsearch_find() 來查詢第一次出現以重置狀態。

返回模式的下一次出現的位置,如果未找到任何匹配項,則返回 UINT_MAX。

unsigned int textsearch_find(struct ts_config *conf, struct ts_state *state)

開始搜尋模式

引數

struct ts_config *conf

搜尋配置

struct ts_state *state

搜尋狀態

描述

返回模式首次出現的位置,如果未找到任何匹配項,則返回 UINT_MAX。

void *textsearch_get_pattern(struct ts_config *conf)

返回模式的頭部

引數

struct ts_config *conf

搜尋配置

unsigned int textsearch_get_pattern_len(struct ts_config *conf)

返回模式的長度

引數

struct ts_config *conf

搜尋配置

Linux 中的 CRC 和數學函式

算術溢位檢查

check_add_overflow

check_add_overflow (a, b, d)

計算加法並進行溢位檢查

引數

a

第一個加數

b

第二個加數

d

儲存和的指標

描述

如果發生迴繞,則返回 true,否則返回 false。

無論是否發生迴繞,**d** 都儲存嘗試加法的結果。

wrapping_add

wrapping_add (type, a, b)

有意執行迴繞加法

引數

type

計算結果的型別

a

第一個加數

b

第二個加數

描述

返回可能迴繞的加法,而不會觸發任何可能啟用的迴繞清理程式。

wrapping_assign_add

wrapping_assign_add (var, offset)

有意執行迴繞遞增賦值

引數

var

要遞增的變數

offset

要新增的量

描述

將 **var** 遞增 **offset**,並進行迴繞。返回 **var** 的結果值。不會觸發任何迴繞清理程式。

返回 **var** 的新值。

check_sub_overflow

check_sub_overflow (a, b, d)

計算減法並進行溢位檢查

引數

a

被減數;要從中減去的值

b

減數;要從 **a** 中減去的值

d

儲存差的指標

描述

如果發生迴繞,則返回 true,否則返回 false。

**d** 儲存嘗試減法的結果,無論是否發生迴繞。

wrapping_sub

wrapping_sub (type, a, b)

有意執行迴繞減法

引數

type

計算結果的型別

a

被減數;要從中減去的值

b

減數;要從 **a** 中減去的值

描述

返回可能迴繞的減法,而不會觸發任何可能啟用的迴繞清理程式。

wrapping_assign_sub

wrapping_assign_sub (var, offset)

有意執行迴繞遞減賦值

引數

var

要遞減的變數

offset

要減去的量

描述

將 **var** 遞減 **offset**,並進行迴繞。返回 **var** 的結果值。不會觸發任何迴繞清理程式。

返回 **var** 的新值。

check_mul_overflow

check_mul_overflow (a, b, d)

計算乘法並進行溢位檢查

引數

a

第一個因子

b

第二個因子

d

儲存積的指標

描述

如果發生迴繞,則返回 true,否則返回 false。

**d** 儲存嘗試乘法的結果,無論是否發生迴繞。

wrapping_mul

wrapping_mul (type, a, b)

有意執行迴繞乘法

引數

type

計算結果的型別

a

第一個因子

b

第二個因子

描述

返回可能迴繞的乘法,而不會觸發任何可能啟用的迴繞清理程式。

check_shl_overflow

check_shl_overflow (a, s, d)

計算左移值並檢查溢位

引數

a

要移位的值

s

要左移多少位

d

儲存結果的位置的指標

描述

計算 **\*d** = (**a** << **s**)

如果“**\*d**”無法儲存結果,或者“**a** << **s**”沒有意義,則返回 true。示例條件

  • 當儲存在 **\*d** 中時,“**a** << **s**”會導致位丟失。

  • “**s**”是垃圾(例如,負數)或太大,以至於保證“**a** << **s**”的結果為 0。

  • “**a**”是負數。

  • 如果存在任何符號位,“**a** << **s**”會在“**\*d**”中設定符號位。

“**\*d**”將儲存嘗試移位的結果,但如果返回 true,則不被認為是“可以安全使用”。

overflows_type

overflows_type (n, T)

用於檢查值、變數或資料型別之間的溢位的輔助函式

引數

n

要檢查的源常量值或變數

T

建議儲存 **x** 的目標變數或資料型別

描述

比較 **x** 表示式,以確定它是否可以安全地放入 **T** 中型別的儲存中。 **x** 和 **T** 可以具有不同的型別。如果 **x** 是常量表達式,它也會解析為常量表達式。

返回

如果可能發生溢位,則為 true,否則為 false。

castable_to_type

castable_to_type (n, T)

類似於 __same_type(),但也允許強制轉換的文字

引數

n

變數或常量值

T

變數或資料型別

描述

與 __same_type() 宏不同,這允許將常量值作為第一個引數。如果此值不會溢位到第二個引數型別的賦值中,則返回 true。否則,這會回退到 __same_type()。

size_t size_mul(size_t factor1, size_t factor2)

計算 size_t 乘法,並在 SIZE_MAX 處飽和

引數

size_t factor1

第一個因子

size_t factor2

第二個因子

返回

計算 **factor1** * **factor2**,兩者都提升為 size_t,任何溢位都會導致返回值變為 SIZE_MAX。左值必須是 size_t,以避免隱式型別轉換。

size_t size_add(size_t addend1, size_t addend2)

計算 size_t 加法,並在 SIZE_MAX 處飽和

引數

size_t addend1

第一個加數

size_t addend2

第二個加數

返回

計算 **addend1** + **addend2**,兩者都提升為 size_t,任何溢位都會導致返回值變為 SIZE_MAX。左值必須是 size_t,以避免隱式型別轉換。

size_t size_sub(size_t minuend, size_t subtrahend)

計算 size_t 減法,並在 SIZE_MAX 處飽和

引數

size_t minuend

要從中減去的值

size_t subtrahend

要從 **minuend** 中減去的值

返回

計算 **minuend** - **subtrahend**,兩者都提升為 size_t,任何溢位都會導致返回值變為 SIZE_MAX。為了與 size_add()size_mul() 輔助函式組合,兩個引數都不能是 SIZE_MAX(否則結果將被強制為 SIZE_MAX)。左值必須是 size_t,以避免隱式型別轉換。

array_size

array_size (a, b)

計算二維陣列的大小。

引數

a

第一維

b

第二維

描述

計算二維陣列的大小:**a** * **b**。

返回

表示陣列所需的位元組數,如果溢位,則為 SIZE_MAX。

array3_size

array3_size (a, b, c)

計算三維陣列的大小。

引數

a

第一維

b

第二維

c

第三維

描述

計算三維陣列的大小:**a** * **b** * **c**。

返回

表示陣列所需的位元組數,如果溢位,則為 SIZE_MAX。

flex_array_size

flex_array_size (p, member, count)

計算封閉結構中靈活陣列成員的大小。

引數

p

指向結構的指標。

member

靈活陣列成員的名稱。

count

陣列中的元素數。

描述

計算 **p** 結構的末尾處 **count** 個 **member** 元素的靈活陣列的大小。

返回

所需的位元組數,如果溢位,則為 SIZE_MAX。

struct_size

struct_size (p, member, count)

計算帶有尾隨靈活陣列的結構的大小。

引數

p

指向結構的指標。

member

陣列成員的名稱。

count

陣列中的元素數。

描述

計算 **p** 結構後跟 **count** 個 **member** 元素陣列所需的記憶體大小。

返回

所需的位元組數,如果溢位,則為 SIZE_MAX。

struct_size_t

struct_size_t (type, member, count)

計算帶有尾隨靈活陣列的結構的大小

引數

type

結構型別名稱。

member

陣列成員的名稱。

count

陣列中的元素數。

描述

計算 **type** 結構後跟 **count** 個 **member** 元素陣列所需的記憶體大小。如果可能,最好使用 struct_size(),以保持計算與型別 **type** 的特定例項變數相關聯。

返回

所需的位元組數,如果溢位,則為 SIZE_MAX。

__DEFINE_FLEX

__DEFINE_FLEX (type, name, member, count, trailer...)

用於 DEFINE_FLEX() 系列的輔助宏。使呼叫方宏能夠傳遞任意尾隨表示式

引數

type

結構型別名稱,包括“struct”關鍵字。

name

要定義的變數的名稱。

member

陣列成員的名稱。

count

陣列中的元素數;必須是編譯時常量。

trailer...

用於屬性和/或初始值設定項的尾隨表示式。

_DEFINE_FLEX

_DEFINE_FLEX (type, name, member, count, initializer...)

用於 DEFINE_FLEX() 系列的輔助宏。使呼叫方宏能夠傳遞(不同的)initializer。

引數

type

結構型別名稱,包括“struct”關鍵字。

name

要定義的變數的名稱。

member

陣列成員的名稱。

count

陣列中的元素數;必須是編譯時常量。

initializer...

初始化表示式(例如,至少傳遞 = { })。

DEFINE_RAW_FLEX

DEFINE_RAW_FLEX (type, name, member, count)

定義一個具有尾隨可變陣列的結構體的棧上例項,當它沒有 __counted_by 註釋時。

引數

type

結構型別名稱,包括“struct”關鍵字。

name

要定義的變數的名稱。

member

陣列成員的名稱。

count

陣列中的元素數;必須是編譯時常量。

描述

定義一個清零的、具有尾隨可變陣列的 **type** 結構體的棧上例項。之後使用 __struct_size( **name** ) 來獲取其編譯時大小。使用 __member_size( **name->member** ) 來獲取 **name** 成員的編譯時大小。使用 STACK_FLEX_ARRAY_SIZE( **name** , **member** ) 來獲取陣列 **member** 中元素的編譯時數量。

DEFINE_FLEX

DEFINE_FLEX (TYPE, NAME, MEMBER, COUNTER, COUNT)

定義一個具有尾隨可變陣列的結構體的棧上例項。

引數

TYPE

結構型別名稱,包括“struct”關鍵字。

NAME

要定義的變數的名稱。

MEMBER

陣列成員的名稱。

COUNTER

__counted_by 成員的名稱。

COUNT

陣列中的元素數;必須是編譯時常量。

描述

定義一個清零的、具有尾隨可變陣列的 **TYPE** 結構體的棧上例項。之後使用 __struct_size( **NAME** ) 來獲取其編譯時大小。使用 __member_size( **NAME->member** ) 來獲取 **NAME** 成員的編譯時大小。使用 STACK_FLEX_ARRAY_SIZE( **name** , **member** ) 來獲取陣列 **member** 中元素的編譯時數量。

STACK_FLEX_ARRAY_SIZE

STACK_FLEX_ARRAY_SIZE (name, array)

用於 DEFINE_FLEX() 系列的輔助宏。返回 **array** 中的元素數量。

引數

name

DEFINE_RAW_FLEX()/DEFINE_FLEX() 中定義的變數的名稱。

array

陣列成員的名稱。

CRC 函式

uint8_t crc4(uint8_t c, uint64_t x, int bits)

計算值的 4 位 crc。

引數

uint8_t c

起始 crc4

uint64_t x

要校驗和的值

int bits

要校驗和的 **x** 中的位數

描述

返回 **x** 的 crc4 值,使用多項式 0b10111。

**x** 值被視為左對齊,並且在 crc 計算中忽略高於 **bits** 的位。

u8 crc7_be(u8 crc, const u8 *buffer, size_t len)

更新資料緩衝區的 CRC7

引數

u8 crc

先前的 CRC7 值

const u8 *buffer

資料指標

size_t len

緩衝區中的位元組數

上下文

任何

描述

返回更新後的 CRC7 值。 CRC7 在位元組中左對齊(lsbit 始終為 0),因為這使得計算更容易,並且所有呼叫者都希望它採用這種形式。

void crc8_populate_msb(u8 table[CRC8_TABLE_SIZE], u8 polynomial)

以反向位順序填充給定多項式的 crc 表。

引數

u8 table[CRC8_TABLE_SIZE]

要填充的表。

u8 polynomial

要填充表的的多項式。

void crc8_populate_lsb(u8 table[CRC8_TABLE_SIZE], u8 polynomial)

以常規位順序填充給定多項式的 crc 表。

引數

u8 table[CRC8_TABLE_SIZE]

要填充的表。

u8 polynomial

要填充表的的多項式。

u8 crc8(const u8 table[CRC8_TABLE_SIZE], const u8 *pdata, size_t nbytes, u8 crc)

計算給定輸入資料的 crc8。

引數

const u8 table[CRC8_TABLE_SIZE]

用於計算的 crc 表。

const u8 *pdata

指向資料緩衝區的指標。

size_t nbytes

資料緩衝區中的位元組數。

u8 crc

先前返回的 crc8 值。

u16 crc16(u16 crc, const u8 *p, size_t len)

計算資料緩衝區的 CRC-16

引數

u16 crc

先前的 CRC 值

const u8 *p

資料指標

size_t len

緩衝區中的位元組數

描述

返回更新的 CRC 值。

u32 crc32_generic_shift(u32 crc, size_t len, u32 polynomial)

以對數時間將 **len** 個 0 位元組附加到 crc

引數

u32 crc

原始的小端 CRC(即 lsbit 是 x^31 係數)

size_t len

位元組數。 **crc** 乘以 x^(8***len**)

u32 polynomial

用於將結果減少到 32 位的模數。

描述

可以透過計算緩衝區各個範圍上的 CRC,然後將它們相加來並行化 CRC 計算。 這會將給定的 CRC 移動 8*len 位(即產生與將 len 個零位元組附加到資料相同的效果),時間與 log(len) 成正比。

u16 crc_ccitt(u16 crc, u8 const *buffer, size_t len)

重新計算資料緩衝區的 CRC(CRC-CCITT 變體)

引數

u16 crc

先前的 CRC 值

u8 const *buffer

資料指標

size_t len

緩衝區中的位元組數

u16 crc_itu_t(u16 crc, const u8 *buffer, size_t len)

計算資料緩衝區的 CRC-ITU-T

引數

u16 crc

先前的 CRC 值

const u8 *buffer

資料指標

size_t len

緩衝區中的位元組數

描述

返回更新後的 CRC 值

以 2 為底的對數和冪函式

bool is_power_of_2(unsigned long n)

檢查一個值是否為 2 的冪

引數

unsigned long n

要檢查的值

描述

確定某個值是否為 2 的冪,其中零被視為 2 的冪。

返回

如果 **n** 是 2 的冪,則為 true,否則為 false。

unsigned long __roundup_pow_of_two(unsigned long n)

向上舍入到最接近的 2 的冪

引數

unsigned long n

要向上舍入的值

unsigned long __rounddown_pow_of_two(unsigned long n)

向下舍入到最接近的 2 的冪

引數

unsigned long n

要向下舍入的值

const_ilog2

const_ilog2 (n)

32 位或 64 位常量無符號值的以 2 為底的對數

引數

n

引數

描述

在 sparse 期望一個真常量表達式的地方使用它,例如,用於陣列索引。

ilog2

ilog2 (n)

32 位或 64 位無符號值的以 2 為底的對數

引數

n

引數

描述

具有常量能力的以 2 為底的對數計算 - 這可以用於從常量資料初始化全域性變數,因此需要大量的二元運算子構造

根據 sizeof(n) 選擇適當大小的最佳化版本

roundup_pow_of_two

roundup_pow_of_two (n)

將給定值向上舍入到最接近的 2 的冪

引數

n

引數

描述

將給定值向上舍入到最接近的 2 的冪 - 當 n == 0 時,結果是未定義的 - 這可以用於從常量資料初始化全域性變數

rounddown_pow_of_two

rounddown_pow_of_two (n)

將給定值向下舍入到最接近的 2 的冪

引數

n

引數

描述

將給定值向下舍入到最接近的 2 的冪 - 當 n == 0 時,結果是未定義的 - 這可以用於從常量資料初始化全域性變數

order_base_2

order_base_2 (n)

計算引數的(向上舍入的)以 2 為底的階數

引數

n

引數

描述

此例程計算的前幾個值

ob2(0) = 0 ob2(1) = 0 ob2(2) = 1 ob2(3) = 2 ob2(4) = 2 ob2(5) = 3 ... 等等。

bits_per

bits_per (n)

計算引數所需的位數

引數

n

引數

描述

這具有常量能力,可以用於編譯時初始化,例如位域。

此例程計算的前幾個值: bf(0) = 1 bf(1) = 1 bf(2) = 2 bf(3) = 2 bf(4) = 3 ... 等等。

整數對數和冪函式

unsigned int intlog2(u32 value)

計算值的 log2;結果左移 24 位

引數

u32 value

該值(必須 != 0)

描述

要使用合理的值,您可以使用以下方法

intlog2(value) = intlog2(value * 2^x) - x * 2^24

一些用例示例

intlog2(8) 將給出 3 << 24 = 3 * 2^24

intlog2(9) 將給出 3 << 24 + ... = 3.16... * 2^24

intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24

返回

log2(value) * 2^24

unsigned int intlog10(u32 value)

計算值的 log10;結果左移 24 位

引數

u32 value

該值(必須 != 0)

描述

要使用合理的值,您可以使用以下方法

intlog10(value) = intlog10(value * 10^x) - x * 2^24

一個用例示例

intlog10(1000) 將給出 3 << 24 = 3 * 2^24

由於實現 intlog10(1000) 可能不完全是 3 * 2^24

檢視 intlog2 以獲取類似的示例

返回

log10(value) * 2^24

u64 int_pow(u64 base, unsigned int exp)

計算給定底數和指數的指數

引數

u64 base

將提高到給定冪的底數

unsigned int exp

要提高到的冪

描述

計算:pow(base, exp),即 **base** 提高到 **exp** 次冪

unsigned long int_sqrt(unsigned long x)

計算整數平方根

引數

unsigned long x

要計算平方根的整數

描述

計算:floor(sqrt(x))

u32 int_sqrt64(u64 x)

當需要最小 64 位輸入時,強烈型別的 int_sqrt 函式。

引數

u64 x

用於計算平方根的 64 位整數

除法函式

do_div

do_div (n, base)

返回 2 個值:計算餘數並更新新的被除數

引數

n

uint64_t 被除數(將被更新)

base

uint32_t 除數

描述

摘要:uint32_t remainder = n % base; n = n / base;

返回

(uint32_t)remainder

注意

宏引數 n 會被多次計算,小心副作用!

u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)

帶 32 位除數的無符號 64 位除法,並返回餘數

引數

u64 dividend

無符號 64 位被除數

u32 divisor

無符號 32 位除數

u32 *remainder

指向無符號 32 位餘數的指標

返回

設定 *remainder,然後返回 被除數 / 除數

描述

通常由 32 位架構提供,以提供最佳化的 64 位除法。

s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)

帶 32 位除數的有符號 64 位除法,並返回餘數

引數

s64 dividend

有符號 64 位被除數

s32 divisor

有符號 32 位除數

s32 *remainder

指向有符號 32 位餘數的指標

返回

設定 *remainder,然後返回 被除數 / 除數

u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder)

帶 64 位除數的無符號 64 位除法,並返回餘數

引數

u64 dividend

無符號 64 位被除數

u64 divisor

無符號 64 位除數

u64 *remainder

指向無符號 64 位餘數的指標

返回

設定 *remainder,然後返回 被除數 / 除數

u64 div64_u64(u64 dividend, u64 divisor)

帶 64 位除數的無符號 64 位除法

引數

u64 dividend

無符號 64 位被除數

u64 divisor

無符號 64 位除數

返回

被除數 / 除數

s64 div64_s64(s64 dividend, s64 divisor)

帶 64 位除數的有符號 64 位除法

引數

s64 dividend

有符號 64 位被除數

s64 divisor

有符號 64 位除數

返回

被除數 / 除數

u64 div_u64(u64 dividend, u32 divisor)

帶 32 位除數的無符號 64 位除法

引數

u64 dividend

無符號 64 位被除數

u32 divisor

無符號 32 位除數

描述

這是最常見的 64 位除法,如果可能,應該使用它,因為許多 32 位架構可以比完整的 64 位除法更好地最佳化這個變體。

返回

被除數 / 除數

s64 div_s64(s64 dividend, s32 divisor)

帶 32 位除數的有符號 64 位除法

引數

s64 dividend

有符號 64 位被除數

s32 divisor

有符號 32 位除數

返回

被除數 / 除數

DIV64_U64_ROUND_UP

DIV64_U64_ROUND_UP (ll, d)

帶 64 位除數的無符號 64 位除法,向上舍入

引數

ll

無符號 64 位被除數

d

無符號 64 位除數

描述

將無符號 64 位被除數除以無符號 64 位除數並向上舍入。

返回

被除數 / 除數,向上舍入

DIV_U64_ROUND_UP

DIV_U64_ROUND_UP (ll, d)

帶 32 位除數的無符號 64 位除法,向上舍入

引數

ll

無符號 64 位被除數

d

無符號 32 位除數

描述

將無符號 64 位被除數除以無符號 32 位除數並向上舍入。

返回

被除數 / 除數,向上舍入

DIV64_U64_ROUND_CLOSEST

DIV64_U64_ROUND_CLOSEST (dividend, divisor)

帶 64 位除數的無符號 64 位除法,舍入到最接近的整數

引數

dividend

無符號 64 位被除數

divisor

無符號 64 位除數

描述

將無符號 64 位被除數除以無符號 64 位除數並舍入到最接近的整數。

返回

被除數 / 除數,舍入到最接近的整數

DIV_U64_ROUND_CLOSEST

DIV_U64_ROUND_CLOSEST (dividend, divisor)

帶 32 位除數的無符號 64 位除法,舍入到最接近的整數

引數

dividend

無符號 64 位被除數

divisor

無符號 32 位除數

描述

將無符號 64 位被除數除以無符號 32 位除數並舍入到最接近的整數。

返回

被除數 / 除數,舍入到最接近的整數

DIV_S64_ROUND_CLOSEST

DIV_S64_ROUND_CLOSEST (dividend, divisor)

帶 32 位除數的有符號 64 位除法,舍入到最接近的整數

引數

dividend

有符號 64 位被除數

divisor

有符號 32 位除數

描述

將有符號 64 位被除數除以有符號 32 位除數並舍入到最接近的整數。

返回

被除數 / 除數,舍入到最接近的整數

u64 roundup_u64(u64 x, u32 y)

將 64 位值向上舍入到下一個指定的 32 位倍數

引數

u64 x

要向上舍入的值

u32 y

要向上舍入到的 32 位倍數

描述

x 舍入到 y 的下一個倍數。對於 32 位 x 值,請參閱 roundup 和更快的 round_up(),適用於 2 的冪。

返回

向上舍入的值。

unsigned long gcd(unsigned long a, unsigned long b)

計算並返回 2 個無符號長整型的最大公約數

引數

unsigned long a

第一個值

unsigned long b

第二個值

UUID/GUID

void generate_random_uuid(unsigned char uuid[16])

生成一個隨機 UUID

引數

unsigned char uuid[16]

將生成的 UUID 放入何處

描述

隨機 UUID 介面

用於建立啟動 ID 或檔案系統 UUID/GUID,但對於其他核心驅動程式也很有用。

bool uuid_is_valid(const char *uuid)

檢查 UUID 字串是否有效

引數

const char *uuid

要檢查的 UUID 字串

描述

它檢查 UUID 字串是否符合格式

xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

其中 x 是一個十六進位制數字。

返回

如果輸入是有效的 UUID 字串,則為 true。

核心 IPC 機制

IPC 實用程式

int ipc_init(void)

初始化 ipc 子系統

引數

void

無引數

描述

初始化各種 sysv ipc 資源(訊號量、訊息和共享記憶體)。

一個回撥例程被註冊到記憶體熱插拔通知鏈中:由於 msgmni 擴充套件到 lowmem,因此在成功新增/刪除記憶體後,將呼叫此回撥例程以重新計算 msmgni。

void ipc_init_ids(struct ipc_ids *ids)

初始化 ipc 識別符號

引數

struct ipc_ids *ids

ipc 識別符號集

描述

設定用於 ipc 識別符號範圍的序列範圍(限制在 ipc_mni 以下),然後初始化金鑰雜湊表和 ids idr。

void ipc_init_proc_interface(const char *path, const char *header, int ids, int (*show)(struct seq_file*, void*))

使用 seq_file 介面為 sysipc 型別建立一個 proc 介面。

引數

const char *path

procfs 中的路徑

const char *header

要在檔案開頭列印的橫幅。

int ids

要迭代的 ipc id 表。

int (*show)(struct seq_file *, void *)

show 例程。

struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)

在 ipc 識別符號集中查詢金鑰

引數

struct ipc_ids *ids

ipc 識別符號集

key_t key

要查詢的金鑰

描述

如果找到,則返回指向 ipc 結構的鎖定指標,否則返回 NULL。如果找到金鑰,則 ipc 指向擁有的 ipc 結構

使用 writer ipc_ids.rwsem 持有來呼叫。

int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int limit)

新增一個 ipc 識別符號

引數

struct ipc_ids *ids

ipc 識別符號集

struct kern_ipc_perm *new

新的 ipc 許可權集

int limit

已使用 id 的數量限制

描述

向 ipc ids idr 新增一個條目“new”。許可權物件被初始化,並設定第一個空閒條目,並返回分配的索引。“new”條目在成功時以鎖定狀態返回。

如果失敗,則該條目未被鎖定,並返回一個負錯誤程式碼。呼叫者必須使用 ipc_rcu_putref() 來釋放識別符號。

使用 writer ipc_ids.rwsem 持有來呼叫。

int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids, const struct ipc_ops *ops, struct ipc_params *params)

建立一個新的 ipc 物件

引數

struct ipc_namespace *ns

ipc 名稱空間

struct ipc_ids *ids

ipc 識別符號集

const struct ipc_ops *ops

要呼叫的實際建立例程

struct ipc_params *params

其引數

描述

當金鑰為 IPC_PRIVATE 時,sys_msgget、sys_semget() 和 sys_shmget() 會呼叫此例程。

int ipc_check_perms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, const struct ipc_ops *ops, struct ipc_params *params)

檢查 ipc 物件的安全和許可權

引數

struct ipc_namespace *ns

ipc 名稱空間

struct kern_ipc_perm *ipcp

ipc 許可權集合

const struct ipc_ops *ops

要呼叫的實際安全例程

struct ipc_params *params

其引數

描述

當鍵不是 IPC_PRIVATE 並且該鍵已存在於 ds IDR 中時,sys_msgget()、sys_semget() 和 sys_shmget() 會呼叫此例程。

成功時,返回 ipc id。

呼叫時會持有 ipc_ids.rwsem 和 ipcp->lock。

int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids, const struct ipc_ops *ops, struct ipc_params *params)

獲取一個 ipc 物件或建立一個新的 ipc 物件

引數

struct ipc_namespace *ns

ipc 名稱空間

struct ipc_ids *ids

ipc 識別符號集

const struct ipc_ops *ops

要呼叫的實際建立例程

struct ipc_params *params

其引數

描述

當鍵不是 IPC_PRIVATE 時,sys_msgget、sys_semget() 和 sys_shmget() 會呼叫此例程。如果找不到該鍵,則會新增一個新條目;如果找到該鍵,則會進行一些許可權/安全檢查。

成功時,返回 ipc id。

void ipc_kht_remove(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)

從鍵雜湊表中刪除一個 ipc

引數

struct ipc_ids *ids

ipc 識別符號集

struct kern_ipc_perm *ipcp

包含要刪除的鍵的 ipc perm 結構

描述

在此函式被呼叫之前,會持有 ipc_ids.rwsem(作為寫入者)和此 ID 的自旋鎖,並且在退出時保持鎖定。

int ipc_search_maxidx(struct ipc_ids *ids, int limit)

搜尋分配的最高索引

引數

struct ipc_ids *ids

ipc 識別符號集

int limit

分配的最高索引的已知上限

描述

該函式確定 **ids** 中分配的最高索引。它旨在在需要更新 ids->max_idx 時呼叫。當刪除當前最高索引 ipc 物件時,更新 ids->max_idx 是必要的。如果沒有分配 ipc 物件,則返回 -1。

ipc_ids.rwsem 需要由呼叫者持有。

void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)

刪除一個 ipc 識別符號

引數

struct ipc_ids *ids

ipc 識別符號集

struct kern_ipc_perm *ipcp

包含要刪除的識別符號的 ipc perm 結構

描述

在此函式被呼叫之前,會持有 ipc_ids.rwsem(作為寫入者)和此 ID 的自旋鎖,並且在退出時保持鎖定。

void ipc_set_key_private(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)

將現有 ipc 的鍵切換到 IPC_PRIVATE

引數

struct ipc_ids *ids

ipc 識別符號集

struct kern_ipc_perm *ipcp

包含要修改的鍵的 ipc perm 結構

描述

在此函式被呼叫之前,會持有 ipc_ids.rwsem(作為寫入者)和此 ID 的自旋鎖,並且在退出時保持鎖定。

int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag)

檢查 ipc 許可權

引數

struct ipc_namespace *ns

ipc 名稱空間

struct kern_ipc_perm *ipcp

ipc 許可權集合

short flag

所需的許可權集合

描述

檢查使用者、組、其他使用者對 ipc 資源的訪問許可權。如果允許,則返回 0

**flag** 最有可能為 0 或 <linux/stat.h> 中的 S_...UGO

void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out)

將核心 ipc 許可權轉換為使用者許可權

引數

struct kern_ipc_perm *in

核心許可權

struct ipc64_perm *out

新樣式的 ipc 許可權

描述

將核心物件 **in** 轉換為一組許可權描述,以便返回給使用者空間 (**out**)。

void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out)

將新的 ipc 許可權轉換為舊的 ipc 許可權

引數

struct ipc64_perm *in

新樣式的 ipc 許可權

struct ipc_perm *out

舊樣式的 ipc 許可權

描述

將新樣式的許可權物件 **in** 轉換為一個相容性物件,並將其儲存到 **out** 指標中。

struct kern_ipc_perm *ipc_obtain_object_idr(struct ipc_ids *ids, int id)

在 ipc ids idr 中查詢一個 id,並返回關聯的 ipc 物件。

引數

struct ipc_ids *ids

ipc 識別符號集

int id

要查詢的 ipc id

描述

在 RCU 臨界區內呼叫。退出時 ipc 物件鎖定。

struct kern_ipc_perm *ipc_obtain_object_check(struct ipc_ids *ids, int id)

ipc_obtain_object_idr() 類似,但也檢查 ipc 物件序列號。

引數

struct ipc_ids *ids

ipc 識別符號集

int id

要查詢的 ipc id

描述

在 RCU 臨界區內呼叫。退出時 ipc 物件鎖定。

int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids, const struct ipc_ops *ops, struct ipc_params *params)

通用的 sys_*get() 程式碼

引數

struct ipc_namespace *ns

名稱空間

struct ipc_ids *ids

ipc 識別符號集

const struct ipc_ops *ops

要在 ipc 物件建立、許可權檢查和進一步檢查時呼叫的操作

struct ipc_params *params

先前操作所需的引數。

描述

sys_msgget()、sys_semget() 和 sys_shmget() 呼叫的通用例程。

int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)

更新 ipc 物件的許可權

引數

struct ipc64_perm *in

作為輸入給定的許可權。

struct kern_ipc_perm *out

要設定的 ipc 的許可權。

struct kern_ipc_perm *ipcctl_obtain_check(struct ipc_namespace *ns, struct ipc_ids *ids, int id, int cmd, struct ipc64_perm *perm, int extra_perm)

檢索 ipc 物件並檢查許可權

引數

struct ipc_namespace *ns

ipc 名稱空間

struct ipc_ids *ids

要在其中查詢 ipc 的 id 表

int id

要檢索的 ipc 的 id

int cmd

要檢查的 cmd

struct ipc64_perm *perm

要設定的許可權

int extra_perm

msq 使用的一個額外的許可權引數

描述

此函式為某些 IPC_XXX cmd 執行一些常見的審計和許可權檢查,並從 semctl_down、shmctl_down 和 msgctl_down 呼叫。

  • 使用給定 id 在給定表中檢索 ipc 物件。

  • 根據給定的 cmd 執行一些審計和許可權檢查

  • 返回指向 ipc 物件的指標,否則返回相應的錯誤。

呼叫時持有 rwsem 和 rcu 讀鎖。

int ipc_parse_version(int *cmd)

ipc 呼叫版本

引數

int *cmd

指向命令的指標

描述

對於新的 IPC 樣式,返回 IPC_64;對於舊的 IPC 樣式,返回 IPC_OLD。 **cmd** 值從編碼命令和版本轉換為僅命令程式碼。

struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t *pos)

基於 seq pos 查詢並鎖定 ipc 結構

引數

struct ipc_ids *ids

ipc 識別符號集

loff_t *pos

預期位置

描述

該函式基於序列檔案位置 **pos** 查詢 ipc 結構。如果在位置 **pos** 處沒有 ipc 結構,則選擇後繼者。如果找到一個結構,則鎖定它(同時鎖定 rcu_read_lock() 和 ipc_lock_object()),並且將 **pos** 設定為定位找到的 ipc 結構所需的位置。如果未找到任何內容(即 EOF),則 **pos** 不會被修改。

該函式返回找到的 ipc 結構,或者在 EOF 時返回 NULL。

FIFO 緩衝區

kfifo 介面

DECLARE_KFIFO_PTR

DECLARE_KFIFO_PTR (fifo, type)

宣告一個 fifo 指標物件的宏

引數

fifo

宣告的 fifo 的名稱

type

fifo 元素的型別

DECLARE_KFIFO

DECLARE_KFIFO (fifo, type, size)

宣告一個 fifo 物件的宏

引數

fifo

宣告的 fifo 的名稱

type

fifo 元素的型別

size

fifo 中的元素數量,這必須是 2 的冪

INIT_KFIFO

INIT_KFIFO (fifo)

初始化由 DECLARE_KFIFO 宣告的 fifo

引數

fifo

宣告的 fifo 資料型別的名稱

DEFINE_KFIFO

DEFINE_KFIFO (fifo, type, size)

定義並初始化一個 fifo 的宏

引數

fifo

宣告的 fifo 資料型別的名稱

type

fifo 元素的型別

size

fifo 中的元素數量,這必須是 2 的冪

注意

該宏可用於全域性和本地 fifo 資料型別變數。

kfifo_initialized

kfifo_initialized (fifo)

檢查 fifo 是否已初始化

引數

fifo

要檢查的 fifo 的地址

描述

如果 fifo 已初始化,則返回 true,否則返回 false。假設 fifo 之前為 0。

kfifo_esize

kfifo_esize (fifo)

返回 fifo 管理的元素的大小

引數

fifo

要使用的 fifo 的地址

kfifo_recsize

kfifo_recsize (fifo)

返回記錄長度欄位的大小

引數

fifo

要使用的 fifo 的地址

kfifo_size

kfifo_size (fifo)

返回 fifo 的元素大小

引數

fifo

要使用的 fifo 的地址

kfifo_reset

kfifo_reset (fifo)

刪除整個 fifo 內容

引數

fifo

要使用的 fifo 的地址

注意

使用 kfifo_reset() 是危險的。它應該只在 FIFO 被獨佔鎖定,或者確保沒有其他執行緒訪問 FIFO 時呼叫。

kfifo_reset_out

kfifo_reset_out (fifo)

跳過 FIFO 內容

引數

fifo

要使用的 fifo 的地址

注意

使用 kfifo_reset_out() 是安全的,前提是它只從讀取執行緒呼叫,並且只有一個併發讀取器。否則,它是危險的,必須以與 kfifo_reset() 相同的方式處理。

kfifo_len

kfifo_len (fifo)

返回 FIFO 中已用元素的數量

引數

fifo

要使用的 fifo 的地址

kfifo_is_empty

kfifo_is_empty (fifo)

如果 FIFO 為空,則返回 true

引數

fifo

要使用的 fifo 的地址

kfifo_is_empty_spinlocked

kfifo_is_empty_spinlocked (fifo, lock)

如果 FIFO 為空,則返回 true,使用自旋鎖進行鎖定

引數

fifo

要使用的 fifo 的地址

lock

用於鎖定的自旋鎖

kfifo_is_empty_spinlocked_noirqsave

kfifo_is_empty_spinlocked_noirqsave (fifo, lock)

如果 FIFO 為空,則返回 true,使用自旋鎖進行鎖定,不停用中斷

引數

fifo

要使用的 fifo 的地址

lock

用於鎖定的自旋鎖

kfifo_is_full

kfifo_is_full (fifo)

如果 FIFO 已滿,則返回 true

引數

fifo

要使用的 fifo 的地址

kfifo_avail

kfifo_avail (fifo)

返回 FIFO 中未使用的元素的數量

引數

fifo

要使用的 fifo 的地址

kfifo_skip_count

kfifo_skip_count (fifo, count)

跳過輸出資料

引數

fifo

要使用的 fifo 的地址

count

要跳過的資料計數

kfifo_skip

kfifo_skip (fifo)

跳過輸出資料

引數

fifo

要使用的 fifo 的地址

kfifo_peek_len

kfifo_peek_len (fifo)

獲取下一個 FIFO 記錄的大小

引數

fifo

要使用的 fifo 的地址

描述

此函式返回下一個 FIFO 記錄的大小,以位元組為單位。

kfifo_alloc

kfifo_alloc (fifo, size, gfp_mask)

動態分配一個新的 FIFO 緩衝區

引數

fifo

指向 FIFO 的指標

size

fifo 中的元素數量,這必須是 2 的冪

gfp_mask

get_free_pages 掩碼,傳遞給 kmalloc()

描述

此宏動態分配一個新的 FIFO 緩衝區。

元素的數量將向上舍入為 2 的冪。FIFO 將透過 kfifo_free() 釋放。如果沒有錯誤,則返回 0,否則返回一個錯誤程式碼。

kfifo_free

kfifo_free (fifo)

釋放 FIFO

引數

fifo

要釋放的 FIFO

kfifo_init

kfifo_init (fifo, buffer, size)

使用預先分配的緩衝區初始化 FIFO

引數

fifo

要分配緩衝區的 FIFO

buffer

要使用的預先分配的緩衝區

size

內部緩衝區的大小,這必須是 2 的冪

描述

此宏使用預先分配的緩衝區初始化 FIFO。

元素的數量將向上舍入為 2 的冪。如果沒有錯誤,則返回 0,否則返回一個錯誤程式碼。

kfifo_put

kfifo_put (fifo, val)

將資料放入 FIFO

引數

fifo

要使用的 fifo 的地址

val

要新增的資料

描述

此宏將給定的值複製到 FIFO 中。如果 FIFO 已滿,則返回 0。否則,它返回已處理元素的數量。

請注意,只有單個併發讀取器和單個併發寫入器,您不需要額外的鎖定即可使用這些宏。

kfifo_get

kfifo_get (fifo, val)

從 FIFO 獲取資料

引數

fifo

要使用的 fifo 的地址

val

儲存資料的地址

描述

此宏從 FIFO 讀取資料。如果 FIFO 為空,則返回 0。否則,它返回已處理元素的數量。

請注意,只有單個併發讀取器和單個併發寫入器,您不需要額外的鎖定即可使用這些宏。

kfifo_peek

kfifo_peek (fifo, val)

從 FIFO 獲取資料而不刪除

引數

fifo

要使用的 fifo 的地址

val

儲存資料的地址

描述

這從 FIFO 讀取資料而不從 FIFO 中刪除它。如果 FIFO 為空,則返回 0。否則,它返回已處理元素的數量。

請注意,只有單個併發讀取器和單個併發寫入器,您不需要額外的鎖定即可使用這些宏。

kfifo_in

kfifo_in (fifo, buf, n)

將資料放入 FIFO

引數

fifo

要使用的 fifo 的地址

buf

要新增的資料

n

要新增的元素的數量

描述

此宏將給定的緩衝區複製到 FIFO 中,並返回複製的元素的數量。

請注意,只有單個併發讀取器和單個併發寫入器,您不需要額外的鎖定即可使用這些宏。

kfifo_in_spinlocked

kfifo_in_spinlocked (fifo, buf, n, lock)

將資料放入 FIFO,使用自旋鎖進行鎖定

引數

fifo

要使用的 fifo 的地址

buf

要新增的資料

n

要新增的元素的數量

lock

指向用於鎖定的自旋鎖的指標

描述

此宏將給定的值緩衝區複製到 FIFO 中,並返回複製的元素的數量。

kfifo_in_spinlocked_noirqsave

kfifo_in_spinlocked_noirqsave (fifo, buf, n, lock)

將資料放入 FIFO,使用自旋鎖進行鎖定,不停用中斷

引數

fifo

要使用的 fifo 的地址

buf

要新增的資料

n

要新增的元素的數量

lock

指向用於鎖定的自旋鎖的指標

描述

這是 kfifo_in_spinlocked() 的一個變體,但使用 spin_lock/unlock() 進行鎖定,並且不停用中斷。

kfifo_out

kfifo_out (fifo, buf, n)

從 FIFO 獲取資料

引數

fifo

要使用的 fifo 的地址

buf

指向儲存緩衝區的指標

n

要獲取的元素的最大數量

描述

此宏從 FIFO 獲取一些資料,並返回複製的元素的數量。

請注意,只有單個併發讀取器和單個併發寫入器,您不需要額外的鎖定即可使用這些宏。

kfifo_out_spinlocked

kfifo_out_spinlocked (fifo, buf, n, lock)

從 FIFO 獲取資料,使用自旋鎖進行鎖定

引數

fifo

要使用的 fifo 的地址

buf

指向儲存緩衝區的指標

n

要獲取的元素的最大數量

lock

指向用於鎖定的自旋鎖的指標

描述

此宏從 FIFO 獲取資料,並返回複製的元素的數量。

kfifo_out_spinlocked_noirqsave

kfifo_out_spinlocked_noirqsave (fifo, buf, n, lock)

從 FIFO 獲取資料,使用自旋鎖進行鎖定,不停用中斷

引數

fifo

要使用的 fifo 的地址

buf

指向儲存緩衝區的指標

n

要獲取的元素的最大數量

lock

指向用於鎖定的自旋鎖的指標

描述

這是 kfifo_out_spinlocked() 的一個變體,它使用 spin_lock/unlock() 進行鎖定,並且不停用中斷。

kfifo_from_user

kfifo_from_user (fifo, from, len, copied)

將一些來自使用者空間的資料放入 FIFO

引數

fifo

要使用的 fifo 的地址

from

指向要新增的資料的指標

len

要新增的資料的長度

copied

指向輸出變數的指標,用於儲存複製的位元組數

描述

此宏從 **from** 將最多 **len** 個位元組複製到 FIFO 中,具體取決於可用空間,並返回 -EFAULT/0。

請注意,只有單個併發讀取器和單個併發寫入器,您不需要額外的鎖定即可使用這些宏。

kfifo_to_user

kfifo_to_user (fifo, to, len, copied)

將資料從 FIFO 複製到使用者空間

引數

fifo

要使用的 fifo 的地址

to

必須將資料複製到哪裡

len

目標緩衝區的大小

copied

指向輸出變數的指標,用於儲存複製的位元組數

描述

此宏從 FIFO 將最多 **len** 個位元組複製到 **to** 緩衝區,並返回 -EFAULT/0。

請注意,只有單個併發讀取器和單個併發寫入器,您不需要額外的鎖定即可使用這些宏。

kfifo_dma_in_prepare_mapped

kfifo_dma_in_prepare_mapped (fifo, sgl, nents, len, dma)

設定用於 DMA 輸入的散列表

引數

fifo

要使用的 fifo 的地址

sgl

指向散列表陣列的指標

nents

散列表陣列中的條目數

len

要傳輸的元素的數量

dma

要填充到 **sgl** 中的對映的 DMA 地址

描述

此宏填充用於 DMA 輸入的散列表。它返回散列表陣列中的條目數。

請注意,只有單個併發讀取器和單個併發寫入器,您不需要額外的鎖定即可使用這些宏。

kfifo_dma_in_finish

kfifo_dma_in_finish (fifo, len)

完成 DMA IN 操作

引數

fifo

要使用的 fifo 的地址

len

要接收的位元組數

描述

此宏完成 DMA IN 操作。in 計數器將由 len 引數更新。不會進行錯誤檢查。

請注意,只有單個併發讀取器和單個併發寫入器,您不需要額外的鎖定即可使用這些宏。

kfifo_dma_out_prepare_mapped

kfifo_dma_out_prepare_mapped (fifo, sgl, nents, len, dma)

設定用於 DMA 輸出的散列表

引數

fifo

要使用的 fifo 的地址

sgl

指向散列表陣列的指標

nents

散列表陣列中的條目數

len

要傳輸的元素的數量

dma

要填充到 **sgl** 中的對映的 DMA 地址

描述

此宏填充用於 DMA 輸出的散列表,最多傳輸 **len** 個位元組。它返回散列表陣列中的條目數。零表示沒有可用空間,並且未填充散列表。

請注意,只有單個併發讀取器和單個併發寫入器,您不需要額外的鎖定即可使用這些宏。

kfifo_dma_out_finish

kfifo_dma_out_finish (fifo, len)

完成 DMA OUT 操作

引數

fifo

要使用的 fifo 的地址

len

傳輸的位元組數

描述

此宏完成 DMA OUT 操作。out 計數器將由 len 引數更新。不會進行錯誤檢查。

請注意,只有單個併發讀取器和單個併發寫入器,您不需要額外的鎖定即可使用這些宏。

kfifo_out_peek

kfifo_out_peek (fifo, buf, n)

從 FIFO 獲取一些資料

引數

fifo

要使用的 fifo 的地址

buf

指向儲存緩衝區的指標

n

要獲取的元素的最大數量

描述

此宏從 FIFO 獲取資料,並返回複製的元素的數量。資料不會從 FIFO 中刪除。

請注意,只有單個併發讀取器和單個併發寫入器,您不需要額外的鎖定即可使用這些宏。

kfifo_out_linear

kfifo_out_linear (fifo, tail, n)

獲取可用資料的尾部/偏移量

引數

fifo

要使用的 fifo 的地址

tail

指向要儲存尾部值的無符號整數的指標

n

要指向的元素的最大數量

描述

此宏獲取 FIFO 緩衝區中可用資料的偏移量(尾部),並返回可用元素的數量。它返回到資料結尾或緩衝區結尾的可用計數。因此,它可以用於線性資料處理(如 memcpy() of ( **fifo->data** + **tail**) with 返回的計數)。

請注意,只有單個併發讀取器和單個併發寫入器,您不需要額外的鎖定即可使用這些宏。

kfifo_out_linear_ptr

kfifo_out_linear_ptr (fifo, ptr, n)

獲取指向可用資料的指標

引數

fifo

要使用的 fifo 的地址

ptr

指向要儲存指向尾部的指標的資料的指標

n

要指向的元素的最大數量

描述

kfifo_out_linear() 類似,此宏獲取 FIFO 緩衝區中可用資料的指標,並返回可用元素的數量。它返回到可用資料結尾或緩衝區結尾的可用計數。因此,它可以用於線性資料處理(如 memcpy() of **ptr** with 返回的計數)。

請注意,只有單個併發讀取器和單個併發寫入器,您不需要額外的鎖定即可使用這些宏。

繼電器介面支援

繼電器介面支援旨在為工具和設施提供一種有效的機制,以便將大量資料從核心空間傳遞到使用者空間。

繼電器介面

int relay_buf_full(struct rchan_buf *buf)

布林值,通道緩衝區是否已滿?

引數

struct rchan_buf *buf

通道緩衝區

如果緩衝區已滿,則返回 1,否則返回 0。

void relay_reset(struct rchan *chan)

重置通道

引數

struct rchan *chan

通道

這具有擦除所有通道緩衝區中的所有資料,並以其初始狀態重新啟動通道的效果。緩衝區不會被釋放,因此任何對映仍然有效。

注意。應注意,在進行此呼叫時,該通道實際上沒有被任何東西使用。

struct rchan *relay_open(const char *base_filename, struct dentry *parent, size_t subbuf_size, size_t n_subbufs, const struct rchan_callbacks *cb, void *private_data)

建立一個新的繼電器通道

引數

const char *base_filename

要建立的檔案的基本名稱

struct dentry *parent

父目錄的目錄項,根目錄或緩衝區的 NULL

size_t subbuf_size

子緩衝區的大小

size_t n_subbufs

子緩衝區的數量

const struct rchan_callbacks *cb

客戶端回撥函式

void *private_data

使用者定義的資料

如果成功,則返回通道指標,否則返回 NULL

使用指定的大小和屬性為每個 CPU 建立一個通道緩衝區。建立的通道緩衝區檔案將命名為 base_filename0...base_filenameN-1。檔案許可權將為 S_IRUSR

size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length)

切換到新的子緩衝區

引數

struct rchan_buf *buf

通道緩衝區

size_t length

當前事件的大小

如果緩衝區已滿,則返回傳入的長度,否則返回 0。

執行子緩衝區切換任務,例如呼叫回撥函式、更新填充計數、喚醒讀取器等。

void relay_subbufs_consumed(struct rchan *chan, unsigned int cpu, size_t subbufs_consumed)

更新緩衝區的已消耗子緩衝區計數

引數

struct rchan *chan

通道

unsigned int cpu

要更新的通道緩衝區關聯的 CPU

size_t subbufs_consumed

要新增到當前緩衝區計數的子緩衝區數量

新增到通道緩衝區已消耗的子緩衝區計數。 subbufs_consumed 應該是新消耗的子緩衝區的數量,而不是總共消耗的數量。

注意:如果通道模式為“overwrite”,則核心客戶端無需呼叫此函式。

void relay_close(struct rchan *chan)

關閉通道

引數

struct rchan *chan

通道

關閉所有通道緩衝區並釋放通道。

void relay_flush(struct rchan *chan)

關閉通道

引數

struct rchan *chan

通道

重新整理所有通道緩衝區,即強制緩衝區切換。

int relay_mmap_buf(struct rchan_buf *buf, struct vm_area_struct *vma)
  • 將通道緩衝區 mmap 到程序地址空間

引數

struct rchan_buf *buf

relay 通道緩衝區

struct vm_area_struct *vma

描述要對映的記憶體的 vm_area_struct

如果成功則返回 0,出錯則返回負數

呼叫者應已獲取 mmap_lock。

void *relay_alloc_buf(struct rchan_buf *buf, size_t *size)

分配通道緩衝區

引數

struct rchan_buf *buf

緩衝區結構體

size_t *size

緩衝區的總大小

返回指向結果緩衝區的指標,如果失敗則返回 NULL。傳入的大小將被頁對齊(如果尚未對齊)。

struct rchan_buf *relay_create_buf(struct rchan *chan)

分配並初始化通道緩衝區

引數

struct rchan *chan

relay 通道

如果成功,則返回通道緩衝區,否則返回 NULL

void relay_destroy_channel(struct kref *kref)

釋放通道結構體

引數

struct kref *kref

包含 relay 通道的目標核心引用

只能從 kref_put() 呼叫。

void relay_destroy_buf(struct rchan_buf *buf)

銷燬 rchan_buf 結構體和關聯的緩衝區

引數

struct rchan_buf *buf

緩衝區結構體

void relay_remove_buf(struct kref *kref)

移除通道緩衝區

引數

struct kref *kref

包含 relay 緩衝區的目標核心引用

從檔案系統中移除該檔案,同時釋放 rchan_buf_struct 和通道緩衝區。 只能從 kref_put() 呼叫。

int relay_buf_empty(struct rchan_buf *buf)

布林值,通道緩衝區是否為空?

引數

struct rchan_buf *buf

通道緩衝區

如果緩衝區為空,則返回 1,否則返回 0。

void wakeup_readers(struct irq_work *work)

喚醒等待通道的讀取器

引數

struct irq_work *work

包含通道緩衝區

此函式用於延遲讀取器喚醒

void __relay_reset(struct rchan_buf *buf, unsigned int init)

重置通道緩衝區

引數

struct rchan_buf *buf

通道緩衝區

unsigned int init

如果是首次初始化,則為 1

有關效果的說明,請參見 relay_reset()

void relay_close_buf(struct rchan_buf *buf)

關閉通道緩衝區

引數

struct rchan_buf *buf

通道緩衝區

將緩衝區標記為已完成,並恢復預設回撥函式。當放棄最後一個引用時,通道緩衝區和通道緩衝區資料結構會自動釋放。

int relay_file_open(struct inode *inode, struct file *filp)

relay 檔案的開啟檔案操作

引數

struct inode *inode

inode

struct file *filp

檔案

增加通道緩衝區引用計數。

int relay_file_mmap(struct file *filp, struct vm_area_struct *vma)

relay 檔案的 mmap 檔案操作

引數

struct file *filp

檔案

struct vm_area_struct *vma

描述要對映的內容的 vma

呼叫 relay_mmap_buf() 將檔案對映到使用者空間。

__poll_t relay_file_poll(struct file *filp, poll_table *wait)

relay 檔案的 poll 檔案操作

引數

struct file *filp

檔案

poll_table *wait

poll 表

Poll 實現。

int relay_file_release(struct inode *inode, struct file *filp)

relay 檔案的 release 檔案操作

引數

struct inode *inode

inode

struct file *filp

檔案

減少通道引用計數,因為檔案系統不再使用它。

size_t relay_file_read_subbuf_avail(size_t read_pos, struct rchan_buf *buf)

返回子緩衝區中可用的位元組數

引數

size_t read_pos

檔案讀取位置

struct rchan_buf *buf

relay 通道緩衝區

size_t relay_file_read_start_pos(struct rchan_buf *buf)

查詢第一個可讀取的位元組

引數

struct rchan_buf *buf

relay 通道緩衝區

如果 read_pos 位於填充的中間,則返回第一個實際可用位元組的位置,否則返回原始值。

size_t relay_file_read_end_pos(struct rchan_buf *buf, size_t read_pos, size_t count)

返回新的讀取位置

引數

struct rchan_buf *buf

relay 通道緩衝區

size_t read_pos

檔案讀取位置

size_t count

要讀取的位元組數

模組支援

核心模組自動載入

int __request_module(bool wait, const char *fmt, ...)

嘗試載入核心模組

引數

bool wait

等待(或不等待)操作完成

const char *fmt

模組名稱的 printf 風格格式字串

...

格式字串中指定的引數

描述

使用使用者模式模組載入器載入模組。 如果成功,該函式返回零;如果失敗,則返回負數的 errno 程式碼或來自“modprobe”的正退出程式碼。 請注意,成功載入模組並不意味著該模組沒有解除安裝並因自身錯誤而退出。 呼叫者必須檢查他們請求的服務現在是否可用,而不是盲目地呼叫它。

如果停用了模組自動載入支援,則此函式只返回 -ENOENT。

模組除錯

啟用 CONFIG_MODULE_STATS 可以啟用模組除錯統計資訊,這些統計資訊對於監視和根本原因分析模組載入中的記憶體壓力問題很有用。 這些統計資訊有助於我們改進生產工作負載。

當前支援的模組除錯統計資訊有助於跟蹤模組載入失敗,以便改進核心模組自動載入的使用 (request_module()) 或與使用者空間的互動。 提供的統計資訊用於跟蹤 finit_module() 路徑中的所有可能失敗以及在此過程空間中浪費的記憶體。 每個失敗計數器都與一種模組載入失敗型別相關聯,已知這種失敗會導致一定數量的記憶體分配丟失。 在最壞的情況下,載入模組將在 3 步記憶體分配過程後失敗

  1. 使用 kernel_read_file_from_fd() 分配的記憶體

  2. 模組解壓縮處理從 kernel_read_file_from_fd() 讀取的檔案,並使用 vmap() 將解壓縮的模組對映到新的本地緩衝區,該緩衝區表示從使用者空間傳遞的解壓縮模組的副本。 kernel_read_file_from_fd() 中的緩衝區會立即釋放。

  3. layout_and_allocate() 為最終位置分配空間,如果模組已成功處理,我們將把模組儲存在該位置。

如果在這些三種不同的分配之後發生失敗,則只會遞增一個計數器,其中包含在此失敗期間釋放的已分配位元組的總和。 同樣,如果模組載入僅在步驟 b) 之後失敗,則將使用單獨的計數器,併為這兩個分配期間釋放且未使用的位元組數遞增該計數器。

虛擬記憶體空間可能會受到限制,例如,在 x86 上,虛擬記憶體大小預設為 128 MiB。 我們應盡力限制和避免在可能的情況下浪費虛擬記憶體分配。 這些模組除錯統計資訊有助於評估由於模組載入失敗而在啟動時浪費了多少記憶體。

所有計數器都設計為增量式的。 使用原子計數器是為了保持簡單並避免延遲和死鎖。

dup_failed_modules - 跟蹤重複的失敗模組

由於已在處理或已載入名稱相同的現有模組而未能載入的模組的連結列表。 finit_module() 系統呼叫會導致大量虛擬記憶體分配。 在最壞的情況下,finit_module() 系統呼叫最終可以分配虛擬記憶體 3 次

  1. kernel_read_file_from_fd() 呼叫使用 vmalloc()

  2. 可選的模組解壓縮使用 vmap()

  3. layout_and allocate() 可以使用 vzalloc() 或 vmalloc 的特定於體系結構的版本來處理需要特殊許可權的 ELF 部分

實際上,在今天的典型啟動中,大多數 finit_module() 呼叫都失敗了,原因是具有相同名稱的模組已載入或即將被處理。 分配給這些失敗模組的所有虛擬記憶體都將被釋放,而沒有實際用途。

為了幫助解決此問題,dup_failed_modules 使我們能夠跟蹤由於模組已載入或正在被處理而未能載入的模組。 我們只有兩個可以使此類呼叫失敗的點,我們在下面列出了它們以及虛擬記憶體分配呼叫的數量

  1. FAIL_DUP_MOD_BECOMING:在 layout_and_allocate() 之前的 early_mod_check() 結束時。 - 使用模組解壓縮:2 個虛擬記憶體分配呼叫 - 不使用模組解壓縮:1 個虛擬記憶體分配呼叫

  2. FAIL_DUP_MOD_LOAD:在 add_unformed_module() 上 layout_and_allocate() 之後 - 使用模組解壓縮:3 個虛擬記憶體分配呼叫 - 不使用模組解壓縮:2 個虛擬記憶體分配呼叫

我們應努力使此列表儘可能小。 如果此列表不為空,則反映了核心或使用者空間中可能存在的工作或最佳化。

模組統計資訊 debugfs 計數器

模組載入期間浪費的虛擬記憶體分配空間總量可以透過將總和相加來計算

  • invalid_kread_bytes + invalid_decompress_bytes + invalid_becoming_bytes + invalid_mod_bytes

以下 debugfs 計數器可用於檢查模組載入失敗

  • total_mod_size:我們在此係統上處理過的所有模組使用的總位元組數

  • total_text_size:我們在此係統上處理過的 .text 和 .init.text ELF 部分大小的總位元組數

  • invalid_kread_bytes: 由於初始的 kernel_read_file_from_fd() 失敗而分配然後釋放的位元組數。 kernel_read_file_from_fd() 使用 vmalloc()。 通常情況下,除非您的系統處於記憶體壓力之下,否則不應發生這種情況。

  • invalid_decompress_bytes: 由於模組解壓縮路徑中使用 vmap() 的記憶體分配而分配和釋放的位元組數。 通常情況下,除非您的系統處於記憶體壓力之下,否則不應發生這種情況。

  • invalid_becoming_bytes: 用於讀取核心模組,在將模組新增到 **modules** 連結串列之前,使用者空間希望我們讀取的位元組總數。 如果我們在成功呼叫 kernel_read_file_from_fd() 之後,以及在我們為模組分配私有記憶體(如果模組成功載入,則會保留)之前進行了檢查,則可能會發生這些故障。 這種失敗最常見的原因是使用者空間正在爭相載入尚未載入的模組。 第一個成功呼叫 add_unformed_module() 的模組會將模組新增到我們的 modules 列表中,並且後續載入同名模組的操作將在 early_mod_check() 的末尾報錯。 在 early_mod_check() 末尾檢查 module_patient_check_exists() 可以防止對已在處理的模組在 layout_and_allocate() 上進行重複分配。 這些重複失敗的模組是非致命的,但通常表明使用者空間尚未看到使用者空間中的模組已載入,並且不必要地嘗試在核心有機會開始處理先前的請求之前載入模組。 儘管重複失敗可能不是致命的,但我們應該積極地嘗試減少 vmalloc() 的壓力,因此理想情況下,啟動後,這個值應儘可能接近 0。 如果使用了模組解壓縮,我們還將壓縮模組的初始 kernel_read_file_from_fd() 的成本新增到此計數器。 如果未使用模組解壓縮,則該值表示 kernel_read_file_from_fd() 呼叫中用於此類失敗的總分配和釋放的位元組數。 這些失敗可能發生,因為

  • module_sig_check() - 模組簽名檢查

  • elf_validity_cache_copy() - 某些 ELF 驗證問題

  • early_mod_check()

    • 黑名單

    • 無法重寫節頭

    • 版本魔數

    • 即時補丁要求未透過檢查

    • 檢測到該模組已存在

  • invalid_mod_bytes: 這些是由於我們對使用者空間傳遞給我們的模組進行了所有健全性檢查,以及在我們首次檢查該模組是否唯一之後發生的故障而分配和釋放的位元組總數。 如果我們在使用 layout_and_allocate() 為模組分配空間後檢測到該模組已載入,則模組仍然可能無法載入,我們在作為即時模組處理並執行其初始化例程之前進行此檢查。 請注意,如果發生此類故障,也意味著相應的 kernel_read_file_from_fd() 記憶體空間也被釋放且未使用,因此我們將此計數器增加模組大小的兩倍。 此外,如果您使用了模組解壓縮,則壓縮模組的大小也會新增到此計數器。

  • modcount:我們在核心生命週期中載入了多少模組

  • failed_kreads:有多少模組因 kernel_read_file_from_fd() 失敗而失敗

  • failed_decompress:我們有多少次失敗的模組解壓縮嘗試。 除非您的壓縮/解壓縮可能已損壞,否則這些情況實際上不應該發生。

  • failed_becoming:在 kernel_read_file_from_fd() 之後,但在我們使用 layout_and_allocate() 為其分配記憶體之前,有多少模組失敗。 如果您成功驗證模組併為其呼叫 layout_and_allocate(),則此計數器永遠不會遞增。

  • failed_load_modules:一旦我們使用 layout_and_allocate() 為我們的模組分配了私有空間,有多少模組失敗。 希望這些失敗大部分已經得到處理。 理論上,此處可能仍然存在競爭,但這僅僅意味著核心已開始併發處理兩個執行緒,直到 early_mod_check(),並且一個執行緒獲勝。 這些失敗是核心或使用者空間正在做一些非常愚蠢的事情,或者可以改進的良好跡象。 我們應該努力修復這些問題,但修復它們可能並不容易。 最近的一個例子是為頻率模組產生的模組請求,正在為系統上的每個 CPU 發出單獨的模組請求。

模組間支援

有關更多資訊,請參閱 kernel/module/ 中的檔案。

硬體介面

DMA 通道

int request_dma(unsigned int dmanr, const char *device_id)

請求並保留系統 DMA 通道

引數

unsigned int dmanr

DMA 通道號

const char * device_id

保留裝置 ID 字串,用於 /proc/dma

void free_dma(unsigned int dmanr)

釋放保留的系統 DMA 通道

引數

unsigned int dmanr

DMA 通道號

資源管理

struct resource *request_resource_conflict(struct resource *root, struct resource *new)

請求並保留 I/O 或記憶體資源

引數

struct resource *root

根資源描述符

struct resource *new

呼叫者所需的資源描述符

描述

成功時返回 0,錯誤時返回衝突資源。

int find_next_iomem_res(resource_size_t start, resource_size_t end, unsigned long flags, unsigned long desc, struct resource *res)

查詢覆蓋 [**start**..**end**] 部分的最低 iomem 資源。

引數

resource_size_t start

搜尋到的資源的起始地址

resource_size_t end

相同資源的結束地址

unsigned long flags

資源必須具有的標誌

unsigned long desc

資源必須具有的描述符

struct resource *res

如果找到資源,則返回 ptr

描述

如果找到資源,則返回 0,並且 **res 會被覆蓋為 [**start**..**end**] 範圍內的資源部分; 如果未找到資源,則返回 -ENODEV。 對於無效引數,返回 -EINVAL。

呼叫者必須指定 **start**、**end**、**flags** 和 **desc**(可以是 IORES_DESC_NONE)。

int reallocate_resource(struct resource *root, struct resource *old, resource_size_t newsize, struct resource_constraint *constraint)

在給定範圍和對齊方式的資源樹中分配一個槽。 如果無法在當前位置重新分配新大小,則將重新定位資源。

引數

struct resource *root

根資源描述符

struct resource *old

呼叫者所需的資源描述符

resource_size_t newsize

資源描述符的新大小

struct resource_constraint *constraint

要滿足的記憶體範圍和對齊方式約束。

struct resource *lookup_resource(struct resource *root, resource_size_t start)

透過資源起始地址查詢現有資源

引數

struct resource *root

根資源描述符

resource_size_t start

資源起始地址

描述

如果找到資源,則返回指向該資源的指標,否則返回 NULL

struct resource *insert_resource_conflict(struct resource *parent, struct resource *new)

在資源樹中插入資源

引數

struct resource *parent

新資源的父資源

struct resource *new

要插入的新資源

描述

成功時返回 0,如果無法插入資源,則返回衝突資源。

當沒有發生衝突時,此函式等效於 request_resource_conflict。 如果發生衝突,並且衝突資源完全適合新資源的範圍,則會插入新資源,並且衝突資源將成為新資源的子資源。

此函式適用於資源生產者,例如 FW 模組和匯流排驅動程式。

resource_size_t resource_alignment(struct resource *res)

計算資源的對齊方式

引數

struct resource *res

資源指標

描述

成功時返回對齊方式,失敗時返回 0(無效對齊方式)。

void release_mem_region_adjustable(resource_size_t start, resource_size_t size)

釋放先前保留的記憶體區域

引數

resource_size_t start

資源起始地址

resource_size_t size

資源區域大小

描述

此介面適用於記憶體熱刪除。 請求的區域將從當前繁忙的記憶體資源中釋放。 請求的區域必須完全匹配或適合單個繁忙資源條目。 在後一種情況下,剩餘的資源將相應地進行調整。 繁忙記憶體資源的現有子資源在請求中必須是不可變的。

注意

  • 在確認它們是有效用例後,可以支援其他釋放條件,例如重疊區域。

  • 當繁忙的記憶體資源被拆分為兩個條目時,程式碼假定所有子資源都保留在較低地址的條目中以簡化操作。 必要時增強此邏輯。

void merge_system_ram_resource(struct resource *res)

將系統 RAM 資源標記為可合併,並嘗試將其與相鄰的可合併資源合併

引數

struct resource *res

資源描述符

描述

此介面適用於記憶體熱插拔,驅動程式透過 add_memory*() 添加了大量連續的系統 ram 資源,並且對實際的資源邊界不感興趣(例如,它可能與 DIMM 相關)。 僅考慮標記為可合併、具有相同父資源且沒有任何子資源的資源。 所有可合併的資源在請求期間必須是不可變的。

注意

  • 呼叫者必須確保在此呼叫之後不再使用指向標記為可合併的資源的任何指標 - 該資源可能會被釋放,並且該指標可能會失效!

  • release_mem_region_adjustable() 將根據記憶體熱拔出的需求進行拆分

int request_resource(struct resource *root, struct resource *new)

請求並保留 I/O 或記憶體資源

引數

struct resource *root

根資源描述符

struct resource *new

呼叫者所需的資源描述符

描述

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

int release_resource(struct resource *old)

釋放先前保留的資源

引數

struct resource *old

資源指標

int walk_iomem_res_desc(unsigned long desc, unsigned long flags, u64 start, u64 end, void *arg, int (*func)(struct resource*, void*))

遍歷 iomem 資源,並使用匹配的資源範圍呼叫 func()。 *

引數

unsigned long desc

I/O 資源描述符。 使用 IORES_DESC_NONE 跳過 **desc** 檢查。

unsigned long flags

I/O 資源標誌

u64 start

起始地址

u64 end

結束地址

void *arg

回撥 **func** 的函式引數

int (*func)(struct resource *, void *)

為每個合格的資源區域呼叫的回撥函式

描述

所有與 start、end 重疊,並且還匹配 flags 和 desc 的記憶體範圍都是有效的候選範圍。

注意

對於新的描述符搜尋,請在 <linux/ioport.h> 中定義一個新的 IORES_DESC,並將其設定在目標資源條目的“desc”中。

int region_intersects(resource_size_t start, size_t size, unsigned long flags, unsigned long desc)

確定區域與已知資源的交集

引數

resource_size_t start

區域起始地址

size_t size

區域大小

unsigned long flags

資源標誌(在 iomem_resource 中)

unsigned long desc

資源描述符(在 iomem_resource 中)或 IORES_DESC_NONE

描述

檢查指定的區域是否部分重疊或完全覆蓋由 **flags** 和 **desc**(可選,使用 IORES_DESC_NONE)標識的資源。 如果區域與 **flags**/ **desc** 不重疊,則返回 REGION_DISJOINT;如果區域與 **flags**/ **desc** 和另一個資源重疊,則返回 REGION_MIXED;如果區域與 **flags**/ **desc** 重疊,且沒有其他定義的資源,則返回 REGION_INTERSECTS。 請注意,在指定區域與 RAM 和未定義的記憶體空洞重疊的情況下,也會返回 REGION_INTERSECTS。

記憶體重新對映函式使用 region_intersect() 來確保使用者沒有重新對映 RAM,並且它比逐頁遍歷資源表的速度快得多。

int find_resource_space(struct resource *root, struct resource *new, resource_size_t size, struct resource_constraint *constraint)

在資源樹中查詢空閒空間

引數

struct resource *root

根資源描述符

struct resource *new

等待空閒資源空間的資源描述符

resource_size_t size

空閒空間的最小大小

struct resource_constraint *constraint

要滿足的範圍和對齊方式約束

描述

在滿足範圍和對齊方式 **constraints** 的資源樹中,在 **root** 下查詢空閒空間。

返回

  • 0 - 如果成功,則會更改 **new** 成員 start、end 和 flags。

  • -EBUSY - 如果未找到空閒空間。

int allocate_resource(struct resource *root, struct resource *new, resource_size_t size, resource_size_t min, resource_size_t max, resource_size_t align, resource_alignf alignf, void *alignf_data)

根據指定的範圍和對齊方式,在資源樹中分配一個空槽。如果資源已經被分配,則會重新分配一個新的大小。

引數

struct resource *root

根資源描述符

struct resource *new

呼叫者所需的資源描述符

resource_size_t size

請求的資源區域大小

resource_size_t min

分配的最小邊界

resource_size_t max

分配的最大邊界

resource_size_t align

請求的對齊方式,以位元組為單位

resource_alignf alignf

對齊函式,可選,如果不為 NULL 則呼叫

void *alignf_data

傳遞給 alignf 函式的任意資料

int insert_resource(struct resource *parent, struct resource *new)

將資源插入資源樹中

引數

struct resource *parent

新資源的父資源

struct resource *new

要插入的新資源

描述

成功返回 0,如果無法插入資源,則返回 -EBUSY。

此函式適用於資源生產者,例如 FW 模組和匯流排驅動程式。

void insert_resource_expand_to_fit(struct resource *root, struct resource *new)

將資源插入資源樹中

引數

struct resource *root

根資源描述符

struct resource *new

要插入的新資源

描述

將資源插入資源樹中,如果需要,可以擴充套件它以包含任何衝突的資源。

int remove_resource(struct resource *old)

移除資源樹中的資源

引數

struct resource *old

要移除的資源

描述

成功返回 0,如果資源無效,則返回 -EINVAL。

此函式移除之前由 insert_resource()insert_resource_conflict() 插入的資源,並將子資源(如果有)上移到它們之前的位置。insert_resource()insert_resource_conflict() 插入一個新資源,並將任何衝突的資源下移到新資源的子資源。

insert_resource()insert_resource_conflict()remove_resource() 適用於資源的生產者,例如 FW 模組和匯流排驅動程式。

int adjust_resource(struct resource *res, resource_size_t start, resource_size_t size)

修改資源的起始地址和大小

引數

struct resource *res

要修改的資源

resource_size_t start

新的起始值

resource_size_t size

新的大小

描述

給定一個現有資源,將其起始地址和大小更改為與引數匹配。成功返回 0,如果無法適應,則返回 -EBUSY。資源的現有子資源假定為不可變的。

struct resource *__request_region(struct resource *parent, resource_size_t start, resource_size_t n, const char *name, int flags)

建立一個新的繁忙資源區域

引數

struct resource *parent

父資源描述符

resource_size_t start

資源起始地址

resource_size_t n

資源區域大小

const char *name

保留呼叫者的 ID 字串

int flags

IO 資源標誌

void __release_region(struct resource *parent, resource_size_t start, resource_size_t n)

釋放先前保留的資源區域

引數

struct resource *parent

父資源描述符

resource_size_t start

資源起始地址

resource_size_t n

資源區域大小

描述

所描述的資源區域必須與當前繁忙區域匹配。

int devm_request_resource(struct device *dev, struct resource *root, struct resource *new)

請求並保留 I/O 或記憶體資源

引數

struct device *dev

請求資源的裝置

struct resource *root

從中請求資源的資源樹的根

struct resource *new

要請求的資源的描述符

描述

這是 request_resource() 的裝置管理版本。通常不需要顯式釋放此函式請求的資源,因為它會在裝置與其驅動程式取消繫結時得到處理。 如果由於某種原因需要顯式釋放資源(例如,由於排序問題),驅動程式必須呼叫 devm_release_resource(),而不是常規的 release_resource()

當在任何現有資源和新請求的資源之間檢測到衝突時,將列印一條錯誤訊息。

成功返回 0,失敗返回負錯誤程式碼。

void devm_release_resource(struct device *dev, struct resource *new)

釋放先前請求的資源

引數

struct device *dev

釋放資源的裝置

struct resource *new

要釋放的資源的描述符

描述

釋放先前使用 devm_request_resource() 請求的資源。

struct resource *devm_request_free_mem_region(struct device *dev, struct resource *base, unsigned long size)

查詢裝置私有記憶體的空閒區域

引數

struct device *dev

用於繫結資源的裝置結構體

struct resource *base

要查詢的資源樹

unsigned long size

要新增的裝置記憶體的大小(以位元組為單位)

描述

此函式嘗試找到足夠大的物理地址空閒範圍來包含新資源,以便以後可以將其熱插拔為 ZONE_DEVICE 記憶體,而 ZONE_DEVICE 記憶體又分配結構體頁面。

struct resource *alloc_free_mem_region(struct resource *base, unsigned long size, unsigned long align, const char *name)

相對於 base 查詢空閒區域

引數

struct resource *base

將成為新資源父節點的資源

unsigned long size

要從 base 分配的記憶體大小(以位元組為單位)

unsigned long align

分配的對齊要求

const char *name

資源名稱

描述

像 CXL 這樣的匯流排,可以動態例項化新的記憶體區域,需要一種方法來為這些區域分配物理地址空間。 分配並插入新資源以覆蓋 base 跨度內未被 base 的子資源宣告的空閒範圍。

MTRR 處理

int arch_phys_wc_add(unsigned long base, unsigned long size)

新增 WC MTRR 並在 PAT 不可用時處理錯誤

引數

unsigned long base

物理基地址

unsigned long size

區域大小

描述

如果 PAT 可用,則不執行任何操作。 如果 PAT 不可用,它會嘗試新增一個覆蓋從 base 開始的 size 位元組的 WC MTRR,如果失敗,則記錄一個錯誤。

被呼叫者應該在等效的二次方邊界上提供二次方大小。

驅動程式必須儲存返回值以傳遞給 mtrr_del_wc_if_needed,但驅動程式不應嘗試解釋該返回值。

安全框架

int security_init(void)

初始化安全框架

引數

void

無引數

描述

應該在核心初始化序列的早期呼叫此函式。

void security_add_hooks(struct security_hook_list *hooks, int count, const struct lsm_id *lsmid)

將模組鉤子新增到鉤子列表。

引數

struct security_hook_list *hooks

要新增的鉤子

int count

要新增的鉤子數

const struct lsm_id *lsmid

安全模組的標識資訊

描述

每個 LSM 必須向基礎架構註冊其鉤子。

int lsm_blob_alloc(void **dest, size_t size, gfp_t gfp)

分配一個複合 blob

引數

void **dest

blob 的目標

size_t size

blob 的大小

gfp_t gfp

分配型別

描述

為所有模組分配一個 blob

返回 0,如果無法分配記憶體,則返回 -ENOMEM。

int lsm_cred_alloc(struct cred *cred, gfp_t gfp)

分配一個複合 cred blob

引數

struct cred *cred

需要 blob 的 cred

gfp_t gfp

分配型別

描述

為所有模組分配 cred blob

返回 0,如果無法分配記憶體,則返回 -ENOMEM。

void lsm_early_cred(struct cred *cred)

在初始化期間分配一個複合 cred blob

引數

struct cred *cred

需要 blob 的 cred

描述

為所有模組分配 cred blob

int lsm_file_alloc(struct file *file)

分配一個複合 file blob

引數

struct file *file

需要 blob 的 file

描述

為所有模組分配 file blob

返回 0,如果無法分配記憶體,則返回 -ENOMEM。

int lsm_inode_alloc(struct inode *inode, gfp_t gfp)

分配一個複合 inode blob

引數

struct inode *inode

需要 blob 的 inode

gfp_t gfp

分配標誌

描述

為所有模組分配 inode blob

返回 0,如果無法分配記憶體,則返回 -ENOMEM。

int lsm_task_alloc(struct task_struct *task)

分配一個組合任務blob

引數

struct task_struct *task

需要blob的任務

描述

為所有模組分配任務blob

返回 0,如果無法分配記憶體,則返回 -ENOMEM。

int lsm_ipc_alloc(struct kern_ipc_perm *kip)

分配一個組合ipc blob

引數

struct kern_ipc_perm *kip

需要blob的ipc

描述

為所有模組分配ipc blob

返回 0,如果無法分配記憶體,則返回 -ENOMEM。

int lsm_key_alloc(struct key *key)

分配一個組合key blob

引數

struct key *key

需要blob的key

描述

為所有模組分配key blob

返回 0,如果無法分配記憶體,則返回 -ENOMEM。

int lsm_msg_msg_alloc(struct msg_msg *mp)

分配一個組合msg_msg blob

引數

struct msg_msg *mp

需要blob的msg_msg

描述

為所有模組分配ipc blob

返回 0,如果無法分配記憶體,則返回 -ENOMEM。

int lsm_bdev_alloc(struct block_device *bdev)

分配一個組合block_device blob

引數

struct block_device *bdev

需要blob的block_device

描述

為所有模組分配block_device blob

返回 0,如果無法分配記憶體,則返回 -ENOMEM。

void lsm_early_task(struct task_struct *task)

在初始化期間分配一個組合任務blob

引數

struct task_struct *task

需要blob的任務

描述

為所有模組分配任務blob

int lsm_superblock_alloc(struct super_block *sb)

分配一個組合superblock blob

引數

struct super_block *sb

需要blob的superblock

描述

為所有模組分配superblock blob

返回 0,如果無法分配記憶體,則返回 -ENOMEM。

int lsm_fill_user_ctx(struct lsm_ctx __user *uctx, u32 *uctx_len, void *val, size_t val_len, u64 id, u64 flags)

填充一個使用者空間lsm_ctx結構

引數

struct lsm_ctx __user *uctx

要填充的使用者空間LSM上下文

u32 *uctx_len

可用的uctx大小(輸入),已使用的uctx大小(輸出)

void *val

新的LSM上下文值

size_t val_len

新的LSM上下文值的大小

u64 id

LSM id

u64 flags

LSM定義的標誌

描述

填充使用者空間 lsm_ctx 結構中的所有欄位。 如果 **uctx** 為 NULL,則只需計算透過 **utc_len** 輸出的所需大小並返回成功。

成功時返回 0,如果使用者空間緩衝區不夠大,則返回 -E2BIG,如果複製錯誤,則返回 -EFAULT,如果無法分配記憶體,則返回 -ENOMEM。

int security_binder_set_context_mgr(const struct cred *mgr)

檢查是否可以成為 binder ctx mgr

引數

const struct cred *mgr

當前 binder 程序的任務憑據

描述

檢查是否允許 **mgr** 成為 binder 上下文管理器。

返回

如果授予許可權,則返回 0。

int security_binder_transaction(const struct cred *from, const struct cred *to)

檢查是否允許 binder 事務

引數

const struct cred *from

傳送程序

const struct cred *to

接收程序

描述

檢查是否允許 **from** 呼叫到 **to** 的 binder 事務呼叫。

返回

如果授予許可權,則返回 0。

int security_binder_transfer_binder(const struct cred *from, const struct cred *to)

檢查是否允許 binder 傳輸

引數

const struct cred *from

傳送程序

const struct cred *to

接收程序

描述

檢查是否允許 **from** 將 binder 引用傳輸到 **to**。

返回

如果授予許可權,則返回 0。

int security_binder_transfer_file(const struct cred *from, const struct file *file)

檢查是否允許 binder 檔案傳輸

引數

const struct cred *from

傳送程序

const struct cred *to

接收程序

const struct file *file

正在傳輸的檔案

描述

檢查是否允許 **from** 將 **file** 傳輸到 **to**。

返回

如果授予許可權,則返回 0。

int security_ptrace_access_check(struct task_struct *child, unsigned int mode)

檢查是否允許跟蹤

引數

struct task_struct *child

目標程序

unsigned int mode

PTRACE_MODE 標誌

描述

允許當前程序跟蹤 **child** 程序之前,檢查許可權。 安全模組也可能希望在 execve 期間的 set_security 或 apply_creds 掛鉤中執行程序跟蹤檢查,如果在 binprm_security_ops 的 bprm_set_creds 掛鉤中的 execve 期間的跟蹤檢查期間程序正在被跟蹤並且其安全屬性將被 execve 更改。

返回

如果授予許可權,則返回 0。

int security_ptrace_traceme(struct task_struct *parent)

檢查是否允許跟蹤

引數

struct task_struct *parent

跟蹤程序

描述

在允許當前程序向 **parent** 程序呈現自己進行跟蹤之前,檢查 **parent** 程序是否具有足夠的許可權來跟蹤當前程序。

返回

如果授予許可權,則返回 0。

int security_capget(const struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted)

獲取程序的 capability 集合

引數

const struct task_struct *target

目標程序

kernel_cap_t *effective

有效 capability 集合

kernel_cap_t *inheritable

可繼承 capability 集合

kernel_cap_t *permitted

允許的 capability 集合

描述

獲取 **target** 程序的 **effective**、**inheritable** 和 **permitted** capability 集合。 該鉤子還可以執行許可權檢查,以確定是否允許當前程序檢視 **target** 程序的 capability 集合。

返回

如果成功獲取 capability 集合,則返回 0。

int security_capset(struct cred *new, const struct cred *old, const kernel_cap_t *effective, const kernel_cap_t *inheritable, const kernel_cap_t *permitted)

設定程序的 capability 集合

引數

struct cred *new

目標程序的新憑據

const struct cred *old

目標程序的當前憑據

const kernel_cap_t *effective

有效 capability 集合

const kernel_cap_t *inheritable

可繼承 capability 集合

const kernel_cap_t *permitted

允許的 capability 集合

描述

為當前程序設定 **effective**、**inheritable** 和 **permitted** capability 集合。

返回

如果授予許可權,則返回 0 並更新 **new**。

int security_capable(const struct cred *cred, struct user_namespace *ns, int cap, unsigned int opts)

檢查程序是否具有必要的 capability

引數

const struct cred *cred

要檢查的憑據

struct user_namespace *ns

使用者名稱空間

int cap

請求的 capability

unsigned int opts

capability 檢查選項

描述

檢查 **tsk** 程序是否在指示的憑據中具有 **cap** capability。 **cap** 包含 capability <include/linux/capability.h>。 **opts** 包含 capability 檢查的選項 <include/linux/security.h>。

返回

如果授予 capability,則返回 0。

int security_quotactl(int cmds, int type, int id, const struct super_block *sb)

檢查是否允許此 fs 的 quotactl() 系統呼叫

引數

int cmds

命令

int type

type

int id

id

const struct super_block *sb

檔案系統

描述

檢查是否允許此 **sb** 的 quotactl 系統呼叫。

返回

如果授予許可權,則返回 0。

int security_quota_on(struct dentry *dentry)

檢查是否允許 dentry 的 QUOTAON

引數

struct dentry *dentry

dentry

描述

檢查是否允許 **dentry** 的 QUOTAON。

返回

如果授予許可權,則返回 0。

int security_syslog(int type)

檢查是否允許訪問核心訊息環

引數

int type

SYSLOG_ACTION_* 型別

描述

在訪問核心訊息環或將日誌記錄更改為控制檯之前檢查許可權。 有關 **type** 值的說明,請參見 syslog(2) 手冊頁。

返回

如果授予許可權,則返回 0。

int security_settime64(const struct timespec64 *ts, const struct timezone *tz)

檢查是否允許更改系統時間

引數

const struct timespec64 *ts

新時間

const struct timezone *tz

時區

描述

檢查更改系統時間的許可權。struct timespec64 定義在 <include/linux/time64.h> 中,timezone 定義在 <include/linux/time.h> 中。

返回

如果授予許可權,則返回 0。

int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)

檢查是否允許分配新的記憶體對映

引數

struct mm_struct *mm

mm 結構體

long pages

頁數

描述

檢查分配新的虛擬對映的許可權。如果所有 LSM 都返回正值,則將使用 cap_sys_admin 設定呼叫 __vm_enough_memory()。如果至少有一個 LSM 返回 0 或負值,則將使用 cap_sys_admin 清除呼叫 __vm_enough_memory()。

返回

如果 LSM 基礎架構授予呼叫者許可權,則返回 0。

呼叫者。

int security_bprm_creds_for_exec(struct linux_binprm *bprm)

準備 exec() 的憑據

引數

struct linux_binprm *bprm

二進位制程式資訊

描述

如果 prepare_exec_creds 中的設定沒有為執行 bprm->file 正確設定 bprm->cred->security,請更新 LSM 的 bprm->cred->security 部分,使其成為 commit_creds 需要為新程式安裝的部分。此 hook 也可以選擇性地檢查許可權(例如,用於安全域之間的轉換)。如果應設定 AT_SECURE 以請求 libc 啟用安全模式,則此 hook 必須將 bprm->secureexec 設定為 1。bprm 包含 linux_binprm 結構。

如果使用 AT_EXECVE_CHECK 標誌呼叫 execveat(2),則會設定 bprm->is_check。即使執行永遠不會真正發生並且將始終刪除 bprm,結果也必須與沒有此標誌的結果相同。

此 hook 不得更改 current->cred,僅更改 bprm->cred

返回

如果 hook 成功並且授予許可權,則返回 0。

int security_bprm_creds_from_file(struct linux_binprm *bprm, const struct file *file)

根據檔案更新 linux_binprm 憑據

引數

struct linux_binprm *bprm

二進位制程式資訊

const struct file *file

關聯檔案

描述

如果 file 是 setpcap、suid、sgid 或以其他方式標記為在 exec 時更改許可權的檔案,請更新 bprm->cred 以反映該更改。 這是在找到將要執行的二進位制檔案而沒有直譯器之後呼叫的。 這可確保憑據不會來自二進位制檔案需要重新開啟的指令碼,該指令碼在重新開啟時可能最終成為完全不同的檔案。 此 hook 也可以選擇性地檢查許可權(例如,用於安全域之間的轉換)。 如果應設定 AT_SECURE 以請求 libc 啟用安全模式,則此 hook 必須將 bprm->secureexec 設定為 1。此 hook 必須將應該從 current->personality 清除的任何個性標誌新增到 bprm->per_clearbprm 包含 linux_binprm 結構。

返回

如果 hook 成功並且授予許可權,則返回 0。

int security_bprm_check(struct linux_binprm *bprm)

調節二進位制處理程式搜尋

引數

struct linux_binprm *bprm

二進位制程式資訊

描述

此 hook 調節二進位制處理程式搜尋將要開始的點。它允許檢查在前面的 creds_for_exec 呼叫中設定的 bprm->cred->security 值。argv 列表和 envp 列表可以在 bprm 中可靠地使用。在單個 execve 期間,可能會多次呼叫此 hook。bprm 包含 linux_binprm 結構。

返回

如果 hook 成功並且授予許可權,則返回 0。

void security_bprm_committing_creds(const struct linux_binprm *bprm)

在 exec() 期間為程序安裝憑據

引數

const struct linux_binprm *bprm

二進位制程式資訊

描述

準備安裝由 execve 操作轉換的程序的新安全屬性,該屬性基於 current->cred 指向的舊憑據和 bprm_creds_for_exec hook 在 bprm->cred 中設定的資訊。bprm 指向 linux_binprm 結構。此 hook 是對程序執行狀態更改的好地方,例如關閉當屬性更改時不再授予訪問許可權的開啟的檔案描述符。這將在 commit_creds() 之前立即呼叫。

void security_bprm_committed_creds(const struct linux_binprm *bprm)

在 exec() 期間完成憑據安裝後進行清理

引數

const struct linux_binprm *bprm

二進位制程式資訊

描述

完成安裝由 execve 操作轉換的程序的新安全屬性後進行清理。此時,新憑據已設定為 current->credbprm 指向 linux_binprm 結構。此 hook 是對程序執行狀態更改的好地方,例如清除不可繼承的訊號狀態。這將在 commit_creds() 之後立即呼叫。

int security_fs_context_submount(struct fs_context *fc, struct super_block *reference)

初始化 fc->security

引數

struct fs_context *fc

新檔案系統上下文

struct super_block *reference

用於子掛載/重新掛載的 dentry 引用

描述

填充新 fs_context 的 ->security 欄位。

返回

成功時返回 0,失敗時返回負錯誤程式碼。

int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc)

複製 fs_context LSM blob

引數

struct fs_context *fc

目標檔案系統上下文

struct fs_context *src_fc

原始檔系統上下文

描述

分配安全結構並將其附加到 sc->security。此指標由呼叫者初始化為 NULL。 fc 指示新的檔案系統上下文。 src_fc 指示原始檔案系統上下文。

返回

成功返回 0,失敗返回負錯誤程式碼。

int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param)

配置檔案系統上下文

引數

struct fs_context *fc

檔案系統上下文

struct fs_parameter *param

檔案系統引數

描述

使用者空間提供了一個引數來配置超級塊。LSM 可以使用該引數或將其返回給呼叫者以供其他地方使用。

返回

如果該引數被 LSM 使用,則應返回 0,如果該引數被

返回給呼叫者,則返回 -ENOPARAM,否則返回負錯誤程式碼。

int security_sb_alloc(struct super_block *sb)

分配 super_block LSM blob

引數

struct super_block *sb

檔案系統超級塊

描述

分配安全結構並將其附加到 sb->s_security 欄位。分配結構時,s_security 欄位將初始化為 NULL。 sb 包含要修改的 super_block 結構。

返回

如果操作成功,則返回 0。

void security_sb_delete(struct super_block *sb)

釋放 super_block LSM 關聯的物件

引數

struct super_block *sb

檔案系統超級塊

描述

釋放與超級塊關聯的物件(例如,inodes)。 sb 包含正在釋放的 super_block 結構。

void security_sb_free(struct super_block *sb)

釋放 super_block LSM blob

引數

struct super_block *sb

檔案系統超級塊

描述

取消分配並清除 sb->s_security 欄位。 sb 包含要修改的 super_block 結構。

int security_sb_kern_mount(const struct super_block *sb)

檢查是否允許核心掛載

引數

const struct super_block *sb

檔案系統超級塊

描述

如果許可權允許,則掛載此 sb

返回

如果授予許可權,則返回 0。

int security_sb_show_options(struct seq_file *m, struct super_block *sb)

輸出超級塊的掛載選項

引數

struct seq_file *m

輸出檔案

struct super_block *sb

檔案系統超級塊

描述

顯示(在 m 上列印)此 sb 的掛載選項。

返回

成功時返回 0,失敗時返回負值。

int security_sb_statfs(struct dentry *dentry)

檢查是否允許訪問 fs 統計資訊

引數

struct dentry *dentry

超級塊控制代碼

描述

在獲取 mnt 掛載點的檔案系統統計資訊之前檢查許可權。 dentry 是檔案系統的超級塊上的控制代碼。

返回

如果授予許可權,則返回 0。

int security_sb_mount(const char *dev_name, const struct path *path, const char *type, unsigned long flags, void *data)

檢查掛載檔案系統的許可權

引數

const char *dev_name

檔案系統後備裝置

const struct path *path

掛載點

const char *type

檔案系統型別

unsigned long flags

掛載標誌

void *data

檔案系統特定資料

描述

dev_name 指定的物件掛載到 nd 命名的掛載點上之前檢查許可權。對於普通掛載,如果檔案系統型別需要裝置,則 dev_name 標識裝置。對於重新掛載(flags & MS_REMOUNT),dev_name 無關緊要。對於環回/繫結掛載(flags & MS_BIND),dev_name 標識要掛載的物件的路徑名。

返回

如果授予許可權,則返回 0。

int security_sb_umount(struct vfsmount *mnt, int flags)

檢查解除安裝檔案系統的許可權

引數

struct vfsmount *mnt

已掛載的檔案系統

int flags

解除安裝標誌

描述

在解除安裝 mnt 檔案系統之前檢查許可權。

返回

如果授予許可權,則返回 0。

int security_sb_pivotroot(const struct path *old_path, const struct path *new_path)

檢查旋轉 rootfs 的許可權

引數

const struct path *old_path

當前 rootfs 的新位置

const struct path *new_path

新 rootfs 的位置

描述

在旋轉根檔案系統之前檢查許可權。

返回

如果授予許可權,則返回 0。

int security_move_mount(const struct path *from_path, const struct path *to_path)

檢查移動掛載的許可權

引數

const struct path *from_path

源掛載點

const struct path *to_path

目標掛載點

描述

在移動掛載之前檢查許可權。

返回

如果授予許可權,則返回 0。

int security_path_notify(const struct path *path, u64 mask, unsigned int obj_type)

檢查是否允許設定監視

引數

const struct path *path

檔案路徑

u64 mask

事件掩碼

unsigned int obj_type

檔案路徑型別

描述

在由 **mask** 定義的事件上,在 **path** 處的物件上,其型別由 **obj_type** 定義,檢查設定監視器之前是否具有許可權。

返回

如果授予許可權,則返回 0。

int security_inode_alloc(struct inode *inode, gfp_t gfp)

分配一個 inode LSM blob

引數

struct inode *inode

inode

gfp_t gfp

分配標誌

描述

分配安全結構並將其附加到 **inode->i_security**。當分配 inode 結構時,i_security 欄位初始化為 NULL。

返回

如果操作成功,則返回 0。

void security_inode_free(struct inode *inode)

釋放 inode 的 LSM blob

引數

struct inode *inode

inode

描述

釋放與 **inode** 關聯的任何 LSM 資源,儘管由於 inode 的 RCU 保護,可能要等到當前 RCU 寬限期過後才能完全釋放這些資源。

LSM 必須注意,儘管存在於對 security_inode_free() 的呼叫中,**inode** 仍然可以在 VFS 路徑遍歷中被引用,並且可能會在呼叫 security_inode_free() 期間或之後對 security_inode_permission() 進行呼叫。因此,inode->i_security 欄位透過 call_rcu() 回撥釋放,並且任何需要在 security_inode_permission() 中使用 inode 狀態的 LSM 都應該只在 inode_free_security_rcu() LSM 鉤子回撥中釋放該狀態。

int security_inode_init_security_anon(struct inode *inode, const struct qstr *name, const struct inode *context_inode)

初始化匿名 inode

引數

struct inode *inode

inode

const struct qstr *name

匿名 inode 類

const struct inode *context_inode

可選的相關 inode

描述

為新的匿名 inode 設定 incore 安全欄位,並返回安全模組是否允許建立 inode。

返回

成功返回 0,如果安全模組拒絕建立此 inode,則返回 -EACCES,或者在其他錯誤時返回其他 -errno。

void security_path_post_mknod(struct mnt_idmap *idmap, struct dentry *dentry)

更新常規檔案建立後的 inode 安全性

引數

struct mnt_idmap *idmap

掛載的 idmap

struct dentry *dentry

新檔案

描述

在建立常規檔案後更新 inode 安全欄位。

int security_path_rmdir(const struct path *dir, struct dentry *dentry)

檢查是否允許刪除目錄

引數

const struct path *dir

父目錄

struct dentry *dentry

要刪除的目錄

描述

檢查刪除目錄的許可權。

返回

如果授予許可權,則返回 0。

檢查是否允許建立符號連結

引數

const struct path *dir

父目錄

struct dentry *dentry

符號連結

const char *old_name

檔案路徑名

描述

檢查建立指向檔案的符號連結的許可權。

返回

如果授予許可權,則返回 0。

檢查是否允許建立硬連結

引數

struct dentry *old_dentry

現有檔案

const struct path *new_dir

新的父目錄

struct dentry *new_dentry

新連結

描述

在建立指向檔案的新硬連結之前檢查許可權。

返回

如果授予許可權,則返回 0。

int security_path_truncate(const struct path *path)

檢查是否允許截斷檔案

引數

const struct path *path

檔案

描述

在截斷 path 指示的檔案之前檢查許可權。請注意,也可以基於已開啟的檔案來檢查截斷許可權,使用 security_file_truncate() 鉤子。

返回

如果授予許可權,則返回 0。

int security_path_chmod(const struct path *path, umode_t mode)

檢查是否允許更改檔案的模式

引數

const struct path *path

檔案

umode_t mode

新模式

描述

檢查更改檔案 **path** 模式的許可權。新模式在 **mode** 中指定,它是 <include/uapi/linux/stat.h> 中的常量位掩碼。

返回

如果授予許可權,則返回 0。

int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid)

檢查是否允許更改檔案的所有者/組

引數

const struct path *path

檔案

kuid_t uid

檔案所有者

kgid_t gid

檔案組

描述

檢查更改檔案或目錄的所有者/組的許可權。

返回

如果授予許可權,則返回 0。

int security_path_chroot(const struct path *path)

檢查是否允許更改根目錄

引數

const struct path *path

目錄

描述

檢查更改根目錄的許可權。

返回

如果授予許可權,則返回 0。

void security_inode_post_create_tmpfile(struct mnt_idmap *idmap, struct inode *inode)

更新新 tmpfile 的 inode 安全性

引數

struct mnt_idmap *idmap

掛載的 idmap

struct inode *inode

新 tmpfile 的 inode

描述

建立 tmpfile 後更新 inode 安全資料。

檢查是否允許建立硬連結

引數

struct dentry *old_dentry

現有檔案

struct inode *dir

新的父目錄

struct dentry *new_dentry

新連結

描述

在建立指向檔案的新硬連結之前檢查許可權。

返回

如果授予許可權,則返回 0。

檢查是否允許刪除硬連結

引數

struct inode *dir

父目錄

struct dentry *dentry

檔案

描述

檢查刪除指向檔案的硬連結的許可權。

返回

如果授予許可權,則返回 0。

檢查是否允許建立符號連結

引數

struct inode *dir

父目錄

struct dentry *dentry

符號連結

const char *old_name

現有檔名

描述

檢查建立指向檔案的符號連結的許可權。

返回

如果授予許可權,則返回 0。

int security_inode_rmdir(struct inode *dir, struct dentry *dentry)

檢查是否允許刪除目錄

引數

struct inode *dir

父目錄

struct dentry *dentry

要刪除的目錄

描述

檢查刪除目錄的許可權。

返回

如果授予許可權,則返回 0。

int security_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)

檢查是否允許建立特殊檔案

引數

struct inode *dir

父目錄

struct dentry *dentry

新檔案

umode_t mode

新檔案模式

dev_t dev

裝置號

描述

檢查建立特殊檔案(或透過 mknod 系統呼叫建立的套接字或 fifo 檔案)時的許可權。請注意,如果 mknod 操作是為常規檔案完成的,那麼將呼叫 create 鉤子,而不是此鉤子。

返回

如果授予許可權,則返回 0。

int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, unsigned int flags)

檢查是否允許重新命名檔案

引數

struct inode *old_dir

舊檔案的父目錄

struct dentry *old_dentry

舊檔案

struct inode *new_dir

新檔案的父目錄

struct dentry *new_dentry

新檔案

unsigned int flags

標誌

描述

檢查重新命名檔案或目錄的許可權。

返回

如果授予許可權,則返回 0。

檢查是否允許讀取符號連結

引數

struct dentry *dentry

連結

描述

檢查讀取符號連結的許可權。

返回

如果授予許可權,則返回 0。

檢查是否允許跟隨符號連結

引數

struct dentry *dentry

連結 dentry

struct inode *inode

連結 inode

bool rcu

如果在 RCU 步行模式下為真

描述

在查詢路徑名時,檢查跟隨符號連結的許可權。 如果 rcu 為真,則 inode 不穩定。

返回

如果授予許可權,則返回 0。

int security_inode_permission(struct inode *inode, int mask)

檢查是否允許訪問 inode

引數

struct inode *inode

inode

int mask

訪問掩碼

描述

在訪問 inode 之前檢查許可權。 此鉤子由現有的 Linux 許可權函式呼叫,因此安全模組可以使用它為現有的 Linux 許可權檢查提供額外的檢查。 請注意,此鉤子在開啟檔案時(以及許多其他操作)呼叫,而 file_security_ops 許可權鉤子在執行實際的讀/寫操作時呼叫。

返回

如果授予許可權,則返回 0。

void security_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry, int ia_valid)

在 setattr 操作後更新 inode

引數

struct mnt_idmap *idmap

掛載的 idmap

struct dentry *dentry

檔案

int ia_valid

設定的檔案屬性

描述

成功設定檔案屬性後,更新 inode 安全欄位。

int security_inode_getattr(const struct path *path)

檢查是否允許獲取檔案屬性

引數

const struct path *path

檔案

描述

在獲取檔案屬性之前檢查許可權。

返回

如果授予許可權,則返回 0。

int security_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry, const char *name, const void *value, size_t size, int flags)

檢查是否允許設定檔案 xattrs

引數

struct mnt_idmap *idmap

掛載的 idmap

struct dentry *dentry

檔案

const char *name

xattr 名稱

const void *value

xattr 值

size_t size

xattr 值的長度

int flags

標誌

描述

此鉤子在 dentry 上設定擴充套件屬性 (xattrs) 之前執行所需的許可權檢查。 重要的是要注意,在我們呼叫主要 LSM 實現之前,我們有一些額外的邏輯來檢測是否需要在 LSM 層執行額外的 capability 檢查。

通常,我們在執行各種 LSM 鉤子實現之前強制執行 capability 檢查,但是如果 LSM 想要避免此 capability 檢查,它可以註冊一個 'inode_xattr_skipcap' 鉤子,併為它想要避免 capability 檢查的 xattrs 返回值 1,讓 LSM 完全負責強制執行特定 xattr 的訪問控制。 如果所有啟用的 LSM 都不註冊 'inode_xattr_skipcap' 鉤子,或者返回 0(預設返回值),則仍會執行 capability 檢查。 如果未註冊任何 'inode_xattr_skipcap' 鉤子,則會執行 capability 檢查。

返回

如果授予許可權,則返回 0。

int security_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, const char *acl_name, struct posix_acl *kacl)

檢查是否允許設定 posix acls

引數

struct mnt_idmap *idmap

掛載的 idmap

struct dentry *dentry

檔案

const char *acl_name

acl 名稱

struct posix_acl *kacl

acl 結構

描述

在設定 posix acls 之前檢查許可權,kacl 中的 posix acls 由 acl_name 標識。

返回

如果授予許可權,則返回 0。

void security_inode_post_set_acl(struct dentry *dentry, const char *acl_name, struct posix_acl *kacl)

從 posix acls 設定更新 inode 安全性

引數

struct dentry *dentry

檔案

const char *acl_name

acl 名稱

struct posix_acl *kacl

acl 結構

描述

成功在 dentry 上設定 posix acls 後,更新 inode 安全資料。 kacl 中的 posix acls 由 acl_name 標識。

int security_inode_get_acl(struct mnt_idmap *idmap, struct dentry *dentry, const char *acl_name)

檢查是否允許讀取 posix acls

引數

struct mnt_idmap *idmap

掛載的 idmap

struct dentry *dentry

檔案

const char *acl_name

acl 名稱

描述

在獲取 osix acls 之前檢查許可權,posix acls 由 acl_name 標識。

返回

如果授予許可權,則返回 0。

int security_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry, const char *acl_name)

檢查是否允許刪除 posix acl

引數

struct mnt_idmap *idmap

掛載的 idmap

struct dentry *dentry

檔案

const char *acl_name

acl 名稱

描述

在刪除 posix acls 之前檢查許可權,posix acls 由 acl_name 標識。

返回

如果授予許可權,則返回 0。

void security_inode_post_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry, const char *acl_name)

rm posix acls 後更新 inode 安全性

引數

struct mnt_idmap *idmap

掛載的 idmap

struct dentry *dentry

檔案

const char *acl_name

acl 名稱

描述

成功從 idmap 中的 dentry 中刪除 posix acls 後,更新 inode 安全資料。 posix acls 由 acl_name 標識。

void security_inode_post_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags)

在 setxattr 操作後更新 inode

引數

struct dentry *dentry

檔案

const char *name

xattr 名稱

const void *value

xattr 值

size_t size

xattr 值大小

int flags

標誌

描述

成功執行 setxattr 操作後,更新 inode 安全欄位。

int security_inode_getxattr(struct dentry *dentry, const char *name)

檢查是否允許訪問 xattr

引數

struct dentry *dentry

檔案

const char *name

xattr 名稱

描述

在獲取由 name 標識的 dentry 的擴充套件屬性之前檢查許可權。

返回

如果授予許可權,則返回 0。

int security_inode_listxattr(struct dentry *dentry)

檢查是否允許列出 xattrs

引數

struct dentry *dentry

檔案

描述

在獲取 dentry 的擴充套件屬性名稱列表之前檢查許可權。

返回

如果授予許可權,則返回 0。

int security_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry, const char *name)

檢查是否允許刪除 xattr

引數

struct mnt_idmap *idmap

掛載的 idmap

struct dentry *dentry

檔案

const char *name

xattr 名稱

描述

此鉤子在 dentry 上設定擴充套件屬性 (xattrs) 之前執行所需的許可權檢查。 重要的是要注意,在我們呼叫主要 LSM 實現之前,我們有一些額外的邏輯來檢測是否需要在 LSM 層執行額外的 capability 檢查。

通常,我們在執行各種 LSM 鉤子實現之前強制執行 capability 檢查,但是如果 LSM 想要避免此 capability 檢查,它可以註冊一個 'inode_xattr_skipcap' 鉤子,併為它想要避免 capability 檢查的 xattrs 返回值 1,讓 LSM 完全負責強制執行特定 xattr 的訪問控制。 如果所有啟用的 LSM 都不註冊 'inode_xattr_skipcap' 鉤子,或者返回 0(預設返回值),則仍會執行 capability 檢查。 如果未註冊任何 'inode_xattr_skipcap' 鉤子,則會執行 capability 檢查。

返回

如果授予許可權,則返回 0。

void security_inode_post_removexattr(struct dentry *dentry, const char *name)

在 removexattr op 之後更新 inode

引數

struct dentry *dentry

檔案

const char *name

xattr 名稱

描述

成功執行 removexattr 操作後更新 inode。

int security_inode_need_killpriv(struct dentry *dentry)

檢查是否需要 security_inode_killpriv()

引數

struct dentry *dentry

關聯的 dentry

描述

當 inode 已更改時呼叫,以確定是否應呼叫 security_inode_killpriv()

返回

如果發生錯誤導致 inode 更改操作中止,則返回 <0,如果

不需要呼叫 security_inode_killpriv(),則返回 0,如果需要呼叫 security_inode_killpriv(),則返回 >0。

int security_inode_killpriv(struct mnt_idmap *idmap, struct dentry *dentry)

刪除了 setuid 位,更新 LSM 狀態

引數

struct mnt_idmap *idmap

掛載的 idmap

struct dentry *dentry

關聯的 dentry

描述

正在刪除 dentry 的 setuid 位。 刪除類似的安全標籤。 使用 dentry->d_inode->i_mutex 持有鎖呼叫。

返回

成功時返回 0。 如果返回錯誤,則操作

導致刪除 setuid 位的操作失敗。

int security_inode_getsecurity(struct mnt_idmap *idmap, struct inode *inode, const char *name, void **buffer, bool alloc)

獲取 inode 的 xattr 安全標籤

引數

struct mnt_idmap *idmap

掛載的 idmap

struct inode *inode

inode

const char *name

xattr 名稱

void **buffer

安全標籤緩衝區

bool alloc

分配標誌

描述

透過 buffer 檢索與 inodename 關聯的安全標籤的擴充套件屬性表示形式的副本。 請注意,name 是刪除安全字首後屬性名稱的其餘部分。 alloc 用於指定呼叫是透過緩衝區返回一個值還是僅返回值的長度。

返回

成功時返回緩衝區的大小。

int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags)

設定inode的xattr安全標籤

引數

struct inode *inode

inode

const char *name

xattr 名稱

const void *value

安全標籤

size_t size

安全標籤的長度

int flags

標誌

描述

從擴充套件屬性值 **value** 為 **inode** 設定與 **name** 關聯的安全標籤。 **size** 指示 **value** 的大小(以位元組為單位)。**flags** 可以是 XATTR_CREATE、XATTR_REPLACE 或 0。請注意,**name** 是移除 security. 字首後屬性名稱的其餘部分。

返回

成功返回 0。

void security_inode_getlsmprop(struct inode *inode, struct lsm_prop *prop)

獲取inode的LSM資料

引數

struct inode *inode

inode

struct lsm_prop *prop

要返回的lsm特定資訊

描述

獲取與節點關聯的lsm特定資訊。

int security_kernfs_init_security(struct kernfs_node *kn_dir, struct kernfs_node *kn)

為kernfs節點初始化LSM上下文

引數

struct kernfs_node *kn_dir

父kernfs節點

struct kernfs_node *kn

要初始化的kernfs節點

描述

根據新建立的kernfs節點自身及其父節點的屬性,初始化其安全上下文。

返回

如果授予許可權,則返回 0。

int security_file_permission(struct file *file, int mask)

檢查檔案許可權

引數

struct file *file

檔案

int mask

請求的許可權

描述

在訪問開啟的檔案之前檢查檔案許可權。此鉤子由讀取或寫入檔案的各種操作呼叫。安全模組可以使用此鉤子對這些操作執行額外的檢查,例如,重新驗證使用許可權以支援許可權括號或策略更改。請注意,此鉤子在執行實際的讀取/寫入操作時使用,而 inode_security_ops 鉤子在開啟檔案時(以及許多其他操作)呼叫。雖然此鉤子可用於重新驗證各種讀取或寫入檔案的系統呼叫操作的許可權,但它不能解決記憶體對映檔案的許可權重新驗證問題。如果安全模組需要此類重新驗證,則必須單獨處理。

返回

如果授予許可權,則返回 0。

int security_file_alloc(struct file *file)

分配和初始化檔案的LSM blob

引數

struct file *file

檔案

描述

分配一個安全結構並將其附加到 file->f_security 欄位。首次建立結構時,安全欄位初始化為 NULL。

返回

如果鉤子成功並且授予許可權,則返回 0。

void security_file_release(struct file *file)

在釋放檔案引用之前執行操作

引數

struct file *file

檔案

描述

在釋放對檔案的最後一個引用之前執行操作。

void security_file_free(struct file *file)

釋放檔案的LSM blob

引數

struct file *file

檔案

描述

取消分配並釋放儲存在 file->f_security 中的任何安全結構。

int security_mmap_file(struct file *file, unsigned long prot, unsigned long flags)

檢查是否允許mmap檔案

引數

struct file *file

檔案

unsigned long prot

核心應用的保護

unsigned long flags

標誌

描述

檢查mmap操作的許可權。 **file** 可以為 NULL,例如,如果對映匿名記憶體。

返回

如果授予許可權,則返回 0。

int security_mmap_addr(unsigned long addr)

檢查是否允許mmap一個地址

引數

unsigned long addr

地址

描述

檢查 **addr** 處 mmap 操作的許可權。

返回

如果授予許可權,則返回 0。

int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, unsigned long prot)

檢查是否允許更改記憶體保護

引數

struct vm_area_struct *vma

記憶體區域

unsigned long reqprot

應用程式請求的保護

unsigned long prot

核心應用的保護

描述

在更改記憶體訪問許可權之前檢查許可權。

返回

如果授予許可權,則返回 0。

int security_file_lock(struct file *file, unsigned int cmd)

檢查是否允許檔案鎖

引數

struct file *file

檔案

unsigned int cmd

鎖定操作 (例如 F_RDLCK, F_WRLCK)

描述

在執行檔案鎖定操作之前檢查許可權。請注意,此鉤子同時調解 flock 和 fcntl 樣式的鎖。

返回

如果授予許可權,則返回 0。

int security_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg)

檢查是否允許 fcntl() 操作

引數

struct file *file

檔案

unsigned int cmd

fcntl 命令

unsigned long arg

命令引數

描述

在允許對檔案 **file** 執行由 **cmd** 指定的檔案操作之前檢查許可權。請注意,**arg** 有時表示使用者空間指標;在其他情況下,它可能是一個簡單的整數值。當 **arg** 表示使用者空間指標時,安全模組永遠不應使用它。

返回

如果授予許可權,則返回 0。

void security_file_set_fowner(struct file *file)

在 LSM blob 中設定檔案所有者資訊

引數

struct file *file

檔案

描述

將所有者安全資訊(通常來自 current->security)儲存在 file->f_security 中,以供 send_sigiotask 鉤子稍後使用。

呼叫此鉤子時會持有 file->f_owner.lock。

返回

成功返回 0。

int security_file_send_sigiotask(struct task_struct *tsk, struct fown_struct *fown, int sig)

檢查是否允許傳送 SIGIO/SIGURG

引數

struct task_struct *tsk

目標任務

struct fown_struct *fown

訊號傳送者

int sig

要傳送的訊號,如果為 0 則傳送 SIGIO

描述

檢查檔案所有者 **fown** 向程序 **tsk** 傳送 SIGIO 或 SIGURG 的許可權。請注意,此鉤子有時從中斷中呼叫。請注意,fown_struct,**fown**,永遠不在 struct file 的上下文之外,因此總是可以獲取檔案結構(和相關的安全資訊):container_of(fown, struct file, f_owner)。

返回

如果授予許可權,則返回 0。

int security_file_receive(struct file *file)

檢查是否允許透過 IPC 接收檔案

引數

struct file *file

正在接收的檔案

描述

此鉤子允許安全模組控制程序透過套接字 IPC 接收開啟的檔案描述符的能力。

返回

如果授予許可權,則返回 0。

int security_file_open(struct file *file)

儲存 open() 時間狀態以供 LSM 稍後使用

引數

struct file *file

描述

儲存 open-time 許可權檢查狀態,以便稍後在 file_permission 上使用,如果自 inode_permission 以來有任何更改,則重新檢查訪問。

我們可以透過檢查 file->f_flags & __FMODE_EXEC 來檢查檔案是否為執行而開啟(例如 execve(2) 呼叫),無論是直接還是間接(例如 ELF 的 ld.so)。

返回

如果授予許可權,則返回 0。

int security_file_truncate(struct file *file)

檢查是否允許截斷檔案

引數

struct file *file

檔案

描述

在截斷檔案之前檢查許可權,即使用 ftruncate。請注意,截斷許可權也可以基於路徑進行檢查,使用 **path_truncate** 鉤子。

返回

如果授予許可權,則返回 0。

int security_task_alloc(struct task_struct *task, unsigned long clone_flags)

分配任務的LSM blob

引數

struct task_struct *task

任務

unsigned long clone_flags

指示正在共享的內容的標誌

描述

處理與任務相關的資源的分配。

返回

成功返回零,失敗返回負值。

void security_task_free(struct task_struct *task)

釋放任務的LSM blob和相關資源

引數

struct task_struct *task

任務

描述

處理與任務相關的資源的釋放。請注意,這可以從中斷上下文中呼叫。

int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)

分配最小記憶體以允許 cred_transfer

引數

struct cred *cred

憑證

gfp_t gfp

gfp 標誌

描述

僅分配足夠的記憶體並附加到 **cred**,以便 cred_transfer() 不會得到 ENOMEM。

返回

成功時返回 0,失敗時返回負值。

void security_cred_free(struct cred *cred)

釋放憑證的LSM blob和相關資源

引數

struct cred *cred

憑證

描述

取消分配並清除一組憑證中的 cred->security 欄位。

int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp)

準備一組新的憑證

引數

struct cred *new

新的憑證

const struct cred *old

原始憑證

gfp_t gfp

gfp 標誌

描述

透過從舊集合複製資料來準備一組新的憑證。

返回

成功時返回 0,失敗時返回負值。

void security_transfer_creds(struct cred *new, const struct cred *old)

傳輸憑證

引數

struct cred *new

目標憑證

const struct cred *old

原始憑證

描述

將資料從原始憑證傳輸到新的憑證。

int security_kernel_act_as(struct cred *new, u32 secid)

設定核心憑據以充當 secid

引數

struct cred *new

憑證

u32 secid

secid

描述

設定核心服務的憑據以充當(主觀上下文)。當前任務必須是提名 secid 的任務。

返回

成功時返回 0。

int security_kernel_create_files_as(struct cred *new, struct inode *inode)

使用 inode 設定檔案建立上下文

引數

struct cred *new

目標憑證

struct inode *inode

引用 inode

描述

在一組憑據中設定檔案建立上下文,使其與指定 inode 的客觀上下文相同。當前任務必須是提名 inode 的任務。

返回

成功時返回 0。

int security_kernel_module_request(char *kmod_name)

檢查是否允許載入模組

引數

char *kmod_name

模組名稱

描述

允許觸發核心自動向上呼叫使用者空間,以便使用者空間載入具有給定名稱的核心模組的能力。

返回

成功時返回 0。

int security_task_fix_setuid(struct cred *new, const struct cred *old, int flags)

使用新的使用者 ID 屬性更新 LSM

引數

struct cred *new

更新的憑據

const struct cred *old

正在替換的憑據

int flags

LSM_SETID_* 標誌值

描述

在設定當前程序的一個或多個使用者身份屬性後,更新模組的狀態。 flags 引數指示哪個 set*uid 系統呼叫呼叫了此鉤子。如果 new 是將要安裝的一組憑據。應該對此進行修改,而不是對 current->cred 進行修改。

返回

成功返回 0。

int security_task_fix_setgid(struct cred *new, const struct cred *old, int flags)

使用新的組 ID 屬性更新 LSM

引數

struct cred *new

更新的憑據

const struct cred *old

正在替換的憑據

int flags

LSM_SETID_* 標誌值

描述

在設定當前程序的一個或多個組身份屬性後,更新模組的狀態。 flags 引數指示哪個 set*gid 系統呼叫呼叫了此鉤子。 new 是將要安裝的一組憑據。應該對此進行修改,而不是對 current->cred 進行修改。

返回

成功返回 0。

int security_task_fix_setgroups(struct cred *new, const struct cred *old)

使用新的補充組更新 LSM

引數

struct cred *new

更新的憑據

const struct cred *old

正在替換的憑據

描述

在設定當前程序的補充組身份屬性後,更新模組的狀態。 new 是將要安裝的一組憑據。應該對此進行修改,而不是對 current->cred 進行修改。

返回

成功返回 0。

int security_task_setpgid(struct task_struct *p, pid_t pgid)

檢查是否允許設定 pgid

引數

struct task_struct *p

正在修改的任務

pid_t pgid

新的 pgid

描述

在將程序 p 的程序組識別符號設定為 pgid 之前,檢查許可權。

返回

如果授予許可權,則返回 0。

int security_task_getpgid(struct task_struct *p)

檢查是否允許獲取 pgid

引數

struct task_struct *p

任務

描述

在獲取程序 p 的程序組識別符號之前,檢查許可權。

返回

如果授予許可權,則返回 0。

int security_task_getsid(struct task_struct *p)

檢查是否允許獲取會話 ID

引數

struct task_struct *p

任務

描述

在獲取程序 p 的會話識別符號之前,檢查許可權。

返回

如果授予許可權,則返回 0。

int security_task_setnice(struct task_struct *p, int nice)

檢查是否允許設定任務的 nice 值

引數

struct task_struct *p

目標任務

int nice

nice 值

描述

在將 p 的 nice 值設定為 nice 之前,檢查許可權。

返回

如果授予許可權,則返回 0。

int security_task_setioprio(struct task_struct *p, int ioprio)

檢查是否允許設定任務的 ioprio

引數

struct task_struct *p

目標任務

int ioprio

ioprio 值

描述

在將 p 的 ioprio 值設定為 ioprio 之前,檢查許可權。

返回

如果授予許可權,則返回 0。

int security_task_getioprio(struct task_struct *p)

檢查是否允許獲取任務的 ioprio

引數

struct task_struct *p

任務

描述

在獲取 p 的 ioprio 值之前,檢查許可權。

返回

如果授予許可權,則返回 0。

int security_task_prlimit(const struct cred *cred, const struct cred *tcred, unsigned int flags)

檢查是否允許獲取/設定資源限制

引數

const struct cred *cred

當前任務憑據

const struct cred *tcred

目標任務憑據

unsigned int flags

LSM_PRLIMIT_* 標誌位,指示獲取/設定/兩者

描述

在獲取和/或設定另一個任務的資源限制之前,檢查許可權。

返回

如果授予許可權,則返回 0。

int security_task_setrlimit(struct task_struct *p, unsigned int resource, struct rlimit *new_rlim)

檢查是否允許設定新的 rlimit 值

引數

struct task_struct *p

目標任務的組領導者

unsigned int resource

正在設定其限制的資源

struct rlimit *new_rlim

新的資源限制

描述

在將程序 presource 的資源限制設定為 new_rlim 之前,檢查許可權。可以透過取消引用 (p->signal->rlim + resource) 來檢查舊的資源限制值。

返回

如果授予許可權,則返回 0。

int security_task_setscheduler(struct task_struct *p)

檢查是否允許設定排程策略/引數

引數

struct task_struct *p

目標任務

描述

在設定程序 p 的排程策略和/或引數之前,檢查許可權。

返回

如果授予許可權,則返回 0。

int security_task_getscheduler(struct task_struct *p)

檢查是否允許獲取排程資訊

引數

struct task_struct *p

目標任務

描述

在獲取程序 p 的排程資訊之前,檢查許可權。

返回

如果授予許可權,則返回 0。

int security_task_movememory(struct task_struct *p)

檢查是否允許移動記憶體

引數

struct task_struct *p

任務

描述

在移動程序 p 擁有的記憶體之前,檢查許可權。

返回

如果授予許可權,則返回 0。

int security_task_kill(struct task_struct *p, struct kernel_siginfo *info, int sig, const struct cred *cred)

檢查是否允許傳送訊號

引數

struct task_struct *p

目標程序

struct kernel_siginfo *info

訊號資訊

int sig

訊號值

const struct cred *cred

訊號傳送者的憑據,如果 current 為 NULL

描述

在向 p 傳送訊號 sig 之前,檢查許可權。 info 可以是 NULL、常量 1 或指向 kernel_siginfo 結構的指標。如果 info 是 1 或 SI_FROMKERNEL(info) 為真,則應將該訊號視為來自核心,並且通常應允許。 SIGIO 訊號由 file_security_ops 中的 send_sigiotask 鉤子單獨處理。

返回

如果授予許可權,則返回 0。

int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5)

檢查是否允許 prctl 操作

引數

int option

操作

unsigned long arg2

引數

unsigned long arg3

引數

unsigned long arg4

引數

unsigned long arg5

引數

描述

在對當前程序執行程序控制操作之前,檢查許可權。

返回

如果沒有人想處理此操作,則返回 -ENOSYS,任何其他值

導致 prctl() 立即返回該值。

void security_task_to_inode(struct task_struct *p, struct inode *inode)

設定任務 inode 的安全屬性

引數

struct task_struct *p

任務

struct inode *inode

inode

描述

根據關聯任務的安全屬性設定 inode 的安全屬性,例如,對於 /proc/pid inodes。

int security_create_user_ns(const struct cred *cred)

檢查是否允許建立新的 userns

引數

const struct cred *cred

準備好的憑據

描述

在建立新的使用者名稱空間之前,檢查許可權。

返回

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

int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag)

檢查是否允許 sysv ipc 訪問

引數

struct kern_ipc_perm *ipcp

ipc 許可權結構

short flag

請求的許可權

描述

檢查訪問 IPC 的許可權。

返回

如果授予許可權,則返回 0。

void security_ipc_getlsmprop(struct kern_ipc_perm *ipcp, struct lsm_prop *prop)

獲取 sysv ipc 物件 LSM 資料

引數

struct kern_ipc_perm *ipcp

ipc 許可權結構

struct lsm_prop *prop

指向 lsm 資訊的指標

描述

獲取與 ipc 物件關聯的 lsm 資訊。

int security_msg_msg_alloc(struct msg_msg *msg)

分配一個 sysv ipc 訊息 LSM blob

引數

struct msg_msg *msg

訊息結構

描述

分配一個安全結構體,並將其附加到 msg->security 欄位。首次建立該結構體時,security 欄位初始化為 NULL。

返回

如果操作成功且許可權被授予,則返回 0。

void security_msg_msg_free(struct msg_msg *msg)

釋放一個 sysv ipc 訊息 LSM blob

引數

struct msg_msg *msg

訊息結構

描述

釋放此訊息的安全結構體。

int security_msg_queue_alloc(struct kern_ipc_perm *msq)

分配一個 sysv ipc 訊息佇列 LSM blob

引數

struct kern_ipc_perm *msq

sysv ipc 許可權結構

描述

分配一個安全結構體,並將其附加到 msg。首次建立該結構體時,security 欄位初始化為 NULL。

返回

如果操作成功且許可權被授予,則返回 0。

void security_msg_queue_free(struct kern_ipc_perm *msq)

釋放一個 sysv ipc 訊息佇列 LSM blob

引數

struct kern_ipc_perm *msq

sysv ipc 許可權結構

描述

釋放訊息佇列的 security 欄位 perm->security

int security_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)

檢查是否允許訊息佇列操作

引數

struct kern_ipc_perm *msq

sysv ipc 許可權結構

int msqflg

操作標誌

描述

透過 msgget 系統呼叫請求訊息佇列時,檢查許可權。僅當為現有訊息佇列返回訊息佇列識別符號時才呼叫此鉤子,而不是建立新訊息佇列時。

返回

如果授予許可權,則返回 0。

int security_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)

檢查是否允許訊息佇列操作

引數

struct kern_ipc_perm *msq

sysv ipc 許可權結構

int cmd

操作

描述

當要在具有許可權的訊息佇列上執行 cmd 指定的訊息控制操作時,檢查許可權。

返回

如果授予許可權,則返回 0。

int security_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *msg, int msqflg)

檢查是否允許傳送 sysv ipc 訊息

引數

struct kern_ipc_perm *msq

sysv ipc 許可權結構

struct msg_msg *msg

訊息

int msqflg

操作標誌

描述

在訊息 msg 排隊到 msq 中指定的具有許可權的訊息佇列之前,檢查許可權。

返回

如果授予許可權,則返回 0。

int security_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *msg, struct task_struct *target, long type, int mode)

檢查是否允許接收 sysv ipc 訊息

引數

struct kern_ipc_perm *msq

sysv ipc 許可權結構

struct msg_msg *msg

訊息

struct task_struct *target

目標任務

long type

請求的訊息型別

int mode

操作標誌

描述

在從訊息佇列中刪除訊息 msg 之前,檢查許可權。 target 任務結構包含一個指向將接收訊息的程序的指標(當執行內聯接收時,不等於當前程序)。

返回

如果授予許可權,則返回 0。

int security_shm_alloc(struct kern_ipc_perm *shp)

分配一個 sysv shm LSM blob

引數

struct kern_ipc_perm *shp

sysv ipc 許可權結構

描述

分配一個安全結構體,並將其附加到 shp 安全欄位。首次建立該結構體時,security 欄位初始化為 NULL。

返回

如果操作成功且許可權被授予,則返回 0。

void security_shm_free(struct kern_ipc_perm *shp)

釋放一個 sysv shm LSM blob

引數

struct kern_ipc_perm *shp

sysv ipc 許可權結構

描述

釋放記憶體段的安全結構體 perm->security

int security_shm_associate(struct kern_ipc_perm *shp, int shmflg)

檢查是否允許 sysv shm 操作

引數

struct kern_ipc_perm *shp

sysv ipc 許可權結構

int shmflg

操作標誌

描述

透過 shmget 系統呼叫請求共享記憶體區域時,檢查許可權。僅當為現有區域返回共享記憶體區域識別符號時才呼叫此鉤子,而不是建立新的共享記憶體區域時。

返回

如果授予許可權,則返回 0。

int security_shm_shmctl(struct kern_ipc_perm *shp, int cmd)

檢查是否允許 sysv shm 操作

引數

struct kern_ipc_perm *shp

sysv ipc 許可權結構

int cmd

操作

描述

當要在 shp 中具有許可權的共享記憶體區域上執行 cmd 指定的共享記憶體控制操作時,檢查許可權。

返回

如果授予許可權,則返回 0。

int security_shm_shmat(struct kern_ipc_perm *shp, char __user *shmaddr, int shmflg)

檢查是否允許 sysv shm 附加操作

引數

struct kern_ipc_perm *shp

sysv ipc 許可權結構

char __user *shmaddr

要附加的記憶體區域的地址

int shmflg

操作標誌

描述

在允許 shmat 系統呼叫將具有許可權 shp 的共享記憶體段附加到呼叫程序的資料段之前,檢查許可權。附加地址由 shmaddr 指定。

返回

如果授予許可權,則返回 0。

int security_sem_alloc(struct kern_ipc_perm *sma)

分配一個 sysv 訊號量 LSM blob

引數

struct kern_ipc_perm *sma

sysv ipc 許可權結構

描述

分配一個安全結構體,並將其附加到 sma 安全欄位。首次建立該結構體時,security 欄位初始化為 NULL。

返回

如果操作成功且許可權被授予,則返回 0。

void security_sem_free(struct kern_ipc_perm *sma)

釋放一個 sysv 訊號量 LSM blob

引數

struct kern_ipc_perm *sma

sysv ipc 許可權結構

描述

釋放訊號量的安全結構體 sma->security

int security_sem_associate(struct kern_ipc_perm *sma, int semflg)

檢查是否允許 sysv 訊號量操作

引數

struct kern_ipc_perm *sma

sysv ipc 許可權結構

int semflg

操作標誌

描述

透過 semget 系統呼叫請求訊號量時,檢查許可權。僅當為現有訊號量返回訊號量識別符號時才呼叫此鉤子,而不是建立新訊號量時。

返回

如果授予許可權,則返回 0。

int security_sem_semctl(struct kern_ipc_perm *sma, int cmd)

檢查是否允許 sysv 訊號量操作

引數

struct kern_ipc_perm *sma

sysv ipc 許可權結構

int cmd

操作

描述

當要在訊號量上執行 cmd 指定的訊號量操作時,檢查許可權。

返回

如果授予許可權,則返回 0。

int security_sem_semop(struct kern_ipc_perm *sma, struct sembuf *sops, unsigned nsops, int alter)

檢查是否允許 sysv 訊號量操作

引數

struct kern_ipc_perm *sma

sysv ipc 許可權結構

struct sembuf *sops

要執行的操作

unsigned nsops

操作的數量

int alter

指示將進行更改的標誌

描述

在對訊號量整合員執行操作之前,檢查許可權。如果 alter 標誌非零,則可以修改訊號量集。

返回

如果授予許可權,則返回 0。

int security_getselfattr(unsigned int attr, struct lsm_ctx __user *uctx, u32 __user *size, u32 flags)

讀取當前程序的 LSM 屬性。

引數

unsigned int attr

要返回哪個屬性

struct lsm_ctx __user *uctx

資訊的使用者空間目標,或 NULL

u32 __user *size

指向可用於接收資料的可用空間大小的指標

u32 flags

特殊處理選項。 LSM_FLAG_SINGLE 表示僅報告與傳遞的 ctx 中標識的 LSM 關聯的屬性。

描述

uctx 的 NULL 值可用於獲取屬性的數量和資料的大小。

成功時返回找到的屬性的數量,錯誤時返回負值。 size 重置為資料的總大小。如果 size 不足以包含資料,則返回 -E2BIG。

int security_setselfattr(unsigned int attr, struct lsm_ctx __user *uctx, u32 size, u32 flags)

設定當前程序的 LSM 屬性。

引數

unsigned int attr

要設定哪個屬性

struct lsm_ctx __user *uctx

資訊的使用者空間來源

u32 size

資料的大小

u32 flags

為將來使用保留,必須為 0

描述

設定當前程序的 LSM 屬性。 LSM、屬性和新值包含在 uctx 中。

成功時返回 0,如果輸入不一致則返回 -EINVAL,如果使用者緩衝區不可訪問則返回 -EFAULT,如果大小太大則返回 E2BIG,或者返回 LSM 特定故障。

int security_getprocattr(struct task_struct *p, int lsmid, const char *name, char **value)

讀取任務的屬性

引數

struct task_struct *p

任務

int lsmid

LSM 標識

const char *name

屬性名稱

char **value

屬性值

描述

讀取任務 p 的屬性 name,如果允許,將其儲存到 value 中。

返回

成功時返回 value 的長度,否則返回負值。

int security_setprocattr(int lsmid, const char *name, void *value, size_t size)

設定任務的屬性

引數

int lsmid

LSM 標識

const char *name

屬性名稱

void *value

屬性值

size_t size

屬性值大小

描述

如果允許,將當前任務的屬性 name 寫入(設定)為 value,大小為 size

返回

成功時返回寫入的位元組數,否則返回負值。

int security_post_notification(const struct cred *w_cred, const struct cred *cred, struct watch_notification *n)

檢查是否可以釋出監視通知

引數

const struct cred *w_cred

設定監視任務的憑據

const struct cred *cred

觸發監視任務的憑據

struct watch_notification *n

通知

描述

檢查是否可以將監視通知釋出到特定佇列。

返回

如果授予許可權,則返回 0。

int security_watch_key(struct key *key)

檢查是否允許任務監視金鑰事件

引數

struct key *key

要監視的金鑰

描述

檢查是否允許程序監視來自金鑰或金鑰環的事件通知。

返回

如果授予許可權,則返回 0。

儲存資訊並檢查是否允許netlink傳送

引數

struct sock *sk

傳送套接字

struct sk_buff *skb

netlink訊息

描述

儲存netlink訊息的安全資訊,以便在處理訊息時可以執行許可權檢查。可以使用netlink_skb_parms結構的eff_cap欄位儲存安全資訊。還可以用於提供對訊息傳輸的細粒度控制。

返回

如果成功儲存資訊並允許傳輸訊息,則返回0。

允許傳輸。

int security_socket_create(int family, int type, int protocol, int kern)

檢查是否允許建立新套接字

引數

int family

協議族

int type

通訊型別

int protocol

請求的協議

int kern

如果請求核心套接字,則設定為1

描述

在建立新套接字之前檢查許可權。

返回

如果授予許可權,則返回 0。

int security_socket_post_create(struct socket *sock, int family, int type, int protocol, int kern)

初始化新建立的套接字

引數

struct socket *sock

套接字

int family

協議族

int type

通訊型別

int protocol

請求的協議

int kern

如果請求核心套接字,則設定為1

描述

此鉤子允許模組更新或分配每個套接字的安全結構。 請注意,安全欄位未直接新增到套接字結構中,而是將套接字安全資訊儲存在關聯的 inode 中。 通常,inode alloc_security 鉤子會將安全資訊分配並附加到 SOCK_INODE(sock)->i_security。 此鉤子可用於使用在分配 inode 時無法獲得的附加資訊來更新 SOCK_INODE(sock)->i_security 欄位。

返回

如果授予許可權,則返回 0。

int security_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)

檢查是否允許套接字繫結操作

引數

struct socket *sock

套接字

struct sockaddr *address

請求的繫結地址

int addrlen

地址的長度

描述

在執行套接字協議層繫結操作並將套接字 sock 繫結到 address 引數中指定的地址之前,檢查許可權。

返回

如果授予許可權,則返回 0。

int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)

檢查是否允許套接字連線操作

引數

struct socket *sock

套接字

struct sockaddr *address

遠端連線點的地址

int addrlen

地址的長度

描述

在套接字協議層連線操作嘗試將套接字 sock 連線到遠端地址 address 之前,檢查許可權。

返回

如果授予許可權,則返回 0。

int security_socket_listen(struct socket *sock, int backlog)

檢查是否允許套接字偵聽

引數

struct socket *sock

套接字

int backlog

連線佇列大小

描述

在套接字協議層偵聽操作之前檢查許可權。

返回

如果授予許可權,則返回 0。

int security_socket_accept(struct socket *sock, struct socket *newsock)

檢查是否允許套接字接受連線

引數

struct socket *sock

偵聽套接字

struct socket *newsock

新建立的連線套接字

描述

在接受新連線之前檢查許可權。 請注意,已建立新套接字 newsock 並已將某些資訊複製到該套接字,但實際上尚未執行接受操作。

返回

如果授予許可權,則返回 0。

int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)

檢查是否允許傳送訊息

引數

struct socket *sock

傳送套接字

struct msghdr *msg

要傳送的訊息

int size

訊息大小

描述

在將訊息傳輸到另一個套接字之前檢查許可權。

返回

如果授予許可權,則返回 0。

int security_socket_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags)

檢查是否允許接收訊息

引數

struct socket *sock

接收套接字

struct msghdr *msg

要接收的訊息

int size

訊息大小

int flags

操作標誌

描述

在從套接字接收訊息之前檢查許可權。

返回

如果授予許可權,則返回 0。

int security_socket_getsockname(struct socket *sock)

檢查是否允許讀取套接字地址

引數

struct socket *sock

套接字

描述

在讀取套接字物件的本地地址(名稱)之前檢查許可權。

返回

如果授予許可權,則返回 0。

int security_socket_getpeername(struct socket *sock)

檢查是否允許讀取對等方的地址

引數

struct socket *sock

套接字

描述

在讀取套接字物件的遠端地址(名稱)之前檢查許可權。

返回

如果授予許可權,則返回 0。

int security_socket_getsockopt(struct socket *sock, int level, int optname)

檢查是否允許讀取套接字選項

引數

struct socket *sock

套接字

int level

選項的協議級別

int optname

選項名稱

描述

在檢索與套接字 sock 關聯的選項之前檢查許可權。

返回

如果授予許可權,則返回 0。

int security_socket_setsockopt(struct socket *sock, int level, int optname)

檢查是否允許設定套接字選項

引數

struct socket *sock

套接字

int level

選項的協議級別

int optname

選項名稱

描述

在設定與套接字 sock 關聯的選項之前檢查許可權。

返回

如果授予許可權,則返回 0。

int security_socket_shutdown(struct socket *sock, int how)

檢查是否允許關閉套接字

引數

struct socket *sock

套接字

int how

指示如何處理傳送和接收的標誌

描述

檢查是否允許關閉套接字 sock 上連線的全部或部分。

返回

如果授予許可權,則返回 0。

int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval, sockptr_t optlen, unsigned int len)

獲取遠端對等方標籤

引數

struct socket *sock

套接字

sockptr_t optval

目標緩衝區

sockptr_t optlen

複製到緩衝區中的對等方標籤的大小

unsigned int len

目標緩衝區的最大大小

描述

此鉤子允許安全模組透過 getsockopt SO_GETPEERSEC 為使用者空間提供 unix 或連線的 tcp 套接字的對等套接字安全狀態。 對於 tcp 套接字,如果套接字與 ipsec SA 相關聯,這可能是有意義的。

返回

如果一切正常,則返回 0,否則,返回典型的 getsockopt 返回值。

價值觀。

int lsm_sock_alloc(struct sock *sock, gfp_t gfp)

分配一個複合套接字 blob

引數

struct sock *sock

需要 blob 的套接字

gfp_t gfp

分配模式

描述

為所有模組分配套接字 blob

返回 0,如果無法分配記憶體,則返回 -ENOMEM。

int security_sk_alloc(struct sock *sk, int family, gfp_t priority)

分配和初始化套接字的 LSM blob

引數

struct sock *sk

套接字

int family

協議族

gfp_t priority

gfp 標誌

描述

分配並將安全結構附加到 sk->sk_security 欄位,該欄位用於在本地流套接字之間複製安全屬性。

返回

成功時返回 0,失敗時返回錯誤。

void security_sk_free(struct sock *sk)

釋放套接字的 LSM blob

引數

struct sock *sk

套接字

描述

取消分配安全結構。

void security_inet_csk_clone(struct sock *newsk, const struct request_sock *req)

基於 request_sock 設定新的 sock LSM 狀態

引數

struct sock *newsk

新的 sock

const struct request_sock *req

連線 request_sock

描述

使用 req 中的 LSM 狀態來設定 sock 的 LSM 狀態。

int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)

從 MPTCP 套接字繼承 LSM 標籤

引數

struct sock *sk

擁有的 MPTCP 套接字

struct sock *ssk

新的子流

描述

更新給定 MPTCP 子流的標籤,使其與擁有的 MPTCP 套接字的標籤匹配。這個鉤子必須在透過 security_socket_create()security_socket_post_create() LSM 鉤子建立和初始化套接字之後呼叫。

返回

成功返回 0,失敗返回負錯誤程式碼。

int security_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctxp)

克隆 xfrm 策略 LSM 狀態

引數

struct xfrm_sec_ctx *old_ctx

xfrm 安全上下文

struct xfrm_sec_ctx **new_ctxp

目標 xfrm 安全上下文

描述

在 new_ctxp 中分配一個安全結構,其中包含來自 old_ctx 結構的資訊。

返回

如果操作成功,則返回 0。

int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)

檢查是否允許刪除 xfrm 策略

引數

struct xfrm_sec_ctx *ctx

xfrm 安全上下文

描述

授權刪除 SPD 條目。

返回

如果授予許可權,則返回 0。

int security_xfrm_state_alloc_acquire(struct xfrm_state *x, struct xfrm_sec_ctx *polsec, u32 secid)

分配一個 xfrm 狀態 LSM blob

引數

struct xfrm_state *x

正在新增到 SAD 的 xfrm 狀態

struct xfrm_sec_ctx *polsec

關聯策略的安全上下文

u32 secid

來自流的 secid

描述

為 x->security 欄位分配一個安全結構;當分配 xfrm_state 時,該安全欄位初始化為 NULL。將上下文設定為與 secid 對應。

返回

如果操作成功,則返回 0。

void security_xfrm_state_free(struct xfrm_state *x)

釋放 xfrm 狀態

引數

struct xfrm_state *x

xfrm 狀態

描述

取消分配 x->security。

int security_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid)

檢查是否允許使用 xfrm 策略

引數

struct xfrm_sec_ctx *ctx

目標 xfrm 安全上下文

u32 fl_secid

用於授權訪問的流 secid

描述

檢查當流選擇 xfrm_policy 以處理資料包上的 XFRM 時是否允許該操作。 該鉤子在選擇每個套接字策略或通用 xfrm 策略時呼叫。

返回

如果授予許可權,則返回 0,否則返回 -ESRCH,或其他錯誤返回 -errno。

其他錯誤。

int security_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, const struct flowi_common *flic)

檢查 xfrm 是否匹配

引數

struct xfrm_state *x

要匹配的 xfrm 狀態

struct xfrm_policy *xp

要檢查是否匹配的 xfrm 策略

const struct flowi_common *flic

要檢查是否匹配的流。

描述

檢查 xpflic 是否與 x 匹配。

返回

如果存在匹配,則返回 1。

int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid)

確定資料包的 xfrm secid

引數

struct sk_buff *skb

xfrm 資料包

u32 *secid

secid

描述

解碼 skb 中的資料包,並在 secid 中返回安全標籤。

返回

如果所有使用的 xfrm 具有相同的 secid,則返回 0。

int security_key_alloc(struct key *key, const struct cred *cred, unsigned long flags)

分配並初始化核心金鑰 LSM blob

引數

struct key *key

金鑰

const struct cred *cred

憑證

unsigned long flags

分配標誌

描述

允許分配金鑰並分配安全資料。請注意,此時尚未為金鑰分配序列號。

返回

如果授予許可權,則返回 0,否則返回 -ve 錯誤。

void security_key_free(struct key *key)

釋放核心金鑰 LSM blob

引數

struct key *key

金鑰

描述

銷燬通知;釋放安全資料。

int security_key_permission(key_ref_t key_ref, const struct cred *cred, enum key_need_perm need_perm)

檢查是否允許核心金鑰操作

引數

key_ref_t key_ref

金鑰引用

const struct cred *cred

請求訪問的參與者的憑據

enum key_need_perm need_perm

請求的許可權

描述

檢視是否授予程序對金鑰的特定操作許可權。

返回

如果授予許可權,則返回 0,否則返回 -ve 錯誤。

int security_key_getsecurity(struct key *key, char **buffer)

獲取金鑰的安全標籤

引數

struct key *key

金鑰

char **buffer

安全標籤緩衝區

描述

獲取附加到金鑰的安全上下文的文字表示形式,以便於處理 KEYCTL_GETSECURITY。此函式分配 NUL 終止字串的儲存空間,呼叫者應釋放它。

返回

返回 buffer 的長度(包括終止 NUL),如果發生錯誤則返回 -ve。

如果金鑰未分配安全標籤,則也可能返回 0(以及 NULL 緩衝區指標)。

void security_key_post_create_or_update(struct key *keyring, struct key *key, const void *payload, size_t payload_len, unsigned long flags, bool create)

金鑰建立或更新通知

引數

struct key *keyring

金鑰所連結到的金鑰環

struct key *key

已建立或更新的金鑰

const void *payload

用於例項化或更新金鑰的資料

size_t payload_len

有效負載的長度

unsigned long flags

金鑰標誌

bool create

指示金鑰是建立還是更新的標誌

描述

通知呼叫者金鑰的建立或更新。

int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule, gfp_t gfp)

分配並初始化 LSM 審計規則結構

引數

u32 field

審計操作

u32 op

規則運算子

char *rulestr

規則上下文

void **lsmrule

審計規則結構的接收緩衝區

gfp_t gfp

用於 kmalloc 的 GFP 標誌

描述

分配並初始化 LSM 審計規則結構。

返回

如果已成功設定 lsmrule,則返回 0,如果規則無效,則返回 -EINVAL。

規則無效。

int security_audit_rule_known(struct audit_krule *krule)

檢查審計規則是否包含 LSM 欄位

引數

struct audit_krule *krule

審計規則

描述

指定給定的 krule 是否包含任何與當前 LSM 相關的欄位。

返回

如果找到關係,則返回 1,否則返回 0。

void security_audit_rule_free(void *lsmrule)

釋放 LSM 審計規則結構

引數

void *lsmrule

審計規則結構

描述

取消分配先前由 audit_rule_init() 分配的 LSM 審計規則結構。

int security_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op, void *lsmrule)

檢查標籤是否與審計規則匹配

引數

struct lsm_prop *prop

安全標籤

u32 field

LSM 審計欄位

u32 op

匹配運算子

void *lsmrule

審計規則

描述

確定給定的 secid 是否與先前經 security_audit_rule_known() 批准的規則匹配。

返回

如果 secid 與規則匹配,則返回 1,如果不匹配,則返回 0,如果失敗,則返回 -ERRNO。

失敗。

int security_bpf(int cmd, union bpf_attr *attr, unsigned int size, bool kernel)

檢查是否允許 bpf 系統呼叫操作

引數

int cmd

命令

union bpf_attr *attr

bpf 屬性

unsigned int size

size

bool kernel

呼叫是否源自核心

描述

在將屬性複製到核心後,對所有 bpf 系統呼叫執行初始檢查。實際的安全模組可以實現自己的規則來檢查它們需要的特定命令。

返回

如果授予許可權,則返回 0。

int security_bpf_map(struct bpf_map *map, fmode_t fmode)

檢查是否允許訪問 bpf map

引數

struct bpf_map *map

bpf map

fmode_t fmode

模式

描述

在核心為 eBPF map 生成並返回檔案描述符時進行檢查。

返回

如果授予許可權,則返回 0。

int security_bpf_prog(struct bpf_prog *prog)

檢查是否允許訪問 bpf 程式

引數

struct bpf_prog *prog

bpf 程式

描述

在核心為 eBPF 程式生成並返回檔案描述符時進行檢查。

返回

如果授予許可權,則返回 0。

int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr, struct bpf_token *token, bool kernel)

檢查是否允許建立 BPF map

引數

struct bpf_map *map

BPF map 物件

union bpf_attr *attr

用於建立 BPF map 的 BPF 系統呼叫屬性

struct bpf_token *token

用於授予使用者訪問許可權的 BPF 令牌

bool kernel

呼叫是否源自核心

描述

在核心建立新的 BPF map 時進行檢查。這也是為需要它們的 LSM 分配 LSM blob 的地方。

返回

成功時返回 0,失敗時返回錯誤。

int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr, struct bpf_token *token, bool kernel)

檢查是否允許載入 BPF 程式

引數

struct bpf_prog *prog

BPF 程式物件

union bpf_attr *attr

用於建立 BPF 程式的 BPF 系統呼叫屬性

struct bpf_token *token

用於授予使用者訪問 BPF 子系統許可權的 BPF 令牌

bool kernel

呼叫是否源自核心

描述

當核心載入 BPF 程式並分配相關的 BPF 程式物件時,執行訪問控制檢查。此鉤子還負責為 BPF 程式分配任何所需的 LSM 狀態。

返回

成功時返回 0,失敗時返回錯誤。

int security_bpf_token_create(struct bpf_token *token, union bpf_attr *attr, const struct path *path)

檢查是否允許建立 BPF 令牌

引數

struct bpf_token *token

BPF 令牌物件

union bpf_attr *attr

用於建立 BPF 令牌的 BPF 系統呼叫屬性

const struct path *path

指向從中建立 BPF 令牌的 BPF FS 掛載點的路徑

描述

當核心從 BPF FS 例項例項化新的 BPF 令牌物件時進行檢查。這也是可以為 LSM 分配 LSM blob 的地方。

返回

成功時返回 0,失敗時返回錯誤。

int security_bpf_token_cmd(const struct bpf_token *token, enum bpf_cmd cmd)

檢查是否允許 BPF 令牌委託請求的 BPF 系統呼叫命令

引數

const struct bpf_token *token

BPF 令牌物件

enum bpf_cmd cmd

請求由 BPF 令牌委託的 BPF 系統呼叫命令

描述

當核心決定提供的 BPF 令牌是否應允許委託請求的 BPF 系統呼叫命令時進行檢查。

返回

成功時返回 0,失敗時返回錯誤。

int security_bpf_token_capable(const struct bpf_token *token, int cap)

檢查是否允許 BPF 令牌委託請求的 BPF 相關 capability

引數

const struct bpf_token *token

BPF 令牌物件

int cap

請求由 BPF 令牌委託的 capability

描述

當核心決定提供的 BPF 令牌是否應允許委託請求的 BPF 相關 capability 時進行檢查。

返回

成功時返回 0,失敗時返回錯誤。

void security_bpf_map_free(struct bpf_map *map)

釋放 bpf map 的 LSM blob

引數

struct bpf_map *map

bpf map

描述

清理儲存在 bpf map 中的安全資訊。

void security_bpf_prog_free(struct bpf_prog *prog)

釋放 BPF 程式的 LSM blob

引數

struct bpf_prog *prog

BPF 程式結構

描述

清理儲存在 BPF 程式中的安全資訊。

void security_bpf_token_free(struct bpf_token *token)

釋放 BPF 令牌的 LSM blob

引數

struct bpf_token *token

BPF 令牌結構

描述

清理儲存在 BPF 令牌中的安全資訊。

int security_perf_event_open(int type)

檢查是否允許 perf event open

引數

int type

事件型別

描述

檢查是否允許 type 型別的 perf_event_open 系統呼叫。

返回

如果授予許可權,則返回 0。

int security_perf_event_alloc(struct perf_event *event)

分配 perf event LSM blob

引數

struct perf_event *event

perf event

描述

分配並儲存 perf_event 安全資訊。

返回

成功時返回 0,失敗時返回錯誤。

void security_perf_event_free(struct perf_event *event)

釋放 perf event LSM blob

引數

struct perf_event *event

perf event

描述

釋放(free)perf_event 安全資訊。

int security_perf_event_read(struct perf_event *event)

檢查是否允許讀取 perf event 標籤

引數

struct perf_event *event

perf event

描述

如果允許,讀取 perf_event 安全資訊。

返回

如果授予許可權,則返回 0。

int security_perf_event_write(struct perf_event *event)

檢查是否允許寫入 perf event 標籤

引數

struct perf_event *event

perf event

描述

如果允許,寫入 perf_event 安全資訊。

返回

如果授予許可權,則返回 0。

int security_uring_override_creds(const struct cred *new)

檢查是否允許覆蓋憑據

引數

const struct cred *new

新的憑證

描述

檢查執行 io_uring 操作的當前任務是否允許使用 new 覆蓋其憑據。

返回

如果授予許可權,則返回 0。

int security_uring_sqpoll(void)

檢查是否允許 IORING_SETUP_SQPOLL

引數

void

無引數

描述

檢查是否允許當前任務生成一個 io_uring 輪詢執行緒 (IORING_SETUP_SQPOLL)。

返回

如果授予許可權,則返回 0。

int security_uring_cmd(struct io_uring_cmd *ioucmd)

檢查是否允許 io_uring 直通命令

引數

struct io_uring_cmd *ioucmd

命令

描述

檢查是否允許執行 file_operations uring_cmd。

返回

如果授予許可權,則返回 0。

int security_uring_allowed(void)

檢查是否允許 io_uring_setup()

引數

void

無引數

描述

檢查是否允許當前任務呼叫 io_uring_setup()。

返回

如果授予許可權,則返回 0。

void security_initramfs_populated(void)

通知 LSM 已載入 initramfs

引數

void

無引數

描述

告知 LSM initramfs 已被解壓縮到 rootfs 中。

struct dentry *securityfs_create_file(const char *name, umode_t mode, struct dentry *parent, void *data, const struct file_operations *fops)

在 securityfs 檔案系統中建立一個檔案

引數

const char *name

指向包含要建立的檔名的字串的指標。

umode_t mode

檔案應具有的許可權

struct dentry *parent

指向此檔案的父 dentry 的指標。如果設定,這應為目錄 dentry。如果此引數為 NULL,則將在 securityfs 檔案系統的根目錄中建立檔案。

void *data

指向呼叫者稍後想要訪問的內容的指標。inode.i_private 指標將在 open() 呼叫中指向此值。

const struct file_operations *fops

指向應用於此檔案的 struct file_operations 的指標。

描述

此函式在 securityfs 中建立一個具有給定 name 的檔案。

如果成功,此函式將返回指向 dentry 的指標。當要刪除檔案時,必須將此指標傳遞給 securityfs_remove() 函式(如果您的模組被解除安裝,則不會發生自動清理,您需要自行負責)。如果發生錯誤,該函式將返回錯誤值(透過 ERR_PTR)。

如果 securityfs 未在核心中啟用,則返回 -ENODEV 值。

struct dentry *securityfs_create_dir(const char *name, struct dentry *parent)

在 securityfs 檔案系統中建立一個目錄

引數

const char *name

指向包含要建立的目錄名稱的字串的指標。

struct dentry *parent

指向此檔案的父 dentry 的指標。如果設定,這應為目錄 dentry。如果此引數為 NULL,則將在 securityfs 檔案系統的根目錄中建立該目錄。

描述

此函式在 securityfs 中建立一個具有給定 name 的目錄。

如果成功,此函式將返回指向 dentry 的指標。當要刪除檔案時,必須將此指標傳遞給 securityfs_remove() 函式(如果您的模組被解除安裝,則不會發生自動清理,您需要自行負責)。如果發生錯誤,該函式將返回錯誤值(透過 ERR_PTR)。

如果 securityfs 未在核心中啟用,則返回 -ENODEV 值。

在 securityfs 檔案系統中建立一個符號連結

引數

const char *name

指向包含要建立的符號連結名稱的字串的指標。

struct dentry *parent

指向符號連結的父 dentry 的指標。如果設定,這應為目錄 dentry。如果此引數為 NULL,則將在 securityfs 檔案系統的根目錄中建立該目錄。

const char *target

指向包含符號連結目標的名稱的字串的指標。如果此引數為 NULL,則需要設定 iops 引數來處理 .readlink 和 .get_link inode_operations。

const struct inode_operations *iops

指向用於符號連結的 struct inode_operations 的指標。如果此引數為 NULL,則將使用預設的 simple_symlink_inode operations。

描述

此函式在 securityfs 中建立一個具有給定 name 的符號連結。

如果成功,此函式將返回指向 dentry 的指標。當要刪除檔案時,必須將此指標傳遞給 securityfs_remove() 函式(如果您的模組被解除安裝,則不會發生自動清理,您需要自行負責)。如果發生錯誤,該函式將返回錯誤值(透過 ERR_PTR)。

如果 securityfs 未在核心中啟用,則返回 -ENODEV 值。

void securityfs_remove(struct dentry *dentry)

從 securityfs 檔案系統中移除檔案或目錄

引數

struct dentry *dentry

指向要移除的檔案或目錄的 dentry 的指標。

描述

此函式從 securityfs 中移除檔案或目錄,該檔案或目錄先前是透過呼叫另一個 securityfs 函式(例如 securityfs_create_file() 或其變體)建立的。

必須呼叫此函式才能移除檔案。模組移除時不會自動清理檔案;您需要在此處負責。

void securityfs_recursive_remove(struct dentry *dentry)

遞迴地移除檔案或目錄

引數

struct dentry *dentry

指向要移除的檔案或目錄的 dentry 的指標。

描述

此函式遞迴地從 securityfs 中移除檔案或目錄,該檔案或目錄先前是透過呼叫另一個 securityfs 函式(例如 securityfs_create_file() 或其變體)建立的。

審計介面

struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type)

獲取審計緩衝區

引數

struct audit_context *ctx

audit_context (可以為 NULL)

gfp_t gfp_mask

分配型別

int type

審計訊息型別

描述

成功時返回 audit_buffer 指標,失敗時返回 NULL。

獲取審計緩衝區。此例程會執行鎖定以獲取審計緩衝區,但隨後呼叫 audit_log_*format 不需要鎖定。如果任務 (ctx) 是當前在系統呼叫中的任務,則該系統呼叫將被標記為可審計,並且將在系統呼叫退出時寫入審計記錄。如果沒有關聯的任務,則任務上下文 (ctx) 應為 NULL。

void audit_log_format(struct audit_buffer *ab, const char *fmt, ...)

將訊息格式化到審計緩衝區中。

引數

struct audit_buffer *ab

audit_buffer

const char *fmt

格式字串

...

fmt 字串匹配的可選引數

描述

所有工作都在 audit_log_vformat 中完成。

void audit_log_end(struct audit_buffer *ab)

結束一條審計記錄

引數

struct audit_buffer *ab

audit_buffer

描述

我們無法在 irq 上下文中進行 netlink 傳送,因為它會阻塞(最後一個引數 flags 未設定為 MSG_DONTWAIT),因此審計緩衝區放置在一個佇列中,並排程一個 kthread 以在 irq 上下文之外從佇列中移除它們。可以在任何上下文中呼叫。

void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type, const char *fmt, ...)

記錄審計記錄

引數

struct audit_context *ctx

審計上下文

gfp_t gfp_mask

分配型別

int type

審計訊息型別

const char *fmt

要使用的格式字串

...

與格式字串匹配的可變引數

描述

這是一個便利函式,它呼叫 audit_log_start、audit_log_vformat 和 audit_log_end。可以在任何上下文中呼叫。

int __audit_filter_op(struct task_struct *tsk, struct audit_context *ctx, struct list_head *list, struct audit_names *name, unsigned long op)

操作的通用過濾器助手(syscall/uring/etc)

引數

struct task_struct *tsk

關聯的任務

struct audit_context *ctx

審計上下文

struct list_head *list

審計過濾器列表

struct audit_names *name

audit_name (可以為 NULL)

unsigned long op

當前 syscall/uring_op

描述

使用 ctxnameop(必要時)針對 tsk 執行 list 中指定的 udit 過濾器;呼叫者負責確保在持有 RCU 讀取鎖定時進行呼叫。 name 引數可以為 NULL,但必須指定所有其他引數。如果過濾器找到匹配項,則返回 1/true;如果未找到匹配項,則返回 0/false。

void audit_filter_uring(struct task_struct *tsk, struct audit_context *ctx)

將過濾器應用於 io_uring 操作

引數

struct task_struct *tsk

關聯的任務

struct audit_context *ctx

審計上下文

void audit_reset_context(struct audit_context *ctx)

重置 audit_context 結構

引數

struct audit_context *ctx

要重置的 audit_context

描述

audit_context 中的所有欄位都將重置為初始狀態,欄位持有的所有引用都將被刪除,並且私有記憶體將被釋放。當此函式返回時,audit_context 將適合重用,只要傳遞的上下文不是 NULL 或虛擬上下文。

int audit_alloc(struct task_struct *tsk)

為任務分配審計上下文塊

引數

struct task_struct *tsk

任務

描述

過濾任務資訊,並在必要時分配每個任務的審計上下文。這樣做會為指定的任務啟用系統呼叫審計。這是從 copy_process 呼叫的,因此不需要鎖定。

void audit_log_uring(struct audit_context *ctx)

生成 AUDIT_URINGOP 記錄

引數

struct audit_context *ctx

審計上下文

void __audit_free(struct task_struct *tsk)

釋放每個任務的審計上下文

引數

struct task_struct *tsk

要釋放其審計上下文塊的任務

描述

從 copy_process、do_exit 和 io_uring 程式碼呼叫

void audit_return_fixup(struct audit_context *ctx, int success, long code)

修復 audit_context 中的返回程式碼

引數

struct audit_context *ctx

audit_context

int success

指示操作是否成功的 true/false 值

long code

操作返回程式碼

描述

如果實際返回程式碼稍後將由特定於 arch 的訊號處理程式修復,我們需要修復審計日誌中的返回程式碼。

void __audit_uring_entry(u8 op)

為 io_uring 準備核心任務的審計上下文

引數

u8 op

io_uring 操作碼

描述

這類似於 audit_syscall_entry(),但旨在由 io_uring 操作使用。此函式應僅從 audit_uring_entry() 呼叫,因為我們依賴於該函式中存在的審計上下文檢查。

void __audit_uring_exit(int success, long code)

在 io_uring 之後包裝核心任務的審計上下文

引數

int success

指示操作是否成功的 true/false 值

long code

操作返回程式碼

描述

這類似於 audit_syscall_exit(),但旨在由 io_uring 操作使用。此函式應僅從 audit_uring_exit() 呼叫,因為我們依賴於該函式中存在的審計上下文檢查。

void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4)

在 syscall 進入時填寫審計記錄

引數

int major

主要的 syscall 型別(函式)

unsigned long a1

額外的 syscall 暫存器 1

unsigned long a2

額外的 syscall 暫存器 2

unsigned long a3

額外的 syscall 暫存器 3

unsigned long a4

額外的 syscall 暫存器 4

描述

在 syscall 進入時填寫審計上下文。只有在建立任務時建立了審計上下文,並且狀態或過濾器要求構建審計上下文時才會發生這種情況。如果來自每個任務的過濾器或來自每個 syscall 的過濾器的狀態為 AUDIT_STATE_RECORD,則該記錄將在 syscall 退出時寫入(否則,只有在核心的另一部分請求寫入該記錄時才會寫入)。

void __audit_syscall_exit(int success, long return_code)

在系統呼叫後釋放審計上下文

引數

int success

syscall 的成功值

long return_code

syscall 的返回值

描述

在系統呼叫後進行清理。如果審計上下文已被標記為可審計(由於過濾器的 AUDIT_STATE_RECORD 狀態,或者由於核心的另一部分寫入了審計訊息),則寫出 syscall 資訊。在所有情況下,釋放從 getname() 儲存的名稱。

struct filename *__audit_reusename(__user const char *uptr)

使用現有條目的資訊填寫檔名

引數

const __user char *uptr

指向路徑名的使用者空間指標

描述

在 audit_names 列表中搜索當前審計上下文。如果存在具有匹配“uptr”的現有條目,則返回與該 audit_name 關聯的檔名。如果不是,則返回 NULL。

void __audit_getname(struct filename *name)

將名稱新增到列表

引數

struct filename *name

要新增的名稱

描述

將名稱新增到此上下文的審計名稱列表中。從 fs/namei.c:getname() 呼叫。

void __audit_inode(struct filename *name, const struct dentry *dentry, unsigned int flags)

儲存來自查詢的 inode 和裝置

引數

struct filename *name

正在審計的名稱

const struct dentry *dentry

正在審計的 dentry

unsigned int flags

此特定條目的屬性

int auditsc_get_stamp(struct audit_context *ctx, struct timespec64 *t, unsigned int *serial)

獲取 audit_context 值的本地副本

引數

struct audit_context *ctx

任務的 audit_context

struct timespec64 *t

timespec64 用於儲存審計上下文中記錄的時間

unsigned int *serial

在審計上下文中記錄的序列值

描述

還會將上下文設定為可審計。

void __audit_mq_open(int oflag, umode_t mode, struct mq_attr *attr)

記錄 POSIX MQ 開啟的審計資料

引數

int oflag

開啟標誌

umode_t mode

模式位

struct mq_attr *attr

佇列屬性

void __audit_mq_sendrecv(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec64 *abs_timeout)

為POSIX MQ定時傳送/接收記錄審計資料

引數

mqd_t mqdes

MQ 描述符

size_t msg_len

訊息長度

unsigned int msg_prio

訊息優先順序

const struct timespec64 *abs_timeout

訊息超時,使用絕對時間

void __audit_mq_notify(mqd_t mqdes, const struct sigevent *notification)

為POSIX MQ通知記錄審計資料

引數

mqd_t mqdes

MQ 描述符

const struct sigevent *notification

通知事件

void __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)

為POSIX MQ獲取/設定屬性記錄審計資料

引數

mqd_t mqdes

MQ 描述符

struct mq_attr *mqstat

MQ 標誌

void __audit_ipc_obj(struct kern_ipc_perm *ipcp)

為 ipc 物件記錄審計資料

引數

struct kern_ipc_perm *ipcp

ipc 許可權

void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode)

為新的 ipc 許可權記錄審計資料

引數

unsigned long qbytes

msgq 位元組數

uid_t uid

msgq 使用者 ID

gid_t gid

msgq 組 ID

umode_t mode

msgq 模式 (許可權)

描述

僅在 audit_ipc_obj() 之後呼叫。

int __audit_socketcall(int nargs, unsigned long *args)

為 sys_socketcall 記錄審計資料

引數

int nargs

引數個數,不應超過 AUDITSC_ARGS。

unsigned long *args

引數陣列

void __audit_fd_pair(int fd1, int fd2)

為管道和socketpair記錄審計資料

引數

int fd1

第一個檔案描述符

int fd2

第二個檔案描述符

int __audit_sockaddr(int len, void *a)

為 sys_bind, sys_connect, sys_sendto 記錄審計資料

引數

int len

使用者空間中的資料長度

void *a

核心空間中的資料地址

描述

成功時返回0,NULL 上下文時返回 NULL,錯誤時返回 < 0。

int audit_signal_info_syscall(struct task_struct *t)

為 syscalls 記錄 signal 資訊

引數

struct task_struct *t

被髮送訊號的任務

描述

如果審計子系統正在終止,記錄執行此操作的任務 (pid) 和 uid。

int __audit_log_bprm_fcaps(struct linux_binprm *bprm, const struct cred *new, const struct cred *old)

儲存有關載入 bprm 和相關 fcaps 的資訊

引數

struct linux_binprm *bprm

指向正在處理的 bprm 的指標

const struct cred *new

提議的新憑據

const struct cred *old

舊憑據

描述

只需檢查 proc 是否已具有檔案給出的 capabilities,如果沒有,則儲存許可權提升資訊,以便在 syscall 結束時進行後續審計

-Eric

void __audit_log_capset(const struct cred *new, const struct cred *old)

儲存有關 capset syscall 引數的資訊

引數

const struct cred *new

新憑據

const struct cred *old

舊 (當前) 憑據

描述

記錄 userspace 傳送給 sys_capset 的引數,以便在適用時由審計系統進行後續列印

void audit_core_dumps(long signr)

記錄有關異常結束的程序的資訊

引數

long signr

訊號值

描述

如果程序以 core dump 結束,則可能存在一些可疑情況,我們應該記錄該事件以進行調查。

void audit_seccomp(unsigned long syscall, long signr, int code)

記錄有關 seccomp 操作的資訊

引數

unsigned long syscall

syscall 號

long signr

訊號值

int code

seccomp 操作

描述

記錄與 seccomp 操作相關的資訊。 不應記錄的 seccomp 操作的事件過濾在 seccomp_log() 中完成。 因此,此函式強制執行獨立於 audit_enabled 和 dummy 上下文狀態的審計,因為即使未使用審計,也應記錄 seccomp 操作。

int audit_rule_change(int type, int seq, void *data, size_t datasz)

將所有規則應用於指定的 訊息型別

引數

int type

審計訊息型別

int seq

netlink 審計訊息序列 (serial) 號

void *data

payload 資料

size_t datasz

payload 資料的大小

int audit_list_rules_send(struct sk_buff *request_skb, int seq)

列出審計規則

引數

struct sk_buff *request_skb

我們正在回覆的請求的 skb(用於定位回覆)

int seq

netlink 審計訊息序列 (serial) 號

int parent_len(const char *path)

查詢路徑名的父部分長度

引數

const char *path

要確定長度的路徑名

int audit_compare_dname_path(const struct qstr *dname, const char *path, int parentlen)

將給定的 dentry 名稱與給定路徑中的最後一個元件進行比較。 返回 0 表示匹配。

引數

const struct qstr *dname

我們正在比較的 dentry 名稱

const char *path

我們正在比較的完整路徑名

int parentlen

如果已知,父級的長度。 在此處傳入 AUDIT_NAME_FULL 表示我們必須計算此值。

會計框架

long sys_acct(const char __user *name)

啟用/停用程序會計

引數

const char __user * name

會計記錄的檔名,或者 NULL 以關閉會計

描述

sys_acct() 是實現程序會計所需的唯一系統呼叫。 它採用應寫入會計記錄的檔案的名稱。 如果檔名為 NULL,則將關閉會計。

返回

成功時返回 0,失敗時返回負 errno 值。

void acct_collect(long exitcode, int group_dead)

將會計資訊收集到 pacct_struct 中

引數

long exitcode

任務退出程式碼

int group_dead

如果此執行緒是程序中的最後一個執行緒,則不為 0。

void acct_process(void)

處理退出任務的程序會計

引數

void

無引數

塊裝置

void bio_advance(struct bio *bio, unsigned int nbytes)

按一定位元組數遞增/完成 bio

引數

struct bio *bio

要遞增的 bio

unsigned int nbytes

要完成的位元組數

描述

這會更新 bi_sector、bi_size 和 bi_idx; 如果要完成的位元組數與 bvec 邊界不對齊,則也會更新最後一個 bvec 上的 bv_len 和 bv_offset。

然後,bio 將表示 io 的剩餘的、未完成的部分。

struct folio_iter

用於迭代 bio 中所有 folios 的狀態。

定義:

struct folio_iter {
    struct folio *folio;
    size_t offset;
    size_t length;
};

成員

folio

我們正在迭代的當前 folio。 最後一個 folio 後為 NULL。

offset

當前 folio 中的位元組偏移量。

長度

此迭代中的位元組數(不會跨越 folio 邊界)。

bio_for_each_folio_all

bio_for_each_folio_all (fi, bio)

迭代 bio 中的每個 folio。

引數

fi

struct folio_iter,它為每個 folio 更新。

bio

要迭代的 struct bio。

struct bio *bio_next_split(struct bio *bio, int sectors, gfp_t gfp, struct bio_set *bs)

從 bio 獲取接下來的 sectors,必要時進行分割

引數

struct bio *bio

要分割的 bio

int sectors

bio 前端分割的扇區數

gfp_t gfp

gfp 掩碼

struct bio_set *bs

從中分配的 bio 集

返回

一個代表 bio 的接下來的 sectors 的 bio - 如果 bio 小於 sectors,則返回原始 bio,不做修改。

unsigned int bio_add_max_vecs(void *kaddr, unsigned int len)

將資料新增到 bio 所需的 bio_vecs 的數量

引數

void *kaddr

要新增的核心虛擬地址

unsigned int len

要新增的位元組長度

描述

計算最壞情況下,需要分配多少 bio_vecs 才能將 [kaddr:len] 中的核心虛擬地址範圍新增到 bio。

bool bio_is_zone_append(struct bio *bio)

這是一個 zone append bio 嗎?

引數

struct bio *bio

要檢查的 bio

描述

檢查 bio 是否為 zone append 操作。核心塊層程式碼和 end_io 處理程式必須使用此函式,而不是直接使用 REQ_OP_ZONE_APPEND 檢查,因為如果本地不支援,塊層可以將 REQ_OP_ZONE_APPEND 重寫為 REQ_OP_WRITE。

void blk_queue_flag_set(unsigned int flag, struct request_queue *q)

原子地設定佇列標誌

引數

unsigned int flag

要設定的標誌

struct request_queue *q

請求佇列

void blk_queue_flag_clear(unsigned int flag, struct request_queue *q)

原子地清除佇列標誌

引數

unsigned int flag

要清除的標誌

struct request_queue *q

請求佇列

const char *blk_op_str(enum req_op op)

返回 REQ_OP_XXX 中的字串 XXX。

引數

enum req_op op

REQ_OP_XXX。

描述

集中式塊層函式,用於將 REQ_OP_XXX 轉換為字串格式。在除錯和跟蹤 bio 或請求時很有用。對於無效的 REQ_OP_XXX,它返回字串“UNKNOWN”。

void blk_sync_queue(struct request_queue *q)

取消佇列上的任何掛起的回撥

引數

struct request_queue *q

佇列

描述

塊層可能會在佇列上執行非同步回撥活動,例如在超時後呼叫 unplug 函式。塊裝置可以呼叫 blk_sync_queue 來確保取消任何此類活動,從而允許它釋放回調可能使用的資源。呼叫者必須已經確保其 ->submit_bio 在呼叫此函式之前不會重新新增外掛。

此函式不會取消因電梯或節流程式碼而產生的任何非同步活動。那將需要使用初始化的佇列鎖呼叫 elevator_exit() 和 blkcg_exit_queue()。

void blk_set_pm_only(struct request_queue *q)

增加 pm_only 計數器

引數

struct request_queue *q

請求佇列指標

void blk_put_queue(struct request_queue *q)

減少 request_queue 引用計數

引數

struct request_queue *q

用於減少引用計數的 request_queue 結構

描述

減少 request_queue 的引用計數,並在引用計數達到 0 時釋放它。

bool blk_get_queue(struct request_queue *q)

增加 request_queue 引用計數

引數

struct request_queue *q

用於增加引用計數的 request_queue 結構

描述

增加 request_queue kobject 的引用計數。

上下文

任何上下文。

void submit_bio_noacct(struct bio *bio)

將 bio 重新提交到塊裝置層進行 I/O

引數

struct bio *bio

描述記憶體和裝置位置的 bio。

描述

這是 submit_bio() 的一個版本,僅應用於由堆疊塊驅動程式重新提交到較低級別驅動程式的 I/O。所有檔案系統和塊層的其他上層使用者都應改用 submit_bio()

void submit_bio(struct bio *bio)

將 bio 提交到塊裝置層進行 I/O

引數

struct bio *bio

描述 I/O 的 struct bio

描述

submit_bio() 用於將 I/O 請求提交到塊裝置。它傳遞一個完全設定好的 struct bio,該結構描述了需要完成的 I/O。bio 將被髮送到由 bi_bdev 欄位描述的裝置。

請求的成功/失敗狀態,以及完成通知,透過 bio 中的 ->bi_end_io() 回撥非同步傳遞。在呼叫 ->bi_end_io() 之前,呼叫者不得觸碰 bio。

int bio_poll(struct bio *bio, struct io_comp_batch *iob, unsigned int flags)

輪詢 BIO 完成

引數

struct bio *bio

要輪詢的 bio

struct io_comp_batch *iob

I/O 批處理

unsigned int flags

控制行為的 BLK_POLL_* 標誌

描述

輪詢與 bio 關聯的佇列上的完成。返回找到的已完成條目的數量。

注意

呼叫者必須是提交 bio 的上下文,或者在 RCU 臨界區中,以防止釋放 bio

unsigned long bio_start_io_acct(struct bio *bio)

啟動基於 bio 的驅動程式的 I/O 記帳

引數

struct bio *bio

要啟動記帳的 bio

描述

返回應傳遞迴 bio_end_io_acct() 的開始時間。

int blk_lld_busy(struct request_queue *q)

檢查裝置的底層低級別驅動程式是否繁忙

引數

struct request_queue *q

正在檢查的裝置的佇列

描述

檢查裝置的底層低級別驅動程式是否繁忙。如果驅動程式想要匯出其繁忙狀態,則必須首先使用 blk_queue_lld_busy() 設定自己的匯出函式。

基本上,此函式僅由請求堆疊驅動程式使用,以在底層裝置繁忙時停止將請求分派到底層裝置。此行為有助於在請求堆疊驅動程式的佇列上進行更多 I/O 合併,並防止在突發 I/O 負載下 I/O 吞吐量下降。

返回

0 - 不繁忙(請求堆疊驅動程式應分派請求) 1 - 繁忙(請求堆疊驅動程式應停止分派請求)

void blk_start_plug(struct blk_plug *plug)

初始化 blk_plug 並在 task_struct 中跟蹤它

引數

struct blk_plug *plug

需要初始化的 struct blk_plug

描述

blk_start_plug() 向塊層指示呼叫者打算批次提交多個 I/O 請求。塊層可以使用此提示來延遲從呼叫者提交 I/O,直到呼叫 blk_finish_plug()。但是,如果排隊的 I/O 數量超過 BLK_MAX_REQUEST_COUNT,或者 I/O 的大小大於 BLK_PLUG_FLUSH_SIZE,則塊層可能會選擇在呼叫 blk_finish_plug() 之前提交請求。如果任務排程(見下文),排隊的 I/O 也可能提前提交。

在 task_struct 中跟蹤 blk_plug 將有助於自動重新整理掛起的 I/O,如果任務最終在 blk_start_plug()blk_finish_plug() 之間阻塞。這從效能角度來看很重要,但也確保我們不會死鎖。例如,如果任務正在阻塞以進行記憶體分配,則記憶體回收最終可能想要釋放屬於當前駐留在我們的私有外掛中的請求的頁面。透過在程序進入睡眠狀態時重新整理掛起的 I/O,我們可以避免這種死鎖。

void blk_finish_plug(struct blk_plug *plug)

標記提交的 I/O 批處理的結束

引數

struct blk_plug *plug

傳遞給 blk_start_plug()struct blk_plug

描述

指示 I/O 提交批處理已完成。此函式必須與對 blk_start_plug() 的初始呼叫配對。目的是允許塊層最佳化 I/O 提交。有關更多資訊,請參閱 blk_start_plug() 的文件。

int blk_queue_enter(struct request_queue *q, blk_mq_req_flags_t flags)

嘗試增加 q->q_usage_counter

引數

struct request_queue *q

請求佇列指標

blk_mq_req_flags_t flags

BLK_MQ_REQ_NOWAIT 和/或 BLK_MQ_REQ_PM

int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, struct rq_map_data *map_data, const struct iov_iter *iter, gfp_t gfp_mask)

將使用者資料對映到請求,用於直通請求

引數

struct request_queue *q

應在其中插入請求的請求佇列

struct request *rq

要將資料對映到的請求

struct rq_map_data *map_data

指向儲存頁面的 rq_map_data 的指標(如果需要)

const struct iov_iter *iter

iovec 迭代器

gfp_t gfp_mask

記憶體分配標誌

描述

如果可能,資料將直接對映以實現零複製 I/O。否則,將使用核心反彈緩衝區。

在 I/O 結束時,仍然在程序上下文中時,必須發出匹配的 blk_rq_unmap_user()

int blk_rq_unmap_user(struct bio *bio)

取消對映具有使用者資料的請求

引數

struct bio *bio

bio 列表的開頭

描述

取消對映先前由 blk_rq_map_user() 對映的 rq。呼叫者必須提供來自 blk_rq_map_user() 返回的原始 rq->bio,因為 I/O 完成可能已更改 rq->bio。

int blk_rq_map_kern(struct request *rq, void *kbuf, unsigned int len, gfp_t gfp_mask)

為直通請求將核心資料對映到請求。

引數

struct request *rq

要填充的請求

void *kbuf

核心緩衝區

unsigned int len

使用者資料的長度

gfp_t gfp_mask

記憶體分配標誌

描述

如果可能,資料將被直接對映。否則,將使用反彈緩衝區。可以多次呼叫以附加多個緩衝區。

int blk_register_queue(struct gendisk *disk)

向 sysfs 註冊塊層佇列

引數

struct gendisk *disk

請求佇列應向 sysfs 註冊的磁碟。

void blk_unregister_queue(struct gendisk *disk)

blk_register_queue() 的對應函式

引數

struct gendisk *disk

應從 sysfs 取消註冊請求佇列的磁碟。

注意

呼叫者負責保證此函式在 blk_register_queue() 完成後呼叫。

void blk_set_stacking_limits(struct queue_limits *lim)

設定堆疊裝置的預設限制

引數

struct queue_limits *lim

要重置的 queue_limits 結構

描述

準備佇列限制,以便使用 blk_stack_limits() 應用來自底層裝置的限制。

int queue_limits_commit_update(struct request_queue *q, struct queue_limits *lim)

提交佇列限制的原子更新

引數

struct request_queue *q

要更新的佇列

struct queue_limits *lim

要應用的限制

描述

將 **lim** 中的限制應用於 q,這些限制是從 queue_limits_start_update() 獲取並由呼叫者更新的。呼叫者必須凍結佇列或確保沒有其他方式的未完成 I/O。

如果成功,則返回 0,否則返回負錯誤程式碼。

int queue_limits_commit_update_frozen(struct request_queue *q, struct queue_limits *lim)

提交佇列限制的原子更新

引數

struct request_queue *q

要更新的佇列

struct queue_limits *lim

要應用的限制

描述

將 **lim** 中的限制應用於 q,這些限制是從 queue_limits_start_update() 獲取並由呼叫者使用新值更新的。在更新之前凍結佇列,並在之後解凍佇列。

如果成功,則返回 0,否則返回負錯誤程式碼。

int queue_limits_set(struct request_queue *q, struct queue_limits *lim)

將佇列限制應用於佇列

引數

struct request_queue *q

要更新的佇列

struct queue_limits *lim

要應用的限制

描述

將 **lim** 中的限制應用於 q,這些限制是新初始化的。要更新現有限制,請改用 queue_limits_start_update() 和 queue_limits_commit_update()

如果成功,則返回 0,否則返回負錯誤程式碼。

int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, sector_t start)

調整堆疊裝置的 queue_limits

引數

struct queue_limits *t

堆疊驅動程式限制(頂部裝置)

struct queue_limits *b

底層佇列限制(底部,元件裝置)

sector_t start

元件裝置內的第一個資料扇區

描述

此函式由 MD 和 DM 等堆疊驅動程式使用,以確保所有元件裝置都具有相容的塊大小和對齊方式。堆疊驅動程式必須提供一個 queue_limits 結構(頂部),然後迭代地為所有元件(底部)裝置呼叫堆疊函式。堆疊函式將嘗試組合這些值並確保正確的對齊方式。

如果頂部和底部 queue_limits 相容,則返回 0。可以調整頂部裝置的塊大小和對齊偏移量,以確保與底部裝置對齊。如果不存在相容的大小和對齊方式,則返回 -1,並且生成的頂部 queue_limits 將設定 misaligned 標誌,以指示 alignment_offset 未定義。

void queue_limits_stack_bdev(struct queue_limits *t, struct block_device *bdev, sector_t offset, const char *pfx)

調整堆疊裝置的 queue_limits

引數

struct queue_limits *t

堆疊驅動程式限制(頂部裝置)

struct block_device *bdev

底層塊裝置(底部)

sector_t offset

元件裝置內資料起點的偏移量

const char *pfx

用於記錄警告的字首

描述

此函式由 MD 和 DM 等堆疊驅動程式使用,以確保所有元件裝置都具有相容的塊大小和對齊方式。堆疊驅動程式必須提供一個 queue_limits 結構(頂部),然後迭代地為所有元件(底部)裝置呼叫堆疊函式。堆疊函式將嘗試組合這些值並確保正確的對齊方式。

bool queue_limits_stack_integrity(struct queue_limits *t, struct queue_limits *b)

堆疊完整性配置檔案

引數

struct queue_limits *t

目標佇列限制

struct queue_limits *b

基本佇列限制

描述

檢查 **b** 中的完整性配置檔案是否可以堆疊到目標 **t** 中。如果滿足以下任一條件,則可以堆疊:

  1. 尚未堆疊任何完整性資訊

  2. **b** 中的完整性配置檔案與 **t** 中的配置檔案相同

如果可以將 **b** 堆疊到 **t** 中,則返回 true。否則,返回 false 並清除 **t** 中的完整性資訊。

void blk_set_queue_depth(struct request_queue *q, unsigned int depth)

告訴塊層裝置佇列深度

引數

struct request_queue *q

裝置的請求佇列

unsigned int depth

佇列深度

int blkdev_issue_flush(struct block_device *bdev)

排隊重新整理

引數

struct block_device *bdev

要發出重新整理的 blockdev

描述

為有問題的塊裝置發出重新整理。

int blkdev_issue_discard(struct block_device *bdev, sector_t sector, sector_t nr_sects, gfp_t gfp_mask)

排隊丟棄

引數

struct block_device *bdev

要發出丟棄的 blockdev

sector_t sector

起始扇區

sector_t nr_sects

要丟棄的扇區數

gfp_t gfp_mask

記憶體分配標誌(對於 bio_alloc)

描述

為有問題的扇區發出丟棄請求。

int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, sector_t nr_sects, gfp_t gfp_mask, struct bio **biop, unsigned flags)

生成多個零填充的寫 bio

引數

struct block_device *bdev

要發出的 blockdev

sector_t sector

起始扇區

sector_t nr_sects

要寫入的扇區數

gfp_t gfp_mask

記憶體分配標誌(對於 bio_alloc)

struct bio **biop

指向錨 bio 的指標

unsigned flags

控制詳細行為

描述

零填充一個塊範圍,可以使用硬體解除安裝,也可以透過將零顯式寫入裝置。

如果裝置使用邏輯塊配置,則如果 flags 包含 BLKDEV_ZERO_NOUNMAP,則不會釋放底層空間。

如果 flags 包含 BLKDEV_ZERO_NOFALLBACK,如果沒有為零填充提供顯式硬體解除安裝,則該函式將返回 -EOPNOTSUPP。

int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, sector_t nr_sects, gfp_t gfp_mask, unsigned flags)

零填充一個塊範圍

引數

struct block_device *bdev

要寫入的 blockdev

sector_t sector

起始扇區

sector_t nr_sects

要寫入的扇區數

gfp_t gfp_mask

記憶體分配標誌(對於 bio_alloc)

unsigned flags

控制詳細行為

描述

零填充一個塊範圍,可以使用硬體解除安裝,也可以透過將零顯式寫入裝置。有關 flags 的有效值,請參閱 __blkdev_issue_zeroout()

int blk_rq_map_integrity_sg(struct request *rq, struct scatterlist *sglist)

將完整性元資料對映到散列表

引數

struct request *rq

要對映的請求

struct scatterlist *sglist

目標散列表

描述

將請求中的完整性向量對映到散列表中。散列表必須足夠大以容納所有元素。即,使用 blk_rq_count_integrity_sg() 或 rq->nr_integrity_segments 調整大小。

int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg)

處理與跟蹤關聯的 ioctl

引數

struct block_device *bdev

塊裝置

unsigned cmd

ioctl cmd

char __user *arg

引數資料(如果有)

void blk_trace_shutdown(struct request_queue *q)

停止並清理跟蹤結構

引數

struct request_queue *q

與裝置關聯的請求佇列

void blk_add_trace_rq(struct request *rq, blk_status_t error, unsigned int nr_bytes, u32 what, u64 cgid)

為面向請求的操作新增跟蹤

引數

struct request *rq

源請求

blk_status_t error

要記錄的返回狀態

unsigned int nr_bytes

已完成的位元組數

u32 what

操作

u64 cgid

cgroup 資訊

描述

記錄針對請求的操作。將記錄 bio 偏移量 + 大小。

void blk_add_trace_bio(struct request_queue *q, struct bio *bio, u32 what, int error)

為 bio 導向的操作新增跟蹤資訊

引數

struct request_queue *q

IO 所在的佇列

struct bio *bio

源 bio

u32 what

操作

int error

錯誤碼(如果存在)

描述

記錄針對 bio 的操作。將記錄 bio 的偏移量 + 大小。

void blk_add_trace_bio_remap(void *ignore, struct bio *bio, dev_t dev, sector_t from)

為 bio 重新對映操作新增跟蹤資訊

引數

void *ignore

跟蹤回撥資料引數(未使用)

struct bio *bio

源 bio

dev_t dev

源裝置

sector_t from

源扇區

描述

在 bio 被重新對映到不同的裝置和/或扇區後呼叫。

void blk_add_trace_rq_remap(void *ignore, struct request *rq, dev_t dev, sector_t from)

為請求重新對映操作新增跟蹤資訊

引數

void *ignore

跟蹤回撥資料引數(未使用)

struct request *rq

源請求

dev_t dev

目標裝置

sector_t from

源扇區

描述

裝置對映器將請求重新對映到其他裝置。為該操作新增跟蹤資訊。

void disk_release(struct device *dev)

釋放 gendisk 的所有已分配資源

引數

struct device *dev

表示此磁碟的裝置

描述

此函式釋放 gendisk 的所有已分配資源。

使用 __device_add_disk() 的驅動程式具有分配了 request_queue 的 gendisk。由於對於這些驅動程式,request_queue 位於 gendisk 的頂部,因此我們還為它們呼叫 blk_put_queue(),我們期望 request_queue 的引用計數在此刻達到 0,因此 request_queue 也將在磁碟之前被釋放。

上下文

可以睡眠

unsigned int bdev_count_inflight(struct block_device *part)

獲取塊裝置正在進行的 IO 數量。

引數

struct block_device *part

塊裝置。

描述

Inflight 在這裡意味著已開始 IO 記帳,對於基於 bio 的塊裝置,從 bdev_start_io_acct() 開始,對於基於 rq 的塊裝置,從 blk_account_io_start() 開始。

int __register_blkdev(unsigned int major, const char *name, void (*probe)(dev_t devt))

註冊一個新的塊裝置

引數

unsigned int major

請求的主裝置號 [1..BLKDEV_MAJOR_MAX-1]。如果 major = 0,則嘗試分配任何未使用的主裝置號。

const char *name

新塊裝置的名稱,以零結尾的字串

void (*probe)(dev_t devt)

在訪問其預建立的裝置節點時,用於建立磁碟的 pre-devtmpfs / pre-udev 回撥。當 probe 呼叫使用 add_disk() 並且失敗時,驅動程式必須清理資源。此介面可能很快將被移除。

描述

name 在系統中必須是唯一的。

返回值取決於 major 輸入引數

  • 如果在範圍 [1..BLKDEV_MAJOR_MAX-1] 中請求了一個主裝置號,則該函式在成功時返回零,否則返回負錯誤程式碼

  • 如果使用 major = 0 引數請求了任何未使用的主裝置號,則返回值是在範圍 [1..BLKDEV_MAJOR_MAX-1] 中分配的主裝置號,否則返回負錯誤程式碼

有關已分配主裝置號的列表,請參見 Linux 分配的裝置(4.x+ 版本)

對於任何新程式碼,請使用 register_blkdev 代替。

int add_disk_fwnode(struct device *parent, struct gendisk *disk, const struct attribute_group **groups, struct fwnode_handle *fwnode)

將磁碟資訊新增到帶有 fwnode 的核心列表中

引數

struct device *parent

磁碟的父裝置

struct gendisk *disk

每個裝置的劃分資訊

const struct attribute_group **groups

其他每個裝置的 sysfs 組

struct fwnode_handle *fwnode

附加的磁碟 fwnode

描述

此函式將 disk 中的劃分資訊註冊到核心中。同時將 fwnode 附加到磁碟裝置。

int device_add_disk(struct device *parent, struct gendisk *disk, const struct attribute_group **groups)

將磁碟資訊新增到核心列表中

引數

struct device *parent

磁碟的父裝置

struct gendisk *disk

每個裝置的劃分資訊

const struct attribute_group **groups

其他每個裝置的 sysfs 組

描述

此函式將 disk 中的劃分資訊註冊到核心中。

void blk_mark_disk_dead(struct gendisk *disk)

將磁碟標記為死亡

引數

struct gendisk *disk

要標記為死亡的磁碟

描述

將磁碟標記為死亡(例如,意外移除)並且不接受任何新的 I/O 到該磁碟。

void del_gendisk(struct gendisk *disk)

移除 gendisk

引數

struct gendisk *disk

要移除的 struct gendisk

描述

移除 gendisk 及其所有相關資源。這將刪除與 gendisk 關聯的分割槽,並登出關聯的 request_queue。

這是對相應 __device_add_disk() 呼叫的計數器。

struct gendisk 的最終移除發生在它的引用計數達到 0 時,使用 put_disk(),如果使用了 __device_add_disk(),則應該在 del_gendisk() 之後呼叫。

存在一些驅動程式,它們依賴於 gendisk 的同步釋放,不應延遲。

上下文

可以睡眠

void invalidate_disk(struct gendisk *disk)

使磁碟無效

引數

struct gendisk *disk

要使其無效的 struct gendisk

描述

用於使磁碟無效的助手函式。它將清理磁碟關聯的緩衝區/頁面快取並重置其內部狀態,以便驅動程式可以重用該磁碟。

上下文

可以睡眠

void put_disk(struct gendisk *disk)

遞減 gendisk 引用計數

引數

struct gendisk *disk

要遞減引用計數的 struct gendisk

描述

這會遞減 struct gendisk 的引用計數。當它達到 0 時,我們將呼叫 disk_release()

注意

對於 blk-mq 磁碟,在處理 probe 錯誤時(即在呼叫 add_disk() 之前),必須在釋放 tag_set 之前呼叫 put_disk。

上下文

任何上下文,但不得從原子上下文中刪除最後一個引用。

void set_disk_ro(struct gendisk *disk, bool read_only)

將 gendisk 設定為只讀

引數

struct gendisk *disk

要操作的 gendisk

bool read_only

true 將磁碟設定為只讀,false 將磁碟設定為讀/寫

描述

此函式用於指示給定的磁碟裝置是否應設定其只讀標誌。set_disk_ro() 通常由裝置驅動程式使用,以指示底層物理裝置是否受到防寫。

int bdev_validate_blocksize(struct block_device *bdev, int block_size)

檢查此塊大小是否可接受

引數

struct block_device *bdev

要檢查的塊裝置

int block_size

要檢查的塊大小

描述

對於不使用緩衝區頭或塊裝置頁面快取的塊裝置使用者,請確保此塊大小可以與該裝置一起使用。

返回

成功時返回零,失敗時返回負錯誤程式碼。

int bdev_freeze(struct block_device *bdev)

鎖定檔案系統並強制其進入一致狀態

引數

struct block_device *bdev

要鎖定的塊裝置

描述

如果在此裝置上找到超級塊,我們將獲取其 s_umount 訊號量,以確保在快照建立完成之前沒有人解除安裝。引用計數器 (bd_fsfreeze_count) 保證只有最後一個解凍程序才能在同時到達多個凍結請求時實際解凍凍結的檔案系統。它在 bdev_freeze() 中計數增加,並在 bdev_thaw() 中計數減少。當它變為 0 時,thaw_bdev() 將實際解凍。

返回

成功時返回零,失敗時返回負錯誤程式碼。

int bdev_thaw(struct block_device *bdev)

解鎖檔案系統

引數

struct block_device *bdev

要解鎖的塊裝置

描述

bdev_freeze() 之後解鎖檔案系統並將其標記為再次可寫。

返回

成功時返回零,失敗時返回負錯誤程式碼。

int bd_prepare_to_claim(struct block_device *bdev, void *holder, const struct blk_holder_ops *hops)

宣告一個塊裝置

引數

struct block_device *bdev

感興趣的塊裝置

void *holder

嘗試宣告 bdev 的持有者

const struct blk_holder_ops *hops

持有者操作。

描述

宣告 bdev。如果 bdev 已經被另一個持有者宣告,並且另一個宣告正在進行中,則此函式將失敗並等待。返回後,呼叫者擁有 bd_claiming 和 bd_holder[s] 的所有權。

返回

如果可以宣告 bdev,則返回 0,否則返回 -EBUSY。

void bd_abort_claiming(struct block_device *bdev, void *holder)

中止對塊裝置的宣告

引數

struct block_device *bdev

感興趣的塊裝置

void *holder

已宣告 bdev 的持有者

描述

當獨佔開啟失敗時,中止對塊裝置的宣告。當實際上不需要獨佔開啟,而我們只需要暫時阻止其他獨佔開啟者時,也可以使用此方法。

void bdev_fput(struct file *bdev_file)

放棄對塊裝置的宣告並放入檔案

引數

struct file *bdev_file

開啟塊裝置

描述

放棄對塊裝置的宣告並放入檔案。確保可以在檔案關閉之前回收塊裝置,這是一個延遲操作。

int lookup_bdev(const char *pathname, dev_t *dev)

透過名稱查詢 struct block_device。

引數

const char *pathname

檔案系統中塊裝置的名稱。

dev_t *dev

指向塊裝置的 dev_t 的指標(如果找到)。

描述

如果可能,在當前名稱空間中的 pathname 處查詢塊裝置的 dev_t,並在 dev 中返回它。

上下文

可能會睡眠。

返回

成功時返回 0,否則返回負數的 errno。

void bdev_mark_dead(struct block_device *bdev, bool surprise)

將塊裝置標記為 dead

引數

struct block_device *bdev

要操作的塊裝置

bool surprise

指示意外移除

描述

告訴檔案系統該裝置或介質已失效。如果 surprise 設定為 true,則裝置或介質已經消失,否則我們正在準備有序移除。

這將呼叫檔案系統,檔案系統通常會同步所有髒資料並寫回 inode,然後使檔案系統上 inode 中的任何快取資料失效。此外,我們還會使塊裝置對映失效。

字元裝置

int register_chrdev_region(dev_t from, unsigned count, const char *name)

註冊一系列裝置號

引數

dev_t from

所需裝置號範圍中的第一個;必須包含主裝置號。

unsigned count

所需的連續裝置號的數量

const char *name

裝置或驅動程式的名稱。

描述

成功時返回值零,失敗時返回負錯誤程式碼。

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)

註冊一系列字元裝置號

引數

dev_t *dev

第一個分配的數字的輸出引數

unsigned baseminor

請求的小裝置號範圍中的第一個

unsigned count

所需的小裝置號的數量

const char *name

關聯裝置或驅動程式的名稱

描述

分配一系列字元裝置號。主裝置號將動態選擇,並在 dev 中返回(以及第一個小裝置號)。返回零或負錯誤程式碼。

int __register_chrdev(unsigned int major, unsigned int baseminor, unsigned int count, const char *name, const struct file_operations *fops)

建立並註冊一個 cdev,佔用一系列小裝置號

引數

unsigned int major

主裝置號;0 表示動態分配

unsigned int baseminor

請求的小裝置號範圍中的第一個

unsigned int count

所需的小裝置號的數量

const char *name

此裝置範圍的名稱

const struct file_operations *fops

與此裝置關聯的檔案操作

描述

如果 major == 0,則此函式將動態分配一個主裝置號並返回其編號。

如果 major > 0,則此函式將嘗試保留一個具有給定主裝置號的裝置,並在成功時返回零。

失敗時返回 -ve errno。

此裝置的名稱與 /dev 中裝置的名稱無關。它僅有助於跟蹤裝置的不同所有者。如果您的模組名稱只有一種型別的裝置,則在此處使用模組名稱是可以的。

void unregister_chrdev_region(dev_t from, unsigned count)

登出一系列裝置號

引數

dev_t from

要登出的號碼範圍中的第一個

unsigned count

要登出的裝置號的數量

描述

此函式將登出一系列 count 裝置號,從 from 開始。呼叫者通常應該是首先分配這些數字的人...

void __unregister_chrdev(unsigned int major, unsigned int baseminor, unsigned int count, const char *name)

登出並銷燬 cdev

引數

unsigned int major

主裝置號

unsigned int baseminor

小裝置號範圍中的第一個

unsigned int count

此 cdev 佔用的小裝置號的數量

const char *name

此裝置範圍的名稱

描述

登出並銷燬佔用由 majorbaseminorcount 描述的區域的 cdev。此函式撤消了 __register_chrdev() 所做的事情。

int cdev_add(struct cdev *p, dev_t dev, unsigned count)

將字元裝置新增到系統

引數

struct cdev *p

裝置的 cdev 結構

dev_t dev

此裝置負責的第一個裝置號

unsigned count

與此裝置對應的連續小裝置號的數量

描述

cdev_add() 將由 p 表示的裝置新增到系統,使其立即生效。失敗時返回負錯誤程式碼。

void cdev_set_parent(struct cdev *p, struct kobject *kobj)

為字元裝置設定父 kobject

引數

struct cdev *p

cdev 結構

struct kobject *kobj

要獲取引用的 kobject

描述

cdev_set_parent() 設定一個父 kobject,它將被適當地引用,以便在 cdev 之前不會釋放父物件。應在 cdev_add 之前呼叫此函式。

int cdev_device_add(struct cdev *cdev, struct device *dev)

新增字元裝置及其對應的 struct device,連結

引數

struct cdev *cdev

cdev 結構

struct device *dev

裝置結構

描述

cdev_device_add() 將由 cdev 表示的字元裝置新增到系統,就像 cdev_add 一樣。然後,它使用 device_add 將 dev 新增到系統。字元裝置的 dev_t 將從 struct device 中獲取,該結構需要首先初始化。此輔助函式正確地獲取對父裝置的引用,因此在釋放對 cdev 的所有引用之前,父裝置不會被釋放。

此助手使用 dev->devt 作為裝置號。如果未設定,它將不會新增 cdev,並且它將等效於 device_add。

只要 struct cdev 和 struct device 是同一結構的成員,並且該結構的生命週期由 struct device 管理,就應該使用此函式。

注意

呼叫者必須假定使用者空間能夠開啟 cdev,並且可以隨時呼叫 cdev fops 回撥,即使此函式失敗也是如此。

void cdev_device_del(struct cdev *cdev, struct device *dev)

cdev_device_add 的逆操作

引數

struct cdev *cdev

cdev 結構

struct device *dev

裝置結構

描述

cdev_device_del() 是一個呼叫 cdev_del 和 device_del 的輔助函式。只要使用 cdev_device_add,就應該使用它。

如果未設定 dev->devt,它將不會刪除 cdev,並且它將等效於 device_del。

注意

這保證了關聯的 sysfs 回撥不會執行或可執行,但是,任何已經開啟的 cdev 將保持不變,並且它們的 fops 仍然可以呼叫,即使在此函式返回之後也是如此。

void cdev_del(struct cdev *p)

從系統中刪除 cdev

引數

struct cdev *p

要刪除的 cdev 結構

描述

cdev_del() 從系統中刪除 p,可能會釋放結構本身。

注意

這保證了 cdev 裝置將不再能夠開啟,但是,任何已經開啟的 cdev 將保持不變,並且它們的 fops 仍然可以呼叫,即使在 cdev_del 返回之後也是如此。

struct cdev *cdev_alloc(void)

分配一個 cdev 結構

引數

void

無引數

描述

分配並返回一個 cdev 結構,如果失敗則返回 NULL。

void cdev_init(struct cdev *cdev, const struct file_operations *fops)

初始化一個 cdev 結構

引數

struct cdev *cdev

要初始化的結構

const struct file_operations *fops

此裝置的檔案操作

描述

初始化 cdev,記住 fops,使其準備好透過 cdev_add() 新增到系統。

時鐘框架

時鐘框架定義了程式設計介面,以支援系統時鐘樹的軟體管理。此框架廣泛用於片上系統 (SOC) 平臺,以支援電源管理和可能需要自定義時鐘速率的各種裝置。請注意,這些“時鐘”與計時或即時時鐘 (RTC) 無關,它們每個都有單獨的框架。這些 struct clk 例項可用於管理例如用於將位移入和移出外圍裝置或匯流排,或以其他方式觸發系統硬體中的同步狀態機轉換的 96 MHz 訊號。

電源管理由顯式軟體時鐘門控支援:停用未使用的時鐘,因此係統不會浪費電力來更改未在主動使用的電晶體的狀態。在某些系統上,這可以透過硬體時鐘門控來支援,其中時鐘在不停用軟體的情況下被門控。晶片中已供電但未計時的部分可能能夠保留其最後的狀態。這種低功耗狀態通常稱為保留模式。這種模式仍然會產生洩漏電流,尤其是在更精細的電路幾何形狀中,但對於 CMOS 電路,電力主要由計時狀態更改使用。

電源感知驅動程式僅在其管理的裝置處於活動使用狀態時才啟用其時鐘。此外,系統睡眠狀態通常因哪個時鐘域處於活動狀態而異:雖然“待機”狀態可能允許從幾個活動域喚醒,但“mem”(掛起至 RAM)狀態可能需要更徹底地關閉從更高速度 PLL 和振盪器派生的時鐘,從而限制了可能的喚醒事件源的數量。驅動程式的掛起方法可能需要知道目標睡眠狀態的系統特定時鐘約束。

某些平臺支援可程式設計時鐘發生器。這些可以被各種型別的外部晶片使用,例如其他 CPU、多媒體編解碼器以及對介面計時有嚴格要求的裝置。

struct clk_notifier

將 clk 與通知器關聯

定義:

struct clk_notifier {
    struct clk                      *clk;
    struct srcu_notifier_head       notifier_head;
    struct list_head                node;
};

成員

clk

要將通知器與之關聯的 struct clk *

notifier_head

此 clk 的 blocking_notifier_head

節點

連結串列指標

描述

通知器程式碼維護一個 struct clk_notifier 列表。每當程式碼在特定 clk 上註冊第一個通知器時,就會建立一個條目。該 clk 上的未來通知器將新增到 notifier_head

struct clk_notifier_data

要傳遞給通知器回撥的速率資料

定義:

struct clk_notifier_data {
    struct clk              *clk;
    unsigned long           old_rate;
    unsigned long           new_rate;
};

成員

clk

正在更改的 struct clk *

old_rate

此 clk 的先前速率

new_rate

此 clk 的新速率

描述

對於 pre-notifier,old_rate 是 clk 在此速率更改之前的速率,new_rate 是速率將來的值。對於 post-notifier,old_rate 和 new_rate 都設定為 clk 的當前速率(這樣做是為了最佳化實現)。

struct clk_bulk_data

用於批次 clk 操作的資料。

定義:

struct clk_bulk_data {
    const char              *id;
    struct clk              *clk;
};

成員

id

時鐘使用者 ID

clk

struct clk * 用於儲存關聯的時鐘

描述

CLK API 提供了一系列 clk_bulk_() API 呼叫,方便需要多個 clk 的使用者。此結構用於管理這些呼叫的資料。

int clk_notifier_register(struct clk *clk, struct notifier_block *nb)

註冊時鐘速率更改通知器回撥

引數

struct clk *clk

我們感興趣的速率的時鐘

struct notifier_block *nb

帶有回撥函式指標的通知器塊

描述

專家提示:跨通知器鏈進行除錯可能會令人沮喪。確保您的通知器回撥函式在發生故障時列印一個大的警告。

int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)

登出時鐘頻率改變通知回撥

引數

struct clk *clk

不再對其頻率感興趣的時鐘

struct notifier_block *nb

將被登出的通知塊

int devm_clk_notifier_register(struct device *dev, struct clk *clk, struct notifier_block *nb)

註冊一個託管的頻率改變通知回撥

引數

struct device *dev

時鐘“消費者”的裝置

struct clk *clk

我們感興趣的速率的時鐘

struct notifier_block *nb

帶有回撥函式指標的通知器塊

描述

成功時返回 0,否則返回 -EERROR

long clk_get_accuracy(struct clk *clk)

獲取時鐘源的精度,單位為 ppb(十億分之一)。

引數

struct clk *clk

時鐘源

描述

這獲取以 ppb 為單位表示的時鐘源精度。一個完美時鐘返回 0。

int clk_set_phase(struct clk *clk, int degrees)

調整時鐘訊號的相位偏移

引數

struct clk *clk

時鐘訊號源

int degrees

訊號偏移的度數

描述

將時鐘訊號的相位移動指定的度數。成功時返回 0,否則返回 -EERROR。

int clk_get_phase(struct clk *clk)

返回時鐘訊號的相位偏移

引數

struct clk *clk

時鐘訊號源

描述

返回時鐘節點的相位偏移(以度為單位),否則返回 -EERROR。

int clk_set_duty_cycle(struct clk *clk, unsigned int num, unsigned int den)

調整時鐘訊號的佔空比

引數

struct clk *clk

時鐘訊號源

unsigned int num

要應用的佔空比的分母

unsigned int den

要應用的佔空比的分母

描述

按指定比率調整時鐘訊號的佔空比。成功時返回 0,否則返回 -EERROR。

int clk_get_scaled_duty_cycle(struct clk *clk, unsigned int scale)

返回時鐘訊號的佔空比

引數

struct clk *clk

時鐘訊號源

unsigned int scale

應用於將比率表示為整數的縮放因子

描述

返回乘以提供的比例因子的佔空比,否則返回 -EERROR。

bool clk_is_match(const struct clk *p, const struct clk *q)

檢查兩個 clk 是否指向同一個硬體時鐘

引數

const struct clk *p

與 q 比較的 clk

const struct clk *q

與 p 比較的 clk

描述

如果兩個 struct clk 指標都指向同一個硬體時鐘節點,則返回 true。換句話說,如果 **p** 和 **q** 共享同一個 struct clk_core 物件,則返回 true。

否則返回 false。請注意,兩個 NULL clk 被視為匹配。

int clk_rate_exclusive_get(struct clk *clk)

獲取對生產者速率控制的獨佔權

引數

struct clk *clk

時鐘源

描述

此函式允許驅動程式獲得對提供者速率的獨佔控制。它可以防止任何其他使用者執行,即使是間接執行,可能改變提供者速率或導致故障的操作

如果在時鐘上多次宣告獨佔權,即使是同一驅動程式,速率實際上也會被鎖定,因為獨佔權無法被搶佔。

不得從原子上下文中呼叫。

返回成功 (0) 或負 errno。

int devm_clk_rate_exclusive_get(struct device *dev, struct clk *clk)

clk_rate_exclusive_get 的 devm 變體

引數

struct device *dev

獨佔權繫結到的裝置

struct clk *clk

時鐘源

描述

在 **clk** 上呼叫 clk_rate_exclusive_get() 並在 **dev** 上註冊一個 devm 清理處理程式,以呼叫 clk_rate_exclusive_put()

不得從原子上下文中呼叫。

void clk_rate_exclusive_put(struct clk *clk)

釋放對生產者速率控制的獨佔權

引數

struct clk *clk

時鐘源

描述

此函式允許驅動程式釋放先前從 clk_rate_exclusive_get() 獲得的獨佔權

呼叫者必須平衡 clk_rate_exclusive_get()clk_rate_exclusive_put() 呼叫的數量。

不得從原子上下文中呼叫。

int clk_prepare(struct clk *clk)

準備時鐘源

引數

struct clk *clk

時鐘源

描述

這為使用準備時鐘源。

不得從原子上下文中呼叫。

bool clk_is_enabled_when_prepared(struct clk *clk)

指示準備時鐘是否也會啟用它。

引數

struct clk *clk

時鐘源

描述

如果 clk_prepare() 隱式啟用時鐘,實際上使 clk_enable()/clk_disable() 成為空操作,則返回 true,否則返回 false。

這主要與電源管理程式碼相關,其中實際停用時鐘還需要取消準備才能產生任何實際效果。

無論此處返回的值如何,呼叫者都必須始終呼叫 clk_enable() 或 clk_prepare_enable() 及其對應項,以使使用計數正確。

void clk_unprepare(struct clk *clk)

撤銷時鐘源的準備

引數

struct clk *clk

時鐘源

描述

這會撤消先前準備的時鐘。呼叫者必須平衡準備和取消準備呼叫的數量。

不得從原子上下文中呼叫。

struct clk *clk_get(struct device *dev, const char *id)

查詢並獲取對時鐘生產者的引用。

引數

struct device *dev

時鐘“消費者”的裝置

const char *id

時鐘使用者 ID

描述

返回對應於時鍾生產者的 struct clk,或者包含 errno 的有效 IS_ERR() 條件。該實現使用 **dev** 和 **id** 來確定時鐘消費者,從而確定時鐘生產者。(換句話說,**id** 可能是相同的字串,但 clk_get 可能會根據 **dev** 返回不同的時鐘生產者。)

驅動程式必須假定時鐘源未啟用。

不應從中斷上下文中呼叫 clk_get。

int clk_bulk_get(struct device *dev, int num_clks, struct clk_bulk_data *clks)

查詢並獲取對時鐘生產者的多個引用。

引數

struct device *dev

時鐘“消費者”的裝置

int num_clks

clk_bulk_data 的數量

struct clk_bulk_data *clks

消費者的 clk_bulk_data 表

描述

此輔助函式允許驅動程式在一個操作中獲取多個 clk 消費者。如果無法獲取任何 clk,則在返回給呼叫者之前,將釋放已獲取的任何 clk。

如果成功獲取 clk_bulk_data 表中指定的所有時鐘,則返回 0,或者返回包含 errno 的有效 IS_ERR() 條件。該實現使用 **dev** 和 **clk_bulk_data.id** 來確定時鐘消費者,從而確定時鐘生產者。返回的時鐘儲存在每個 **clk_bulk_data.clk** 欄位中。

驅動程式必須假定時鐘源未啟用。

不應從中斷上下文中呼叫 clk_bulk_get。

int clk_bulk_get_all(struct device *dev, struct clk_bulk_data **clks)

查詢並獲取對時鐘生產者的所有可用引用。

引數

struct device *dev

時鐘“消費者”的裝置

struct clk_bulk_data **clks

指向消費者的 clk_bulk_data 表的指標

描述

此輔助函式允許驅動程式在一個操作中獲取所有 clk 消費者。如果無法獲取任何 clk,則在返回給呼叫者之前,將釋放已獲取的任何 clk。

返回獲取的時鐘數量的正值,同時時鐘引用儲存在 **clks** 欄位中的 clk_bulk_data 表中。如果沒有,則返回 0,如果發生錯誤,則返回負值。

驅動程式必須假定時鐘源未啟用。

不應從中斷上下文中呼叫 clk_bulk_get。

int clk_bulk_get_optional(struct device *dev, int num_clks, struct clk_bulk_data *clks)

查詢並獲取對時鐘生產者的多個引用

引數

struct device *dev

時鐘“消費者”的裝置

int num_clks

clk_bulk_data 的數量

struct clk_bulk_data *clks

消費者的 clk_bulk_data 表

描述

行為與 clk_bulk_get() 相同,除非沒有時鐘生產者。在這種情況下,該函式不會返回 -ENOENT,而是返回 0,對於無法確定時鐘生產者的 clk,則返回 NULL。

int devm_clk_bulk_get(struct device *dev, int num_clks, struct clk_bulk_data *clks)

託管獲取多個 clk 消費者

引數

struct device *dev

時鐘“消費者”的裝置

int num_clks

clk_bulk_data 的數量

struct clk_bulk_data *clks

消費者的 clk_bulk_data 表

描述

成功時返回 0,失敗時返回 errno。

此輔助函式允許驅動程式在一個操作中獲取多個 clk 消費者並進行管理,當裝置未繫結時,clk 將自動釋放。

int devm_clk_bulk_get_optional(struct device *dev, int num_clks, struct clk_bulk_data *clks)

獲取多個可選的消費者時鐘(託管的)

引數

struct device *dev

時鐘“消費者”的裝置

int num_clks

clk_bulk_data 的數量

struct clk_bulk_data *clks

指向消費者的 clk_bulk_data 表的指標

描述

行為與 devm_clk_bulk_get() 相同,除非沒有時鐘生產者。在這種情況下,函式不會返回 -ENOENT,而是為給定的時鐘返回 NULL。假設 clk_bulk_data 中的所有時鐘都是可選的。

如果成功獲取 clk_bulk_data 表中指定的所有時鐘,或者對於任何 clk 沒有可用的 clk 提供者,則返回 0,否則返回包含 errno 的有效 IS_ERR() 條件。該實現使用 devclk_bulk_data.id 來確定時鐘消費者,從而確定時鐘生產者。返回的時鐘儲存在每個 clk_bulk_data.clk 欄位中。

驅動程式必須假定時鐘源未啟用。

不應從中斷上下文中呼叫 clk_bulk_get。

int devm_clk_bulk_get_all(struct device *dev, struct clk_bulk_data **clks)

託管獲取多個 clk 消費者

引數

struct device *dev

時鐘“消費者”的裝置

struct clk_bulk_data **clks

指向消費者的 clk_bulk_data 表的指標

描述

返回獲取的時鐘數量的正值,同時時鐘引用儲存在 **clks** 欄位中的 clk_bulk_data 表中。如果沒有,則返回 0,如果發生錯誤,則返回負值。

此輔助函式允許驅動程式在一個操作中獲取多個 clk 消費者並進行管理,當裝置未繫結時,clk 將自動釋放。

int devm_clk_bulk_get_all_enabled(struct device *dev, struct clk_bulk_data **clks)

獲取並啟用消費者的所有時鐘(託管的)

引數

struct device *dev

時鐘“消費者”的裝置

struct clk_bulk_data **clks

指向消費者的 clk_bulk_data 表的指標

描述

返回獲取的時鐘數量的正值,同時時鐘引用儲存在 **clks** 欄位中的 clk_bulk_data 表中。如果沒有,則返回 0,如果發生錯誤,則返回負值。

此輔助函式允許驅動程式獲取消費者的所有時鐘,並在一次操作中啟用它們,並進行管理。當裝置取消繫結時,clks 將自動停用和釋放。

struct clk *devm_clk_get(struct device *dev, const char *id)

查詢並獲取對時鐘生產者的託管引用。

引數

struct device *dev

時鐘“消費者”的裝置

const char *id

時鐘使用者 ID

上下文

可能會睡眠。

返回

與時鐘生產者相對應的 struct clk,或包含 errno 的有效 IS_ERR() 條件。該實現使用 devid 來確定時鐘消費者,從而確定時鐘生產者。(也就是說,id 可能是相同的字串,但 clk_get 可能會根據 dev 返回不同的時鐘生產者。)

描述

驅動程式必須假設時鐘源既未準備好也未啟用。

當裝置從匯流排取消繫結時,時鐘將自動釋放。

struct clk *devm_clk_get_prepared(struct device *dev, const char *id)

devm_clk_get() + clk_prepare()

引數

struct device *dev

時鐘“消費者”的裝置

const char *id

時鐘使用者 ID

上下文

可能會睡眠。

返回

與時鐘生產者相對應的 struct clk,或包含 errno 的有效 IS_ERR() 條件。該實現使用 devid 來確定時鐘消費者,從而確定時鐘生產者。(也就是說,id 可能是相同的字串,但 clk_get 可能會根據 dev 返回不同的時鐘生產者。)

描述

返回的 clk(如果有效)已準備好。但是,驅動程式必須假定時鐘未啟用。

當裝置從匯流排取消繫結時,時鐘將自動取消準備並釋放。

struct clk *devm_clk_get_enabled(struct device *dev, const char *id)

devm_clk_get() + clk_prepare_enable()

引數

struct device *dev

時鐘“消費者”的裝置

const char *id

時鐘使用者 ID

上下文

可能會睡眠。

返回

與時鐘生產者相對應的 struct clk,或包含 errno 的有效 IS_ERR() 條件。該實現使用 devid 來確定時鐘消費者,從而確定時鐘生產者。(也就是說,id 可能是相同的字串,但 clk_get 可能會根據 dev 返回不同的時鐘生產者。)

描述

返回的 clk(如果有效)已準備好並啟用。

當裝置從匯流排取消繫結時,時鐘將自動停用、取消準備並釋放。

struct clk *devm_clk_get_optional(struct device *dev, const char *id)

查詢並獲取對可選時鐘生產者的託管引用。

引數

struct device *dev

時鐘“消費者”的裝置

const char *id

時鐘使用者 ID

上下文

可能會睡眠。

返回

與時鐘生產者相對應的 struct clk,或包含 errno 的有效 IS_ERR() 條件。該實現使用 devid 來確定時鐘消費者,從而確定時鐘生產者。如果未找到此類 clk,則它將返回 NULL,該值充當虛擬 clk。這是與 devm_clk_get() 相比唯一的區別。

描述

驅動程式必須假設時鐘源既未準備好也未啟用。

當裝置從匯流排取消繫結時,時鐘將自動釋放。

struct clk *devm_clk_get_optional_prepared(struct device *dev, const char *id)

devm_clk_get_optional() + clk_prepare()

引數

struct device *dev

時鐘“消費者”的裝置

const char *id

時鐘使用者 ID

上下文

可能會睡眠。

返回

與時鐘生產者相對應的 struct clk,或包含 errno 的有效 IS_ERR() 條件。該實現使用 devid 來確定時鐘消費者,從而確定時鐘生產者。如果未找到此類 clk,則它將返回 NULL,該值充當虛擬 clk。這是與 devm_clk_get_prepared() 相比唯一的區別。

描述

返回的 clk(如果有效)已準備好。但是,驅動程式必須假定時鐘未啟用。

當裝置從匯流排取消繫結時,時鐘將自動取消準備並釋放。

struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id)

devm_clk_get_optional() + clk_prepare_enable()

引數

struct device *dev

時鐘“消費者”的裝置

const char *id

時鐘使用者 ID

上下文

可能會睡眠。

返回

與時鐘生產者相對應的 struct clk,或包含 errno 的有效 IS_ERR() 條件。該實現使用 devid 來確定時鐘消費者,從而確定時鐘生產者。如果未找到此類 clk,則它將返回 NULL,該值充當虛擬 clk。這是與 devm_clk_get_enabled() 相比唯一的區別。

描述

返回的 clk(如果有效)已準備好並啟用。

當裝置從匯流排取消繫結時,時鐘將自動停用、取消準備並釋放。

struct clk *devm_clk_get_optional_enabled_with_rate(struct device *dev, const char *id, unsigned long rate)

devm_clk_get_optional() + clk_set_rate() + clk_prepare_enable()

引數

struct device *dev

時鐘“消費者”的裝置

const char *id

時鐘使用者 ID

unsigned long rate

新的時鐘頻率

上下文

可能會睡眠。

返回

與時鐘生產者相對應的 struct clk,或包含 errno 的有效 IS_ERR() 條件。該實現使用 devid 來確定時鐘消費者,從而確定時鐘生產者。如果未找到此類 clk,則它將返回 NULL,該值充當虛擬 clk。這是與 devm_clk_get_enabled() 相比唯一的區別。

描述

返回的 clk(如果有效)已準備好、啟用並設定了速率。

當裝置從匯流排取消繫結時,時鐘將自動停用、取消準備並釋放。

struct clk *devm_get_clk_from_child(struct device *dev, struct device_node *np, const char *con_id)

從子節點查詢並獲取對時鐘生產者的託管引用。

引數

struct device *dev

時鐘“消費者”的裝置

struct device_node *np

指向時鐘消費者節點的指標

const char *con_id

時鐘使用者 ID

描述

此函式解析時鐘,並使用它們透過使用 npcon_id 從註冊的時鐘提供者列表中查詢 struct clk

當裝置從匯流排取消繫結時,時鐘將自動釋放。

int clk_enable(struct clk *clk)

通知系統何時應執行時鐘源。

引數

struct clk *clk

時鐘源

描述

如果無法啟用/停用時鐘,則應返回成功。

可以從原子上下文中呼叫。

返回成功 (0) 或負 errno。

int clk_bulk_enable(int num_clks, const struct clk_bulk_data *clks)

通知系統何時應執行這組 clk。

引數

int num_clks

clk_bulk_data 的數量

const struct clk_bulk_data *clks

消費者的 clk_bulk_data 表

描述

可以從原子上下文中呼叫。

返回成功 (0) 或負 errno。

void clk_disable(struct clk *clk)

通知系統何時不再需要時鐘源。

引數

struct clk *clk

時鐘源

描述

通知系統驅動程式不再需要時鐘源,可以關閉。

可以從原子上下文中呼叫。

實現細節:如果時鐘源在多個驅動程式之間共享,則 clk_enable() 呼叫必須與相同數量的 clk_disable() 呼叫保持平衡,才能停用時鐘源。

void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks)

通知系統何時不再需要這組 clk。

引數

int num_clks

clk_bulk_data 的數量

const struct clk_bulk_data *clks

消費者的 clk_bulk_data 表

描述

通知系統驅動程式不再需要一組 clk,可以關閉。

可以從原子上下文中呼叫。

實現細節:如果這組 clk 在多個驅動程式之間共享,則 clk_bulk_enable() 呼叫必須與相同數量的 clk_bulk_disable() 呼叫保持平衡,才能停用時鐘源。

unsigned long clk_get_rate(struct clk *clk)

獲取時鐘源的當前時鐘頻率(以 Hz 為單位)。僅在啟用時鐘源後才有效。

引數

struct clk *clk

時鐘源

void clk_put(struct clk *clk)

“釋放”時鐘源

引數

struct clk *clk

時鐘源

注意

驅動程式必須確保在此時鐘源上進行的所有 clk_enable 呼叫在呼叫此函式之前都透過 clk_disable 呼叫保持平衡。

描述

不應從中斷上下文中呼叫 clk_put。

void clk_bulk_put(int num_clks, struct clk_bulk_data *clks)

“釋放”時鐘源

引數

int num_clks

clk_bulk_data 的數量

struct clk_bulk_data *clks

消費者的 clk_bulk_data 表

注意

驅動程式必須確保在此時鐘源上進行的所有 clk_bulk_enable 呼叫在呼叫此函式之前都透過 clk_bulk_disable 呼叫保持平衡。

描述

不應從中斷上下文中呼叫 clk_bulk_put。

void clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks)

“釋放”所有時鐘源

引數

int num_clks

clk_bulk_data 的數量

struct clk_bulk_data *clks

消費者的 clk_bulk_data 表

注意

驅動程式必須確保在此時鐘源上進行的所有 clk_bulk_enable 呼叫在呼叫此函式之前都透過 clk_bulk_disable 呼叫保持平衡。

描述

不應在中斷上下文中呼叫 clk_bulk_put_all。

void devm_clk_put(struct device *dev, struct clk *clk)

“釋放”一個託管時鐘源

引數

struct device *dev

用於獲取時鐘的裝置

struct clk *clk

使用 devm_clk_get() 獲取的時鐘源

注意

驅動程式必須確保在此時鐘源上進行的所有 clk_enable 呼叫在呼叫此函式之前都透過 clk_disable 呼叫保持平衡。

描述

不應從中斷上下文中呼叫 clk_put。

long clk_round_rate(struct clk *clk, unsigned long rate)

將速率調整為時鐘可以提供的精確速率

引數

struct clk *clk

時鐘源

unsigned long rate

所需的時鐘速率,單位為 Hz

描述

這回答了問題“如果我將 **rate** 傳遞給 clk_set_rate(),我最終會得到什麼樣的時鐘速率?”,而不會以任何方式更改硬體。換句話說

rate = clk_round_rate(clk, r);

clk_set_rate(clk, r); rate = clk_get_rate(clk);

是等效的,只是前者不會以任何方式修改時鐘硬體。

返回四捨五入的時鐘速率,單位為 Hz,或負的 errno。

int clk_set_rate(struct clk *clk, unsigned long rate)

設定時鐘源的時鐘速率

引數

struct clk *clk

時鐘源

unsigned long rate

所需的時鐘速率,單位為 Hz

描述

更新速率從最頂層受影響的時鐘開始,然後沿著樹向下走到需要更新的最底層時鐘。

返回成功 (0) 或負 errno。

int clk_set_rate_exclusive(struct clk *clk, unsigned long rate)

設定時鐘速率並宣告對時鐘源的獨佔權

引數

struct clk *clk

時鐘源

unsigned long rate

所需的時鐘速率,單位為 Hz

描述

此輔助函式允許驅動程式原子地設定生產者的速率並宣告對生產者速率控制的獨佔權。

它本質上是 clk_set_rate() 和 clk_rate_exclusite_get() 的組合。呼叫者必須透過呼叫 clk_rate_exclusive_put() 來平衡此呼叫。

返回成功 (0) 或負 errno。

bool clk_has_parent(const struct clk *clk, const struct clk *parent)

檢查一個時鐘是否是另一個時鐘可能的父時鐘

引數

const struct clk *clk

時鐘源

const struct clk *parent

父時鐘源

描述

驅動程式可以使用此函式來檢查一個時鐘是否可以成為另一個時鐘的父時鐘,而無需實際更改父時鐘。

如果 **parent** 是 **clk** 的可能父時鐘,則返回 true;否則返回 false。

int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)

為時鐘源設定速率範圍

引數

struct clk *clk

時鐘源

unsigned long min

所需的最小時鐘速率,單位為 Hz,包含

unsigned long max

所需的最大時鐘速率,單位為 Hz,包含

描述

返回成功 (0) 或負 errno。

int clk_set_min_rate(struct clk *clk, unsigned long rate)

為時鐘源設定最小時鐘速率

引數

struct clk *clk

時鐘源

unsigned long rate

所需的最小時鐘速率,單位為 Hz,包含

描述

返回成功 (0) 或負 errno。

int clk_set_max_rate(struct clk *clk, unsigned long rate)

為時鐘源設定最大時鐘速率

引數

struct clk *clk

時鐘源

unsigned long rate

所需的最大時鐘速率,單位為 Hz,包含

描述

返回成功 (0) 或負 errno。

int clk_set_parent(struct clk *clk, struct clk *parent)

為此時鐘設定父時鐘源

引數

struct clk *clk

時鐘源

struct clk *parent

父時鐘源

描述

返回成功 (0) 或負 errno。

struct clk *clk_get_parent(struct clk *clk)

獲取此時鐘的父時鐘源

引數

struct clk *clk

時鐘源

描述

返回與父時鐘源對應的 struct clk,或包含 errno 的有效 IS_ERR() 條件。

struct clk *clk_get_sys(const char *dev_id, const char *con_id)

根據裝置名稱獲取時鐘

引數

const char *dev_id

裝置名稱

const char *con_id

連線 ID

描述

返回與時鐘生產者對應的 struct clk,或包含 errno 的有效 IS_ERR() 條件。該實現使用 **dev_id** 和 **con_id** 來確定時鐘消費者,從而確定時鐘生產者。與 clk_get() 相比,此函式使用裝置名稱而不是裝置本身進行標識。

驅動程式必須假定時鐘源未啟用。

不應在中斷上下文中呼叫 clk_get_sys。

int clk_save_context(void)

儲存時鐘上下文以進行斷電

引數

void

無引數

描述

儲存時鐘暫存器的上下文,以用於暫存器內容將丟失的電源狀態。發生在掛起程式碼深處,因此不需要鎖定。

void clk_restore_context(void)

斷電後恢復時鐘上下文

引數

void

無引數

描述

這發生在所有時鐘都啟用的情況下。發生在恢復程式碼深處,因此不需要鎖定。

int clk_drop_range(struct clk *clk)

重置在該時鐘上設定的任何範圍

引數

struct clk *clk

時鐘源

描述

返回成功 (0) 或負 errno。

struct clk *clk_get_optional(struct device *dev, const char *id)

查詢並獲取對可選時鐘生產者的引用。

引數

struct device *dev

時鐘“消費者”的裝置

const char *id

時鐘使用者 ID

描述

其行為與 clk_get() 相同,只是在沒有時鐘生產者的情況下。在這種情況下,該函式不是返回 -ENOENT,而是返回 NULL。

同步原語

讀取-複製更新 (RCU)

bool same_state_synchronize_rcu(unsigned long oldstate1, unsigned long oldstate2)

兩個舊狀態值是否相同?

引數

unsigned long oldstate1

第一個舊狀態值。

unsigned long oldstate2

第二個舊狀態值。

描述

這兩個舊狀態值必須從 get_state_synchronize_rcu()start_poll_synchronize_rcu()get_completed_synchronize_rcu() 之一獲取。如果兩個值相同,則返回 **true**;否則返回 **false**。這允許其生存期由舊狀態值跟蹤的結構將這些值推送到列表標頭,從而使這些結構稍微小一些。

bool rcu_trace_implies_rcu_gp(void)

RCU 任務跟蹤寬限期是否意味著 RCU 寬限期?

引數

void

無引數

描述

作為實現的意外,RCU 任務跟蹤寬限期也充當 RCU 寬限期。但是,這隨時可能更改。依賴此意外的程式碼必須呼叫此函式以驗證此意外是否仍在發生。

已發出警告!

cond_resched_tasks_rcu_qs

cond_resched_tasks_rcu_qs ()

向 RCU 報告潛在的靜止狀態

描述

此宏類似於 cond_resched(),不同之處在於,即使 cond_resched() 機制已關閉,它也被定義為向 RCU 任務報告潛在的靜止狀態,正如某些 PREEMPTION 核心所倡導的那樣。

rcu_softirq_qs_periodic

rcu_softirq_qs_periodic (old_ts)

報告 RCU 和 RCU 任務靜止狀態

引數

old_ts

處理開始時的節拍數。

描述

此幫助程式用於長時間執行的 softirq 處理程式,例如網路中的 NAPI 執行緒。呼叫者應在 softirq 處理程式的開頭初始化作為 **old_ts** 傳遞的變數。頻繁呼叫時,此宏將在此後每 100 毫秒呼叫一次 rcu_softirq_qs(),這將提供 RCU 和 RCU 任務靜止狀態。請注意,此宏會修改其 old_ts 引數。

由於已停用 softirq 的程式碼區域充當 RCU 讀取端臨界區,因此應在啟用 softirq(和搶佔)的情況下呼叫此宏。

當定義了 CONFIG_PREEMPT_RT 時,不需要此宏。RT 核心將有更多機會呼叫 schedule() 呼叫並提供必要的靜止狀態。相比之下,僅呼叫 cond_resched() 不會達到相同的效果,因為 cond_resched() 不提供 RCU 任務靜止狀態。

RCU_LOCKDEP_WARN

RCU_LOCKDEP_WARN (c, s)

如果滿足指定的條件,則發出 lockdep splat

引數

c

要檢查的條件

s

資訊性訊息

描述

這會在檢查 (c) 之前檢查 debug_lockdep_rcu_enabled(),以防止由於 lockdep 尚未初始化而導致的早期引導 splat,並在檢查 (c) 之後重新檢查它,以防止由於 lockdep 被停用而導致的誤報 splat。有關更多詳細資訊,請參見 提交 3066820034b5dd(“rcu:拒絕 RCU_LOCKDEP_WARN() 誤報”)。

lockdep_assert_in_rcu_read_lock

lockdep_assert_in_rcu_read_lock ()

如果未受 rcu_read_lock() 保護,則發出警告

描述

如果啟用了 lockdep 並且沒有 rcu_read_lock() 生效,則發出 splat。

lockdep_assert_in_rcu_read_lock_bh

lockdep_assert_in_rcu_read_lock_bh ()

如果未受 rcu_read_lock_bh() 保護,則發出警告

描述

如果啟用了 lockdep 並且沒有生效的 rcu_read_lock_bh(),則會觸發 splat。請注意,local_bh_disable() 及其同類函式在這裡是不夠的,而是需要實際的 rcu_read_lock_bh()

lockdep_assert_in_rcu_read_lock_sched

lockdep_assert_in_rcu_read_lock_sched ()

如果未受 rcu_read_lock_sched() 保護,則發出警告。

描述

如果啟用了 lockdep 並且沒有生效的 rcu_read_lock_sched(),則會觸發 splat。請注意,preempt_disable() 及其同類函式在這裡是不夠的,而是需要實際的 rcu_read_lock_sched()

lockdep_assert_in_rcu_reader

lockdep_assert_in_rcu_reader ()

如果不在某種型別的 RCU 讀取器中,則發出警告。

描述

如果啟用了 lockdep 並且沒有任何型別的 RCU 讀取器生效,則會觸發 splat。請注意,受 preempt_disable、local_bh_disable() 和 local_irq_disable() 等保護的程式碼區域都符合 RCU 讀取器的條件。

請注意,這永遠不會在未同時使用 PREEMPT_COUNT 構建的 PREEMPT_NONE 或 PREEMPT_VOLUNTARY 核心中觸發。但是,如果您啟用了 lockdep,那麼最好也啟用 PREEMPT_COUNT。

unrcu_pointer

unrcu_pointer (p)

將指標標記為不受 RCU 保護。

引數

p

需要失去其 __rcu 屬性的指標。

描述

p 從 __rcu 指標轉換為 __kernel 指標。這允許將 __rcu 指標與 xchg() 及其同類函式一起使用。

RCU_INITIALIZER

RCU_INITIALIZER (v)

靜態初始化一個受 RCU 保護的全域性變數。

引數

v

要靜態初始化的值。

rcu_assign_pointer

rcu_assign_pointer (p, v)

賦值給受 RCU 保護的指標。

引數

p

要賦值的指標。

v

要賦值(釋出)的值。

描述

將指定的值賦值給指定的受 RCU 保護的指標,確保任何併發的 RCU 讀取器都將看到任何先前的初始化。

在需要它們的架構(即大多數架構)上插入記憶體屏障,並防止編譯器在指標賦值後重新排序初始化結構體的程式碼。更重要的是,此呼叫記錄了哪些指標將被 RCU 讀取端程式碼取消引用。

在某些特殊情況下,您可以使用 RCU_INIT_POINTER() 代替 rcu_assign_pointer()RCU_INIT_POINTER() 速度更快,因為它不限制 CPU 或編譯器。也就是說,當您應該使用 rcu_assign_pointer() 時使用 RCU_INIT_POINTER() 是一件非常糟糕的事情,會導致難以診斷的記憶體損壞。因此,請務必小心。有關詳細資訊,請參閱 RCU_INIT_POINTER() 註釋頭。

請注意,儘管看起來如此,rcu_assign_pointer() 僅評估其每個引數一次。其中一個“額外的”評估在 typeof() 中,另一個僅對 sparse (__CHECKER__) 可見,它們都不會實際執行引數。與大多數 cpp 宏一樣,這種僅執行引數一次的屬性非常重要,因此在更改 rcu_assign_pointer() 及其呼叫的其他宏時,請務必小心。

rcu_replace_pointer

rcu_replace_pointer (rcu_ptr, ptr, c)

替換 RCU 指標,返回其舊值。

引數

rcu_ptr

RCU 指標,其舊值將被返回。

ptr

常規指標

c

取消引用將發生的 lockdep 條件。

描述

執行替換,其中 rcu_ptr 是 RCU 註釋的指標,而 c 是傳遞給用於讀取該指標的 rcu_dereference_protected() 呼叫的 lockdep 引數。將返回 rcu_ptr 的舊值,並且 rcu_ptr 將設定為 ptr

rcu_access_pointer

rcu_access_pointer (p)

獲取 RCU 指標,不進行取消引用。

引數

p

要讀取的指標

描述

返回指定 RCU 保護的指標的值,但省略 RCU 讀取端臨界區中的 lockdep 檢查。當訪問此指標的值,但不取消引用指標時,這很有用,例如,當針對 NULL 測試 RCU 保護的指標時。雖然 rcu_access_pointer() 也可用於更新端鎖阻止指標的值更改的情況,但您應該為此用例改用 rcu_dereference_protected()。在 RCU 讀取端臨界區中,幾乎沒有理由使用 rcu_access_pointer()

通常最好直接測試 rcu_access_pointer() 返回值,以避免以後不注意的更改引入意外的取消引用。換句話說,將 rcu_access_pointer() 返回值分配給區域性變數會導致事故發生。

當對指標的讀取端訪問已至少在一個寬限期前刪除時,也可以使用 rcu_access_pointer(),例如在釋放資料的 RCU 回撥的上下文中,或者在 synchronize_rcu() 返回之後。在寬限期過去後拆除多連結結構時,這可能很有用。但是,通常首選 rcu_dereference_protected() 用於此用例。

rcu_dereference_check

rcu_dereference_check (p, c)

帶有除錯檢查的 rcu_dereference。

引數

p

取消引用之前要讀取的指標。

c

取消引用將發生的條件。

描述

執行 rcu_dereference(),但檢查取消引用將發生的條件是否正確。通常,這些條件指示此時應保持的各種鎖定條件。如果滿足條件,則檢查應返回 true。包含對 RCU 讀取端臨界區 (rcu_read_lock()) 中的隱式檢查。

例如

bar = rcu_dereference_check(foo->bar, lockdep_is_held(foo->lock));

可用於向 lockdep 指示只有在持有 rcu_read_lock() 或持有替換 foo->bar 處的 bar 結構所需的鎖時,才可以取消引用 foo->bar。

請注意,條件列表還可以包括何時不需要持有鎖的指示,例如在目標結構的初始化或銷燬期間。

bar = rcu_dereference_check(foo->bar, lockdep_is_held(foo->lock) ||

atomic_read(foo->usage) == 0);

在需要它們的架構(當前僅 Alpha)上插入記憶體屏障,防止編譯器重新獲取(併合並獲取),更重要的是,準確地記錄哪些指標受 RCU 保護,並檢查指標是否已註釋為 __rcu。

rcu_dereference_bh_check

rcu_dereference_bh_check (p, c)

帶有除錯檢查的 rcu_dereference_bh。

引數

p

取消引用之前要讀取的指標。

c

取消引用將發生的條件。

描述

這是 rcu_dereference_check() 的 RCU-bh 對應項。但是,請注意,從 v5.0 核心開始,vanilla RCU 寬限期除了等待由 rcu_read_lock()rcu_read_unlock() 標記的程式碼區域之外,還等待 local_bh_disable() 程式碼區域。這意味著 synchronize_rcu()、call_rcu 及其同類函式不僅考慮了 rcu_read_lock(),還考慮了 rcu_read_lock_bh()

rcu_dereference_sched_check

rcu_dereference_sched_check (p, c)

帶有除錯檢查的 rcu_dereference_sched。

引數

p

取消引用之前要讀取的指標。

c

取消引用將發生的條件。

描述

這是 rcu_dereference_check() 的 RCU-sched 對應項。但是,請注意,從 v5.0 核心開始,vanilla RCU 寬限期除了等待由 rcu_read_lock()rcu_read_unlock() 標記的程式碼區域之外,還等待 preempt_disable() 程式碼區域。這意味著 synchronize_rcu()、call_rcu 及其同類函式不僅考慮了 rcu_read_lock(),還考慮了 rcu_read_lock_sched()

rcu_dereference_protected

rcu_dereference_protected (p, c)

在阻止更新時獲取 RCU 指標。

引數

p

取消引用之前要讀取的指標。

c

取消引用將發生的條件。

描述

返回指定 RCU 保護的指標的值,但省略 READ_ONCE()。這在更新端鎖阻止指標的值更改的情況下很有用。請注意,此原語阻止編譯器重複此引用或將其與其他引用組合,因此不應在沒有適當鎖的保護的情況下使用它。

此函式僅供更新端使用。僅在受 rcu_read_lock() 保護時使用此函式會導致不頻繁但非常糟糕的故障。

rcu_dereference

rcu_dereference (p)

獲取 RCU 保護的指標以進行取消引用。

引數

p

取消引用之前要讀取的指標。

描述

這是 rcu_dereference_check() 周圍的簡單包裝器。

rcu_dereference_bh

rcu_dereference_bh (p)

獲取受 RCU-bh 保護的指標以進行取消引用。

引數

p

取消引用之前要讀取的指標。

描述

使 rcu_dereference_check() 完成所有髒活。

rcu_dereference_sched

rcu_dereference_sched (p)

獲取受 RCU-sched 保護的指標以進行取消引用。

引數

p

取消引用之前要讀取的指標。

描述

使 rcu_dereference_check() 完成所有髒活。

rcu_pointer_handoff

rcu_pointer_handoff (p)

將指標從 RCU 移交給其他機制。

引數

p

要移交的指標

描述

這只是一個恆等函式,但它記錄了指標從 RCU 移交給其他同步機制的位置,例如引用計數或鎖定。在 C11 中,它將對映到 kill_dependency()。它可以按如下方式使用。

rcu_read_lock();
p = rcu_dereference(gp);
long_lived = is_long_lived(p);
if (long_lived) {
        if (!atomic_inc_not_zero(p->refcnt))
                long_lived = false;
        else
                p = rcu_pointer_handoff(p);
}
rcu_read_unlock();
void rcu_read_lock(void)

標記 RCU 讀取端臨界區的開始。

引數

void

無引數

描述

如果在其他 CPU 位於 RCU 讀取端臨界區中時在一個 CPU 上呼叫 synchronize_rcu(),則保證 synchronize_rcu() 會阻塞,直到所有其他 CPU 退出其臨界區之後。類似地,如果在其他 CPU 位於 RCU 讀取端臨界區中時在一個 CPU 上呼叫 call_rcu(),則相應的 RCU 回撥的呼叫會延遲到所有其他 CPU 退出其臨界區之後。

synchronize_rcu()call_rcu() 都還會等待停用搶佔的程式碼區域,包括停用中斷或軟中斷的程式碼區域。

但是,請注意,允許 RCU 回撥與新的 RCU 讀取端臨界區併發執行。發生這種情況的一種方式是透過以下事件序列:(1)CPU 0 進入 RCU 讀取端臨界區,(2)CPU 1 呼叫 call_rcu() 以註冊 RCU 回撥,(3)CPU 0 退出 RCU 讀取端臨界區,(4)CPU 2 進入 RCU 讀取端臨界區,(5)呼叫 RCU 回撥。這是合法的,因為與 call_rcu() 併發執行的 RCU 讀取端臨界區(因此可能引用相應的 RCU 回撥會釋放的某些內容)在呼叫相應的 RCU 回撥之前已完成。

RCU 讀取端臨界區可以巢狀。任何延遲操作都將延遲到最外層的 RCU 讀取端臨界區完成。

您可以透過遵循以下規則來避免閱讀和理解下一段:不要將任何會在 !PREEMPTION 核心中阻塞的內容放入 rcu_read_lock() RCU 讀取端臨界區中。但是,如果您想要完整的故事,請繼續閱讀!

在不可搶佔的 RCU 實現(純 TREE_RCU 和 TINY_RCU)中,在 RCU 讀取端臨界區中阻塞是非法的。在 CONFIG_PREEMPTION 核心構建中的可搶佔 RCU 實現 (PREEMPT_RCU) 中,RCU 讀取端臨界區可能會被搶佔,但顯式阻塞是非法的。最後,在即時(帶有 -rt 補丁集)核心構建中的可搶佔 RCU 實現中,RCU 讀取端臨界區可能會被搶佔,並且它們也可能會阻塞,但僅在獲取受優先順序繼承約束的自旋鎖時。

void rcu_read_unlock(void)

標記 RCU 讀取端臨界區的結束。

引數

void

無引數

描述

在幾乎所有情況下,rcu_read_unlock() 都不會死鎖。由於當停用中斷時呼叫 rcu_read_unlock() 時執行的靜止狀態延遲,這種死鎖免疫性也擴充套件到排程程式的執行佇列和優先順序繼承自旋鎖。

有關更多資訊,請參閱 rcu_read_lock()

void rcu_read_lock_bh(void)

標記 RCU-bh 臨界區的開始。

引數

void

無引數

描述

這等效於 rcu_read_lock(),但也會停用軟中斷。請注意,任何停用軟中斷的其他操作也可以用作 RCU 讀取端臨界區。但是,請注意,此等效性僅適用於 v5.0 及更高版本。在 v5.0 之前,rcu_read_lock()rcu_read_lock_bh() 是不相關的。

請注意,rcu_read_lock_bh() 和與之匹配的 rcu_read_unlock_bh() 必須在同一上下文中發生。例如,如果匹配的 rcu_read_lock_bh() 是從其他任務呼叫的,則從一個任務呼叫 rcu_read_unlock_bh() 是非法的。

void rcu_read_unlock_bh(void)

標記軟中斷(softirq)專用 RCU 臨界區的結束

引數

void

無引數

描述

有關更多資訊,請參見 rcu_read_lock_bh()

void rcu_read_lock_sched(void)

標記 RCU-sched 臨界區的開始

引數

void

無引數

描述

這等效於 rcu_read_lock(),但也停用了搶佔。 讀端臨界區也可以由任何停用搶佔的操作引入,包括 local_irq_disable() 及其類似函式。 但是,請注意,與 rcu_read_lock() 的等效性僅適用於 v5.0 及更高版本。 在 v5.0 之前,rcu_read_lock()rcu_read_lock_sched() 是不相關的。

請注意,rcu_read_lock_sched() 和與之匹配的 rcu_read_unlock_sched() 必須在同一上下文中發生。例如,如果匹配的 rcu_read_lock_sched() 是從 NMI 處理程式呼叫的,則從程序上下文中呼叫 rcu_read_unlock_sched() 是非法的。

void rcu_read_unlock_sched(void)

標記 RCU-classic 臨界區的結束

引數

void

無引數

描述

有關更多資訊,請參見 rcu_read_lock_sched()

RCU_INIT_POINTER

RCU_INIT_POINTER (p, v)

初始化一個 RCU 保護的指標

引數

p

要初始化的指標。

v

指標要初始化的值。

描述

在特殊情況下初始化 RCU 保護的指標,在這些情況下,讀取者不需要 CPU 或編譯器的排序約束。 這些特殊情況是

  1. 使用 RCU_INIT_POINTER() 將指標置為 NULL *或*

  2. 呼叫者已採取必要的步驟來防止 RCU 讀取者併發訪問此指標 *或*

  3. 引用資料結構已經透過編譯時或透過 rcu_assign_pointer() 暴露給讀取者 *並且*

    1. 自那時以來,您沒有對此結構進行 *任何* 對讀取者可見的更改 *或*

    2. 允許從其新位置訪問此結構的讀取者看到該結構的舊狀態。(例如,更改是對統計計數器或其他不需要精確同步的狀態進行的。)

未能遵循這些關於使用 RCU_INIT_POINTER() 的規則將導致難以診斷的記憶體損壞。 就像在崩潰轉儲中結構看起來沒問題一樣,但是任何併發的 RCU 讀取者都可能看到引用資料結構的預初始化值。 因此,請非常小心地使用 RCU_INIT_POINTER()!!!

如果您正在建立一個由單個外部到結構的 RCU 保護的指標訪問的 RCU 保護的連結結構,則可以使用 RCU_INIT_POINTER() 初始化內部 RCU 保護的指標,但是在完全初始化連結結構的可讀取部分 *之後*,必須使用 rcu_assign_pointer() 初始化外部到結構的指標。

請注意,與 rcu_assign_pointer() 不同,RCU_INIT_POINTER() 不提供 CPU 或編譯器的排序保證。

RCU_POINTER_INITIALIZER

RCU_POINTER_INITIALIZER (p, v)

靜態初始化 RCU 保護的指標

引數

p

要初始化的指標。

v

指標要初始化的值。

描述

結構欄位中 RCU 保護的指標的 GCC 風格初始化。

kfree_rcu

kfree_rcu (ptr, rhf)

在寬限期後 kfree 物件。

引數

ptr

用於雙引數呼叫的 kfree 指標。

rhf

ptr 型別中 struct rcu_head 的名稱。

描述

許多 rcu 回撥函式只是對基本結構呼叫 kfree()。 這些函式很簡單,但是它們的大小會累積起來,而且當它們在核心模組中使用時,該模組必須在模組解除安裝時呼叫高延遲的 rcu_barrier() 函式。

kfree_rcu() 函式處理此問題。 為了使通用回撥函式處理 rcu_head 的不同偏移量,回撥需要確定被釋放物件的起始地址,該起始地址可以是大型 kmalloc 或 vmalloc 分配。 為了允許簡單地將指標向下對齊到頁邊界,只能容納最大 4095 位元組的偏移量。 如果偏移量大於 4095 位元組,則會在 kvfree_rcu_arg_2() 中生成編譯時錯誤。 如果觸發此錯誤,您可以回退到使用 call_rcu() 或重新排列結構以將 rcu_head 結構定位到前 4096 個位元組中。

要釋放的物件可以透過 kmalloc()kmem_cache_alloc() 分配。

請注意,允許的偏移量將來可能會減小。

BUILD_BUG_ON 檢查不得涉及任何函式呼叫,因此此處在宏中進行檢查。

kfree_rcu_mightsleep

kfree_rcu_mightsleep (ptr)

在寬限期後 kfree 物件。

引數

ptr

用於單引數呼叫的 kfree 指標。

描述

對於無頭變體,僅傳遞一個引數,即一個必須在寬限期後釋放的指標。 因此,語義是

kfree_rcu_mightsleep(ptr);

其中 ptr 是要透過 kvfree() 釋放的指標。

請注意,允許從必須遵循 might_sleep() 註釋的上下文中以無頭方式釋放。 否則,請切換並在 ptr 型別中嵌入 rcu_head 結構。

void rcu_head_init(struct rcu_head *rhp)

初始化 rcu_head 以用於 rcu_head_after_call_rcu()

引數

struct rcu_head *rhp

要初始化的 rcu_head 結構。

描述

如果您打算呼叫 rcu_head_after_call_rcu() 以測試給定的 rcu_head 結構是否已經傳遞給 call_rcu(),那麼您還必須在分配該結構後立即呼叫此 rcu_head_init() 函式。 對此函式的呼叫不得與對 call_rcu()rcu_head_after_call_rcu() 或回撥呼叫的呼叫競爭。

bool rcu_head_after_call_rcu(struct rcu_head *rhp, rcu_callback_t f)

此 rcu_head 是否已傳遞給 call_rcu()

引數

struct rcu_head *rhp

要測試的 rcu_head 結構。

rcu_callback_t f

rhp 一起傳遞給 call_rcu() 的函式。

描述

如果 rhp 已使用 func 傳遞給 call_rcu(),則返回 true,否則返回 false。 在任何其他情況下都會發出警告,包括 rhp 在寬限期後已經被呼叫的情況。 對此函式的呼叫不得與回撥呼叫競爭。 避免此類競爭的一種方法是將對 rcu_head_after_call_rcu() 的呼叫放在 RCU 讀取端臨界區中,該臨界區包含包含 rhp 的結構的指標的讀取端提取。

void rcu_softirq_qs(void)

在軟中斷處理中提供一組 RCU 靜止狀態

引數

void

無引數

描述

標記 RCU、Tasks RCU 和 Tasks Trace RCU 的靜止狀態。 這是一個特殊用途的函式,用於軟中斷基礎設施,也可能用於偶爾長時間執行的軟中斷處理程式。

請注意,從 RCU 的角度來看,呼叫 rcu_softirq_qs() 等效於暫時完全啟用搶佔。 例如,給定以下程式碼

local_bh_disable();
do_something();
rcu_softirq_qs();  // A
do_something_else();
local_bh_enable();  // B

與 do_something() 的呼叫併發開始的對 synchronize_rcu() 的呼叫將保證僅等待到執行到達語句 A。如果沒有 rcu_softirq_qs(),則相同的 synchronize_rcu() 將改為保證等待到執行到達語句 B。

bool rcu_watching_snap_stopped_since(struct rcu_data *rdp, int snap)

自指定的 snap 以來,RCU 是否停止監視給定的 CPU?

引數

struct rcu_data *rdp

與要檢查 EQS 的 CPU 對應的 rcu_data。

int snap

CPU 不在 EQS 中時拍攝的 rcu_watching 快照。

描述

如果與 rdp 對應的 CPU 自 snap 以來在擴充套件靜止狀態中花費了一些時間,則返回 true。 請注意,這不會檢查它是否 /仍然/ 在 EQS 中,只是檢查它自 snap 以來是否經歷過 EQS。

這旨在用於迴圈中,等待 CPU 經歷 EQS。

int rcu_is_cpu_rrupt_from_idle(void)

檢視是否從空閒狀態“中斷”

引數

void

無引數

描述

如果當前 CPU 處於空閒狀態,並且正在執行第一級(非巢狀)中斷,或者直接從空閒狀態執行,則返回 true。

呼叫者必須至少停用 IRQ。

void rcu_irq_exit_check_preempt(void)

驗證是否可以進行排程

引數

void

無引數

void __rcu_irq_enter_check_tick(void)

如果 RCU 需要,則在 CPU 上啟用排程程式時鐘。

引數

void

無引數

描述

當 CPU 從 nohz_full 使用者空間執行進入核心時,排程程式時鐘通常不會啟用。 畢竟,nohz_full 使用者空間執行是 RCU 靜止狀態,並且在核心中執行的時間非常短。 除非當然不是。 並且不難導致大型系統在核心中迴圈數十秒甚至數分鐘,這會導致許多問題,包括 RCU CPU 停止警告。

因此,如果 nohz_full CPU 未能及時報告靜止狀態,則 RCU 寬限期 kthread 會設定該 CPU 的 ->rcu_urgent_qs 標誌,並期望下一個中斷或異常會呼叫此函式,這將開啟排程程式時鐘,這將使 RCU 能夠檢測到該 CPU 的靜止狀態,例如,由於 CONFIG_PREEMPT=n 核心中的 cond_resched() 呼叫。 一旦報告了此 CPU 的靜止狀態,將停用該時鐘。

當然,在經過仔細調整的系統中,可能永遠不會發生中斷或異常。 在這種情況下,RCU 寬限期 kthread 最終會導致發生中斷或異常。 但是,在控制不太嚴格的環境中,此函式允許 RCU 在不建立其他無用中斷的情況下獲得所需內容。

notrace bool rcu_is_watching(void)

是否允許在當前 CPU 上使用 RCU 讀取端臨界區?

引數

void

無引數

描述

如果 RCU 正在監視正在執行的 CPU,則返回 true,否則返回 falsetrue 返回值表示此 CPU 可以安全地進入 RCU 讀取端臨界區。

儘管從核心的大多數部分呼叫 rcu_is_watching() 將返回 true,但也有重要的例外情況。 例如,如果當前 CPU 位於其空閒迴圈的深處、在核心進入/退出程式碼中或處於離線狀態,則 rcu_is_watching() 將返回 false

使 notrace,因為它可能被 ftrace 的內部函式呼叫,並且使此 notrace 可以消除不必要的遞迴呼叫。

void rcu_set_gpwrap_lag(unsigned long lag_gps)

設定 RCU GP 序列溢位滯後值。

引數

unsigned long lag_gps

將溢位滯後設定為此多個寬限期的計數器值,rcutorture 使用該值快速強制 gpwrap 情況。 lag_gps = 0 表示我們將其重置回啟動時間值。

void call_rcu_hurry(struct rcu_head *head, rcu_callback_t func)

將 RCU 回撥排隊,以便在寬限期後呼叫,並在這樣做時將所有延遲迴調(包括新的回撥)重新整理到主 ->cblist。

引數

struct rcu_head *head

用於對 RCU 更新進行排隊的結構。

rcu_callback_t func

在寬限期後呼叫的實際回撥函式

描述

回撥函式將在完整的寬限期結束後的一段時間呼叫,換句話說,在所有預先存在的 RCU 讀取端臨界區都已完成之後。

如果你不希望回撥函式被延遲很長時間才執行(這種情況可能發生在記憶體壓力不大、負載較輕或基本空閒的系統上),請使用此 API 而不是 call_rcu()。此函式會以犧牲額外功耗為代價,使回撥函式儘快被呼叫。除此之外,此函式與 call_rcu() 完全相同,並且重用 call_rcu() 的邏輯。有關記憶體排序和其他功能的更多詳細資訊,請參閱 call_rcu()

void call_rcu(struct rcu_head *head, rcu_callback_t func)

將 RCU 回撥函式排隊,以便在寬限期結束後呼叫。預設情況下,回撥是“懶惰的”,並且對主 ->cblist 保持隱藏,以防止過早啟動寬限期。如果您希望寬限期儘快開始,請使用 call_rcu_hurry()

引數

struct rcu_head *head

用於對 RCU 更新進行排隊的結構。

rcu_callback_t func

在寬限期後呼叫的實際回撥函式

描述

回撥函式將在完整的寬限期結束後的一段時間被呼叫,換句話說,在所有先前存在的 RCU 讀取端臨界區都已完成後。但是,回撥函式很可能與在呼叫 call_rcu() 後啟動的 RCU 讀取端臨界區併發執行。

從回撥函式內部重新發布 RCU 回撥,可能會使用不同的回撥函式,這是完全合法的。指定的函式將在另一個完整的寬限期結束後被呼叫。此用例在形式上類似於從其自身處理程式中重新發布計時器的常見做法。

RCU 讀取端臨界區由 rcu_read_lock()rcu_read_unlock() 分隔,並且可以巢狀。此外,但僅在 v5.0 及更高版本中,停用中斷、搶佔或軟中斷的程式碼區域也充當 RCU 讀取端臨界區。這包括硬體中斷處理程式、軟中斷處理程式和 NMI 處理程式。

請注意,所有 CPU 必須同意寬限期已擴充套件到所有先前存在的 RCU 讀取端臨界區之外。在具有多個 CPU 的系統上,這意味著當呼叫“func()”時,保證每個 CPU 自其最後一個 RCU 讀取端臨界區結束以來都已執行完整的記憶體屏障,該 RCU 讀取端臨界區的開始先於呼叫 call_rcu()。這也意味著每個執行 RCU 讀取端臨界區的 CPU,該臨界區繼續超出“func()”的開始,必須在 call_rcu() 之後但在該 RCU 讀取端臨界區的開始之前執行記憶體屏障。請注意,這些保證包括離線、空閒或以使用者模式執行的 CPU,以及在核心中執行的 CPU。

此外,如果 CPU A 呼叫了 call_rcu(),並且 CPU B 呼叫了 resulting RCU 回撥函式“func()”,則保證 CPU A 和 CPU B 在呼叫 call_rcu() 和呼叫“func()”之間的時間間隔內執行完整的記憶體屏障——即使 CPU A 和 CPU B 是同一個 CPU(但同樣只有在系統有多個 CPU 的情況下)。

此處描述了這些記憶體排序保證的實現:TREE_RCU 的寬限期記憶體排序之旅

特別是對於 call_rcu()(與其他 call_rcu*() 函式相反),在以 CONFIG_RCU_LAZY=y 構建的核心中,call_rcu() 可能會延遲數秒,然後才開始對應回撥所需的寬限期。這種延遲可以顯著提高低利用率電池供電裝置的能效。為了避免這種延遲,在對延遲敏感的核心程式碼中,請使用 call_rcu_hurry()

void synchronize_rcu(void)

等待寬限期結束。

引數

void

無引數

描述

在完整的寬限期結束後的一段時間,控制權將返回給呼叫者,換句話說,在所有當前執行的 RCU 讀取端臨界區都已完成後。但是,請注意,從 synchronize_rcu() 返回後,呼叫者很可能與在 synchronize_rcu() 等待時開始的新的 RCU 讀取端臨界區併發執行。

RCU 讀取端臨界區由 rcu_read_lock()rcu_read_unlock() 分隔,並且可以巢狀。此外,但僅在 v5.0 及更高版本中,停用中斷、搶佔或軟中斷的程式碼區域也充當 RCU 讀取端臨界區。這包括硬體中斷處理程式、軟中斷處理程式和 NMI 處理程式。

請注意,此保證意味著進一步的記憶體排序保證。在具有多個 CPU 的系統上,當 synchronize_rcu() 返回時,保證每個 CPU 自其最後一個 RCU 讀取端臨界區結束以來都已執行完整的記憶體屏障,該 RCU 讀取端臨界區的開始先於呼叫 synchronize_rcu()。此外,每個具有 RCU 讀取端臨界區的 CPU,該臨界區超出 synchronize_rcu() 的返回,保證在 synchronize_rcu() 的開始之後和該 RCU 讀取端臨界區的開始之前執行完整的記憶體屏障。請注意,這些保證包括離線、空閒或以使用者模式執行的 CPU,以及在核心中執行的 CPU。

此外,如果 CPU A 呼叫了 synchronize_rcu(),它在 CPU B 上返回到其呼叫者,則保證 CPU A 和 CPU B 在執行 synchronize_rcu() 期間執行完整的記憶體屏障——即使 CPU A 和 CPU B 是同一個 CPU(但同樣只有在系統有多個 CPU 的情況下)。

此處描述了這些記憶體排序保證的實現:TREE_RCU 的寬限期記憶體排序之旅

void get_completed_synchronize_rcu_full(struct rcu_gp_oldstate *rgosp)

返回一個完全預先完成的輪詢狀態 Cookie

引數

struct rcu_gp_oldstate *rgosp

放置狀態 Cookie 的位置

描述

將一個值儲存到 rgosp 中,該值將始終被諸如 poll_state_synchronize_rcu_full() 之類的函式視為寬限期已完成的 Cookie。

unsigned long get_state_synchronize_rcu(void)

快照當前 RCU 狀態

引數

void

無引數

描述

返回一個 Cookie,該 Cookie 由後續對 cond_synchronize_rcu()poll_state_synchronize_rcu() 的呼叫使用,以確定在此期間是否經過了完整的寬限期。

void get_state_synchronize_rcu_full(struct rcu_gp_oldstate *rgosp)

快照 RCU 狀態,包括正常和加速

引數

struct rcu_gp_oldstate *rgosp

放置組合的正常/加速寬限期狀態的位置

描述

將正常和加速的寬限期狀態放置在 rgosp 中。可以將此狀態值傳遞給後續對 cond_synchronize_rcu_full()poll_state_synchronize_rcu_full() 的呼叫,以確定在此期間是否經過寬限期(無論是正常還是加速)。rcu_gp_oldstate 結構佔用的記憶體是 unsigned long 的兩倍,但保證可以看到所有寬限期。相比之下,組合狀態佔用的記憶體較少,但有時無法考慮寬限期。

這不能保證所需的寬限期實際開始。

unsigned long start_poll_synchronize_rcu(void)

快照並啟動 RCU 寬限期

引數

void

無引數

描述

返回一個 Cookie,該 Cookie 由後續對 cond_synchronize_rcu()poll_state_synchronize_rcu() 的呼叫使用,以確定在此期間是否經過了完整的寬限期。如果所需的寬限期尚未計劃開始,則通知 RCU 核心需要該寬限期。

void start_poll_synchronize_rcu_full(struct rcu_gp_oldstate *rgosp)

獲取完整快照並啟動 RCU 寬限期

引數

struct rcu_gp_oldstate *rgosp

來自 get_state_synchronize_rcu_full()start_poll_synchronize_rcu_full() 的值

描述

將正常和加速的寬限期狀態放置在 *rgos 中。可以將此狀態值傳遞給後續對 cond_synchronize_rcu_full()poll_state_synchronize_rcu_full() 的呼叫,以確定在此期間是否經過寬限期(無論是正常還是加速)。如果所需的寬限期尚未計劃開始,則通知 RCU 核心需要該寬限期。

bool poll_state_synchronize_rcu(unsigned long oldstate)

指定的 RCU 寬限期是否已完成?

引數

unsigned long oldstate

來自 get_state_synchronize_rcu()start_poll_synchronize_rcu() 的值

描述

如果自獲得 oldstate 的先前呼叫以來,已經過了完整的 RCU 寬限期,則返回 true,否則返回 false。如果返回 false,則呼叫者有責任稍後呼叫此函式,直到它返回 true。或者,呼叫者可以顯式等待寬限期,例如,透過將 oldstate 傳遞給 cond_synchronize_rcu()cond_synchronize_rcu_expedited(),或者透過直接呼叫 synchronize_rcu()synchronize_rcu_expedited()

是的,此函式不考慮計數器迴繞。但是計數器迴繞是無害的。如果計數器迴繞,我們已經等待超過 10 億個寬限期(在 64 位系統上更多!)。那些需要將舊狀態值保持很長時間(即使在 32 位系統上也是幾個小時)的人員應該偶爾檢查它們,並重新整理它們或設定一個標誌,指示寬限期已完成。或者,他們可以使用 get_completed_synchronize_rcu() 來獲得保證完成的寬限期狀態。

此外,由於 oldstate 將正常和加速寬限期的寬限期狀態壓縮為單個 unsigned long,因此當 synchronize_rcu()synchronize_rcu_expedited() 併發執行時,它可能會錯過寬限期。如果這是不可接受的,請改為使用這些輪詢 API 的 _full() 變體。

此函式提供與在提供 oldstate 的函式呼叫時呼叫並在該函式結束時返回的 synchronize_rcu() 提供的相同的記憶體排序保證。

bool poll_state_synchronize_rcu_full(struct rcu_gp_oldstate *rgosp)

指定的 RCU 寬限期是否已完成?

引數

struct rcu_gp_oldstate *rgosp

來自 get_state_synchronize_rcu_full()start_poll_synchronize_rcu_full() 的值

描述

如果自獲得 rgosp 的先前呼叫以來,已經過了完整的 RCU 寬限期,則返回 **true*,否則返回 false。如果返回 false,則呼叫者有責任稍後呼叫此函式,直到它返回 true。或者,呼叫者可以顯式等待寬限期,例如,透過將 rgosp 傳遞給 cond_synchronize_rcu() 或透過直接呼叫 synchronize_rcu()

是的,此函式不考慮計數器迴繞。但是計數器迴繞是無害的。如果計數器迴繞,我們已經等待超過 10 億個寬限期(在 64 位系統上更多!)。那些需要將 rcu_gp_oldstate 值保持很長時間(即使在 32 位系統上也是幾個小時)的人員應該偶爾檢查它們,並重新整理它們或設定一個標誌,指示寬限期已完成。或者,他們可以使用 get_completed_synchronize_rcu_full() 來獲得保證完成的寬限期狀態。

此函式提供與在提供 rgosp 的函式呼叫時呼叫並在該函式結束時返回的 synchronize_rcu() 提供的相同的記憶體排序保證。並且此保證要求檢查根 rcu_node 結構的 ->gp_seq 欄位,而不是 rcu_state 結構的欄位。問題在於,剛剛結束的寬限期的回撥可以在更新根 rcu_node 結構的 ->gp_seq 欄位的時間與更新 rcu_state 結構的 ->gp_seq 欄位的時間之間被呼叫。因此,如果要使單個 synchronize_rcu() 導致後續的 poll_state_synchronize_rcu_full() 返回 true,則需要輪詢根 rcu_node 結構。

void cond_synchronize_rcu(unsigned long oldstate)

有條件地等待 RCU 寬限期

引數

unsigned long oldstate

來自 get_state_synchronize_rcu()start_poll_synchronize_rcu()start_poll_synchronize_rcu_expedited() 的值

描述

如果自先前呼叫 get_state_synchronize_rcu()start_poll_synchronize_rcu() 以來,已經過了完整的 RCU 寬限期,則直接返回。否則,呼叫 synchronize_rcu() 以等待完整的寬限期。

是的,此函式不考慮計數器迴繞。但是計數器迴繞是無害的。如果計數器迴繞,我們已經等待超過 20 億個寬限期(在 64 位系統上更多!),因此等待幾個額外的寬限期應該沒有問題。

此函式提供與在提供 oldstate 的函式呼叫時呼叫並在該函式結束時返回的 synchronize_rcu() 提供的相同的記憶體排序保證。

void cond_synchronize_rcu_full(struct rcu_gp_oldstate *rgosp)

有條件地等待 RCU 寬限期

引數

struct rcu_gp_oldstate *rgosp

來自 get_state_synchronize_rcu_full()start_poll_synchronize_rcu_full()start_poll_synchronize_rcu_expedited_full() 的值

描述

如果自呼叫 get_state_synchronize_rcu_full()start_poll_synchronize_rcu_full()start_poll_synchronize_rcu_expedited_full()(從中獲取了 rgosp)以來,已經過了一個完整的 RCU 寬限期,則直接返回。否則,呼叫 synchronize_rcu() 等待一個完整的寬限期。

是的,此函式不考慮計數器迴繞。但是計數器迴繞是無害的。如果計數器迴繞,我們已經等待超過 20 億個寬限期(在 64 位系統上更多!),因此等待幾個額外的寬限期應該沒有問題。

此函式提供的記憶體排序保證與呼叫提供 rgosp 的函式時呼叫,並在該函式結束時返回的 synchronize_rcu() 所提供的記憶體排序保證相同。

void rcu_barrier(void)

等待所有正在進行的 call_rcu() 回撥完成。

引數

void

無引數

描述

請注意,此原語不一定等待 RCU 寬限期完成。例如,如果系統中任何地方都沒有排隊的 RCU 回撥,則 rcu_barrier() 有權立即返回,無需等待任何事情,更不用說 RCU 寬限期了。

void rcu_barrier_throttled(void)

執行 rcu_barrier(),但限制為每秒一次

引數

void

無引數

描述

這可以被認為是 rcu_barrier() 周圍的防護欄,允許不受限制的使用者空間使用,至少假設硬體的 try_cmpxchg() 是健壯的。使用此函式,系統範圍內每秒最多呼叫一次 rcu_barrier(),這意味著呼叫者可能會不必要地等待一到三秒。

這旨在供測試套件使用,以避免 OOM,透過在啟動下一個測試之前重新整理先前測試中的 RCU 回撥。有關更多資訊,請參見 rcutree.do_rcu_barrier 模組引數。

為什麼不簡單地使 rcu_barrier() 更具可伸縮性?這可能是最終的端點,但暫時讓我們保持簡單。請注意,模組引數基礎結構序列化對給定 .set() 函式的呼叫,但是如果可能同時呼叫 .set(),我們已經準備好了!

void synchronize_rcu_expedited(void)

暴力 RCU 寬限期

引數

void

無引數

描述

等待 RCU 寬限期,但加快它。基本思想是 IPI 所有非空閒、非nohz 的線上 CPU。IPI 處理程式檢查 CPU 是否處於 RCU 臨界區,如果是,則設定一個標誌,該標誌導致最外層的 rcu_read_unlock() 報告 RCU-preempt 的靜止狀態,或要求排程程式為 RCU-sched 提供幫助。另一方面,如果 CPU 不在 RCU 讀取側臨界區中,則 IPI 處理程式會立即報告靜止狀態。

儘管與以前的加速實現相比,這是一個很大的改進,但它對即時工作負載仍然不友好,因此不建議用於任何型別的常見情況程式碼。實際上,如果您在迴圈中使用 synchronize_rcu_expedited(),請重構您的程式碼以批次更新,然後改用單個 synchronize_rcu()

這具有與 synchronize_rcu() 相同的語義(但比它更殘酷)。

unsigned long start_poll_synchronize_rcu_expedited(void)

快照當前 RCU 狀態並啟動加速寬限期

引數

void

無引數

描述

返回一個 cookie,傳遞給對 cond_synchronize_rcu()cond_synchronize_rcu_expedited()poll_state_synchronize_rcu() 的呼叫,允許它們確定是否在此期間已經過任何型別的寬限期。如果所需的加速寬限期尚未計劃啟動,則啟動該寬限期。

void start_poll_synchronize_rcu_expedited_full(struct rcu_gp_oldstate *rgosp)

獲取完整快照並啟動加速寬限期

引數

struct rcu_gp_oldstate *rgosp

放置寬限期狀態快照的位置

描述

將正常和加速寬限期狀態放置在 rgosp 中。此狀態值可以傳遞給稍後對 cond_synchronize_rcu_full()poll_state_synchronize_rcu_full() 的呼叫,以確定在此期間是否已經過寬限期(無論是正常寬限期還是加速寬限期)。如果所需的加速寬限期尚未計劃啟動,則啟動該寬限期。

void cond_synchronize_rcu_expedited(unsigned long oldstate)

有條件地等待加速的 RCU 寬限期

引數

unsigned long oldstate

來自 get_state_synchronize_rcu()start_poll_synchronize_rcu()start_poll_synchronize_rcu_expedited() 的值

描述

如果自先前呼叫 get_state_synchronize_rcu()start_poll_synchronize_rcu()start_poll_synchronize_rcu_expedited() 以來,已經過任何型別的完整 RCU 寬限期,則直接返回。否則,呼叫 synchronize_rcu_expedited() 等待一個完整的寬限期。

是的,此函式不考慮計數器迴繞。但是計數器迴繞是無害的。如果計數器迴繞,我們已經等待超過 20 億個寬限期(在 64 位系統上更多!),因此等待幾個額外的寬限期應該沒有問題。

此函式提供與在提供 oldstate 的函式呼叫時呼叫並在該函式結束時返回的 synchronize_rcu() 提供的相同的記憶體排序保證。

void cond_synchronize_rcu_expedited_full(struct rcu_gp_oldstate *rgosp)

有條件地等待加速的 RCU 寬限期

引數

struct rcu_gp_oldstate *rgosp

來自 get_state_synchronize_rcu_full()start_poll_synchronize_rcu_full()start_poll_synchronize_rcu_expedited_full() 的值

描述

如果自呼叫 get_state_synchronize_rcu_full()start_poll_synchronize_rcu_full()start_poll_synchronize_rcu_expedited_full()(從中獲取了 rgosp)以來,已經過了一個完整的 RCU 寬限期,則直接返回。否則,呼叫 synchronize_rcu_expedited() 等待一個完整的寬限期。

是的,此函式不考慮計數器迴繞。但是計數器迴繞是無害的。如果計數器迴繞,我們已經等待超過 20 億個寬限期(在 64 位系統上更多!),因此等待幾個額外的寬限期應該沒有問題。

此函式提供的記憶體排序保證與呼叫提供 rgosp 的函式時呼叫,並在該函式結束時返回的 synchronize_rcu() 所提供的記憶體排序保證相同。

bool rcu_read_lock_held_common(bool *ret)

我們是否可能位於 RCU-sched 讀取側臨界區?

引數

bool *ret

如果無法依賴 lockdep,則提供最佳猜測答案

描述

如果必須忽略 lockdep,則返回 true,在這種情況下,*ret 包含下面描述的最佳猜測。否則返回 false,在這種情況下,*ret 不告訴呼叫者任何內容,呼叫者應改為查閱 lockdep。

如果選擇了 CONFIG_DEBUG_LOCK_ALLOC,則當且僅當在 RCU-sched 讀取側臨界區中時,才將 *ret 設定為非零值。在沒有 CONFIG_DEBUG_LOCK_ALLOC 的情況下,這假定我們位於 RCU-sched 讀取側臨界區中,除非可以證明情況並非如此。請注意,停用搶佔(包括停用 irq)算作 RCU-sched 讀取側臨界區。這對於需要從 RCU-sched 讀取側臨界區中呼叫的函式中的除錯檢查很有用。

檢查 debug_lockdep_rcu_enabled() 以防止在啟動期間和停用 lockdep 時出現誤報。

請注意,如果 CPU 從 RCU 的角度來看處於空閒迴圈中(即:我們位於 ct_idle_enter() 和 ct_idle_exit() 之間的部分中),則即使 CPU 執行了 rcu_read_lock()rcu_read_lock_held() 也會將 *ret 設定為 false。這樣做的原因是 RCU 忽略處於此類部分的 CPU,將其視為處於擴充套件靜止狀態,因此無論 RCU 呼叫哪些原語,此類 CPU 實際上永遠不會處於 RCU 讀取側臨界區中。這種情況是必需的 --- 我們需要在空閒狀態下保持一個無 RCU 的視窗,CPU 可能會進入低功耗模式。這樣,我們可以注意到啟動寬限期的其他 CPU 的擴充套件靜止狀態。否則,只要我們在空閒任務中執行,就會延遲任何寬限期。

類似地,如果當前 CPU 處於離線狀態,我們將避免宣告持有 RCU 讀取鎖。

void rcu_async_hurry(void)

使未來的非同步 RCU 回撥不會延遲。

引數

void

無引數

描述

在呼叫此函式後,將及時處理對 call_rcu() 的未來呼叫。

void rcu_async_relax(void)

使未來的非同步 RCU 回撥延遲。

引數

void

無引數

描述

在呼叫此函式後,將以延遲方式處理對 call_rcu() 的未來呼叫。

void rcu_expedite_gp(void)

加速未來的 RCU 寬限期

引數

void

無引數

描述

在呼叫此函式後,對 synchronize_rcu() 及其相關函式的未來呼叫將像呼叫了相應的 synchronize_rcu_expedited() 函式一樣。

void rcu_unexpedite_gp(void)

取消先前的 rcu_expedite_gp() 呼叫

引數

void

無引數

描述

撤消先前對 rcu_expedite_gp() 的呼叫。如果通過後續呼叫 rcu_unexpedite_gp() 撤消了所有先前對 rcu_expedite_gp() 的呼叫,並且未設定 rcu_expedited sysfs/boot 引數,則對 synchronize_rcu() 及其相關函式的所有後續呼叫將恢復為正常的非加速行為。

int rcu_read_lock_held(void)

我們是否可能位於 RCU 讀取側臨界區?

引數

void

無引數

描述

如果選擇了 CONFIG_DEBUG_LOCK_ALLOC,則當且僅當在 RCU 讀取側臨界區中時,才返回非零值。在沒有 CONFIG_DEBUG_LOCK_ALLOC 的情況下,這假定我們位於 RCU 讀取側臨界區中,除非可以證明情況並非如此。這對於需要從 RCU 讀取側臨界區中呼叫的函式中的除錯檢查很有用。

檢查 debug_lockdep_rcu_enabled() 以防止在啟動期間和停用 lockdep 時出現誤報。

請注意,rcu_read_lock() 和匹配的 rcu_read_unlock() 必須發生在同一上下文中,例如,如果在 irq 處理程式中呼叫了匹配的 rcu_read_lock(),則在程序上下文中呼叫 rcu_read_unlock() 是非法的。

請注意,如果 CPU 從 RCU 的角度來看是空閒的或離線的,則不允許使用 rcu_read_lock(),因此也要檢查這些情況。

int rcu_read_lock_bh_held(void)

我們是否可能位於 RCU-bh 讀取側臨界區?

引數

void

無引數

描述

檢查是否停用了 bottom half,這涵蓋了 CONFIG_PROVE_RCU 和非 CONFIG_PROVE_RCU 的情況。請注意,如果有人使用 rcu_read_lock_bh(),但稍後啟用了 BH,則 lockdep(如果啟用)將顯示該情況。這對於需要從 RCU 讀取側臨界區中呼叫的函式中的除錯檢查很有用。

檢查 debug_lockdep_rcu_enabled() 以防止在啟動期間出現誤報。

請注意,如果 CPU 從 RCU 的角度來看是空閒的或離線的,則不允許使用 rcu_read_lock_bh(),因此也要檢查這些情況。

void wakeme_after_rcu(struct rcu_head *head)

寬限期後喚醒任務的回撥函式

引數

struct rcu_head *head

指向 rcu_synchronize 結構中的 rcu_head 成員的指標

描述

現在寬限期已過,喚醒相應的任務。

void init_rcu_head_on_stack(struct rcu_head *head)

初始化用於 debugobjects 的堆疊上的 rcu_head

引數

struct rcu_head *head

指向要初始化的 rcu_head 結構的指標

描述

此函式通知 debugobjects 已分配一個新的 rcu_head 結構作為堆疊上的自動變數。對於靜態定義或在堆上動態分配的 rcu_head 結構,不需要此函式。對於 !CONFIG_DEBUG_OBJECTS_RCU_HEAD 核心構建,此函式無效。

void destroy_rcu_head_on_stack(struct rcu_head *head)

銷燬用於 debugobjects 的堆疊上的 rcu_head

引數

struct rcu_head *head

指向要初始化的 rcu_head 結構的指標

描述

此函式通知 debugobjects 堆疊上的 rcu_head 結構即將超出範圍。與 init_rcu_head_on_stack() 一樣,對於靜態定義或在堆上動態分配的 rcu_head 結構,不需要此函式。此外,與 init_rcu_head_on_stack() 一樣,對於 !CONFIG_DEBUG_OBJECTS_RCU_HEAD 核心構建,此函式無效。

unsigned long get_completed_synchronize_rcu(void)

返回預完成的輪詢狀態 cookie

引數

void

無引數

描述

返回一個值,該值將始終被 poll_state_synchronize_rcu() 等函式視為寬限期已完成的 cookie。

unsigned long get_completed_synchronize_srcu(void)

返回預完成的輪詢狀態 cookie

引數

void

無引數

描述

返回一個值,poll_state_synchronize_srcu() 將始終將其視為寬限期已完成的 cookie。

bool same_state_synchronize_srcu(unsigned long oldstate1, unsigned long oldstate2)

兩個舊狀態值是否相同?

引數

unsigned long oldstate1

第一個舊狀態值。

unsigned long oldstate2

第二個舊狀態值。

描述

這兩個舊狀態值必須從 get_state_synchronize_srcu()start_poll_synchronize_srcu()get_completed_synchronize_srcu() 中獲得。如果兩個值相同,則返回 true,否則返回 false。這允許其生命週期由舊狀態值跟蹤的結構將這些值推送到列表頭,從而使這些結構稍微小一些。

int srcu_read_lock_held(const struct srcu_struct *ssp)

我們可能在 SRCU 讀取端臨界區嗎?

引數

const struct srcu_struct *ssp

要檢查的 srcu_struct 結構

描述

如果選擇了 CONFIG_DEBUG_LOCK_ALLOC,則當且僅當在 SRCU 讀取端臨界區中時才返回非零值。在沒有 CONFIG_DEBUG_LOCK_ALLOC 的情況下,這假定我們在 SRCU 讀取端臨界區中,除非它可以證明相反的情況。

檢查 debug_lockdep_rcu_enabled() 以防止在啟動期間和停用 lockdep 時出現誤報。

請注意,SRCU 基於其自己的狀態機,並且不依賴於普通的 RCU,它可以從 CPU 呼叫,該 CPU 從 RCU 的角度來看處於空閒迴圈或離線狀態。

srcu_dereference_check

srcu_dereference_check (p, ssp, c)

獲取 SRCU 保護的指標以供以後解引用

引數

p

要獲取並保護以供以後解引用的指標

ssp

指向 srcu_struct 的指標,用於檢查我們是否真的在 SRCU 讀取端臨界區中。

c

要檢查的更新端使用的條件

描述

如果啟用了 PROVE_RCU,則在 RCU 讀取端臨界區之外呼叫此函式將導致 RCU 鎖依賴錯誤,除非 c 的計算結果為 1。 c 引數通常是一個包含 lockdep_is_held() 呼叫的邏輯表示式。

srcu_dereference

srcu_dereference (p, ssp)

獲取 SRCU 保護的指標以供以後解引用

引數

p

要獲取並保護以供以後解引用的指標

ssp

指向 srcu_struct 的指標,用於檢查我們是否真的在 SRCU 讀取端臨界區中。

描述

使 rcu_dereference_check() 完成繁重的工作。如果啟用了 PROVE_RCU,則在 RCU 讀取端臨界區之外呼叫此函式將導致 RCU 鎖依賴錯誤。

srcu_dereference_notrace

srcu_dereference_notrace (p, ssp)

此處沒有跟蹤,也沒有鎖依賴呼叫

引數

p

要獲取並保護以供以後解引用的指標

ssp

指向 srcu_struct 的指標,用於檢查我們是否真的在 SRCU 讀取端臨界區中。

int srcu_read_lock(struct srcu_struct *ssp)

為受 SRCU 保護的結構註冊一個新的讀取器。

引數

struct srcu_struct *ssp

要在其中註冊新讀取器的 srcu_struct。

描述

進入 SRCU 讀取端臨界區。請注意,SRCU 讀取端臨界區可以巢狀。但是,呼叫任何等待同一 srcu_struct 的 SRCU 寬限期的操作(無論是直接還是間接)都是非法的。請注意,間接等待 SRCU 寬限期的一種方法是在呼叫 synchronize_srcu()synchronize_srcu_expedited() 時,獲取其他地方持有的互斥鎖。

srcu_read_lock() 的返回值保證為非負數。此值必須原封不動地傳遞給匹配的 srcu_read_unlock()。請注意,srcu_read_lock() 和匹配的 srcu_read_unlock() 必須在同一上下文中發生,例如,如果在程序上下文中呼叫了匹配的 srcu_read_lock(),則在 irq 處理程式中呼叫 srcu_read_unlock() 是非法的。或者,從一個任務呼叫 srcu_read_unlock(),從另一個任務呼叫匹配的 srcu_read_lock() 也是非法的。

struct srcu_ctr __percpu *srcu_read_lock_fast(struct srcu_struct *ssp)

為受 SRCU 保護的結構註冊一個新的讀取器。

引數

struct srcu_struct *ssp

要在其中註冊新讀取器的 srcu_struct。

描述

進入 SRCU 讀取端臨界區,但適用於輕量級的無 smp_mb() 讀取器。有關更多資訊,請參見 srcu_read_lock()

如果在 srcu_struct 結構上使用了 srcu_read_lock_fast(),則無論之前、期間還是之後,都不能使用其他任何風格。請注意,對於 _fast srcu_struct 結構,寬限期自動加速已停用,因為自動加速的寬限期會呼叫 synchronize_rcu_expedited()、IPI 以及所有內容。

請注意,只能從 RCU 正在監視的上下文中呼叫 srcu_read_lock_fast(),也就是說,從呼叫 rcu_read_lock() 合法的上下文中。否則,lockdep 將會報錯。

struct srcu_ctr __percpu *srcu_down_read_fast(struct srcu_struct *ssp)

為受 SRCU 保護的結構註冊一個新的讀取器。

引數

struct srcu_struct *ssp

要在其中註冊新讀取器的 srcu_struct。

描述

進入類似訊號量的 SRCU 讀取端臨界區,但適用於輕量級的無 smp_mb() 讀取器。有關更多資訊,請參見 srcu_read_lock_fast()srcu_down_read()

srcu_down_read_fast()srcu_read_lock_fast() 可以併發使用相同的 srcu_struct。

int srcu_read_lock_lite(struct srcu_struct *ssp)

為受 SRCU 保護的結構註冊一個新的讀取器。

引數

struct srcu_struct *ssp

要在其中註冊新讀取器的 srcu_struct。

描述

進入 SRCU 讀取端臨界區,但適用於輕量級的無 smp_mb() 讀取器。有關更多資訊,請參見 srcu_read_lock()

如果在 srcu_struct 結構上使用了 srcu_read_lock_lite(),則無論之前、期間還是之後,都不能使用其他任何風格。請注意,對於 _lite srcu_struct 結構,寬限期自動加速已停用,因為自動加速的寬限期會呼叫 synchronize_rcu_expedited()、IPI 以及所有內容。

請注意,只能從 RCU 正在監視的上下文中呼叫 srcu_read_lock_lite(),也就是說,從呼叫 rcu_read_lock() 合法的上下文中。否則,lockdep 將會報錯。

int srcu_read_lock_nmisafe(struct srcu_struct *ssp)

為受 SRCU 保護的結構註冊一個新的讀取器。

引數

struct srcu_struct *ssp

要在其中註冊新讀取器的 srcu_struct。

描述

進入 SRCU 讀取端臨界區,但以 NMI 安全的方式進行。有關更多資訊,請參見 srcu_read_lock()

如果在 srcu_struct 結構上使用了 srcu_read_lock_nmisafe(),則無論之前、期間還是之後,都不能使用其他任何風格。

int srcu_down_read(struct srcu_struct *ssp)

為受 SRCU 保護的結構註冊一個新的讀取器。

引數

struct srcu_struct *ssp

要在其中註冊新讀取器的 srcu_struct。

描述

進入類似訊號量的 SRCU 讀取端臨界區。請注意,SRCU 讀取端臨界區可以巢狀。但是,呼叫任何等待同一 srcu_struct 的 SRCU 寬限期的操作(無論是直接還是間接)都是非法的。請注意,間接等待 SRCU 寬限期的一種方法是在呼叫 synchronize_srcu()synchronize_srcu_expedited() 時,獲取其他地方持有的互斥鎖。但是,如果您希望 lockdep 幫助您理清這些內容,則應改用 srcu_read_lock()

srcu_down_read() 的類似訊號量的性質意味著可以從其他一些上下文(例如,從其他一些任務或從 irq 處理程式)呼叫匹配的 srcu_up_read()。但是,既不能從 NMI 處理程式呼叫 srcu_down_read(),也不能從 NMI 處理程式呼叫 srcu_up_read()

srcu_down_read() 的呼叫可以巢狀,類似於對 down_read() 的呼叫可以巢狀的方式。srcu_down_read()srcu_read_lock() 可以併發使用相同的 srcu_struct。

void srcu_read_unlock(struct srcu_struct *ssp, int idx)

從受 SRCU 保護的結構中登出舊的讀取器。

引數

struct srcu_struct *ssp

要在其中登出舊的讀取器的 srcu_struct。

int idx

來自相應 srcu_read_lock() 的返回值。

描述

退出 SRCU 讀取端臨界區。

void srcu_read_unlock_fast(struct srcu_struct *ssp, struct srcu_ctr __percpu *scp)

從受 SRCU 保護的結構中登出舊的讀取器。

引數

struct srcu_struct *ssp

要在其中登出舊的讀取器的 srcu_struct。

struct srcu_ctr __percpu *scp

來自相應 srcu_read_lock_fast() 的返回值。

描述

退出輕量級 SRCU 讀取端臨界區。

void srcu_up_read_fast(struct srcu_struct *ssp, struct srcu_ctr __percpu *scp)

從受 SRCU 保護的結構中登出舊的讀取器。

引數

struct srcu_struct *ssp

要在其中登出舊的讀取器的 srcu_struct。

struct srcu_ctr __percpu *scp

來自相應 srcu_read_lock_fast() 的返回值。

描述

退出 SRCU 讀取端臨界區,但不一定與匹配的 srcu_down_read_fast() 位於同一上下文中。

void srcu_read_unlock_lite(struct srcu_struct *ssp, int idx)

從受 SRCU 保護的結構中登出舊的讀取器。

引數

struct srcu_struct *ssp

要在其中登出舊的讀取器的 srcu_struct。

int idx

來自相應 srcu_read_lock_lite() 的返回值。

描述

退出輕量級 SRCU 讀取端臨界區。

void srcu_read_unlock_nmisafe(struct srcu_struct *ssp, int idx)

從受 SRCU 保護的結構中登出舊的讀取器。

引數

struct srcu_struct *ssp

要在其中登出舊的讀取器的 srcu_struct。

int idx

來自相應 srcu_read_lock_nmisafe() 的返回值。

描述

退出 SRCU 讀取端臨界區,但以 NMI 安全的方式進行。

void srcu_up_read(struct srcu_struct *ssp, int idx)

從受 SRCU 保護的結構中登出舊的讀取器。

引數

struct srcu_struct *ssp

要在其中登出舊的讀取器的 srcu_struct。

int idx

來自相應 srcu_read_lock() 的返回值。

描述

退出 SRCU 讀取側臨界區,但不一定與匹配的 srcu_down_read() 在同一上下文中。

void smp_mb__after_srcu_read_unlock(void)

確保在 srcu_read_unlock 之後完全排序

引數

void

無引數

描述

將前面的 srcu_read_unlock 轉換為雙向記憶體屏障。

在 srcu_read_unlock 之後呼叫此函式,以保證在 smp_mb__after_srcu_read_unlock 之後發生的所有記憶體操作都將在前面的 srcu_read_unlock 之後發生。

void smp_mb__after_srcu_read_lock(void)

確保在 srcu_read_lock 之後完全排序

引數

void

無引數

描述

將前面的 srcu_read_lock 轉換為雙向記憶體屏障。

在 srcu_read_lock 之後呼叫此函式,以保證在 smp_mb__after_srcu_read_lock 之後發生的所有記憶體操作都將在前面的 srcu_read_lock 之後發生。

int init_srcu_struct(struct srcu_struct *ssp)

初始化一個睡眠-RCU 結構

引數

struct srcu_struct *ssp

要初始化的結構。

描述

必須在將給定的 srcu_struct 傳遞給任何其他函式之前,在該 srcu_struct 上呼叫此函式。每個 srcu_struct 代表一個單獨的 SRCU 保護域。

bool srcu_readers_active(struct srcu_struct *ssp)

如果存在讀取者,則返回 true。否則返回 false

引數

struct srcu_struct *ssp

要計算活動讀取者(持有 srcu_read_lock)的 srcu_struct。

描述

請注意,這不是一個原子原語,因此在活動 srcu_struct 上呼叫時可能會出現嚴重錯誤。也就是說,它可以在清理時用作錯誤檢查。

void cleanup_srcu_struct(struct srcu_struct *ssp)

解構一個睡眠-RCU 結構

引數

struct srcu_struct *ssp

要清理的結構。

描述

在使用透過 init_srcu_struct() 初始化的給定 srcu_struct 後,必須呼叫此函式,否則會洩漏記憶體。

void call_srcu(struct srcu_struct *ssp, struct rcu_head *rhp, rcu_callback_t func)

在 SRCU 寬限期後排隊一個回撥以進行呼叫

引數

struct srcu_struct *ssp

將回調排隊的 srcu_struct

struct rcu_head *rhp

用於排隊 SRCU 回撥的結構。

rcu_callback_t func

在 SRCU 寬限期結束後要呼叫的函式

描述

回撥函式將在完整的 SRCU 寬限期結束後的一段時間內呼叫,換句話說,在所有預先存在的 SRCU 讀取側臨界區完成後。但是,回撥函式很可能與在呼叫 call_srcu() 之後啟動的其他 SRCU 讀取側臨界區同時執行。SRCU 讀取側臨界區由 srcu_read_lock()srcu_read_unlock() 分隔,並且可能是巢狀的。

回撥將從程序上下文中呼叫,但停用了 bh。因此,回撥函式必須快速且不得阻塞。

有關記憶體排序保證的更多詳細資訊,請參見 call_rcu() 的描述。

void synchronize_srcu_expedited(struct srcu_struct *ssp)

強制 SRCU 寬限期

引數

struct srcu_struct *ssp

要同步的 srcu_struct。

描述

等待 SRCU 寬限期過去,但在等待時更積極地進行旋轉,而不是阻塞。

請注意,synchronize_srcu_expedited() 具有與 synchronize_srcu() 相同的死鎖和記憶體排序屬性。

void synchronize_srcu(struct srcu_struct *ssp)

等待先前的 SRCU 讀取側臨界區完成

引數

struct srcu_struct *ssp

要同步的 srcu_struct。

描述

等待兩個索引的計數都降至零。為了避免 synchronize_srcu() 可能發生的飢餓,它首先等待 index=!(ssp->srcu_ctrp - ssp->sda->srcu_ctrs[0]) 的計數降至零,然後翻轉 ->srcu_ctrp 並等待另一個索引的計數。

可以阻塞;必須從程序上下文中呼叫。

請注意,從相應的 SRCU 讀取側臨界區呼叫 synchronize_srcu() 是非法的;這樣做會導致死鎖。但是,從某個其他 srcu_struct 的讀取側臨界區呼叫一個 srcu_struct 上的 synchronize_srcu() 是完全合法的,只要生成的 srcu_struct 圖是無環的。

synchronize_srcu() 隱含了記憶體排序約束。在具有多個 CPU 的系統上,當 synchronize_srcu() 返回時,保證每個 CPU 都執行了一個完整的記憶體屏障,該記憶體屏障自從其最後一個相應的 SRCU 讀取側臨界區結束以來,該臨界區的開始先於對 synchronize_srcu() 的呼叫。此外,具有 SRCU 讀取側臨界區的每個 CPU,該臨界區超出 synchronize_srcu() 的返回,都保證在 synchronize_srcu() 開始之後和該 SRCU 讀取側臨界區開始之前執行了一個完整的記憶體屏障。請注意,這些保證包括離線、空閒或以使用者模式執行的 CPU,以及在核心中執行的 CPU。

此外,如果 CPU A 呼叫了 synchronize_srcu(),該函式返回給 CPU B 上的呼叫者,則保證 CPU A 和 CPU B 都在 synchronize_srcu() 的執行過程中執行了一個完整的記憶體屏障。即使 CPU A 和 CPU B 是同一個 CPU,此保證也適用,但同樣僅當系統具有多個 CPU 時才適用。

當然,這些記憶體排序保證僅在將相同的 srcu_struct 結構傳遞給 synchronize_srcu()srcu_read_lock()srcu_read_unlock() 時才適用。

這些記憶體排序保證的實現與 synchronize_rcu() 的實現類似。

如果 SRCU 可能處於空閒狀態(由 srcu_should_expedite() 確定),則加速第一個請求。此語義由 Classic SRCU 提供,並被其使用者所依賴,因此 TREE SRCU 也必須提供此語義。請注意,檢測空閒狀態是啟發式的,並且容易出現誤報和漏報。

unsigned long get_state_synchronize_srcu(struct srcu_struct *ssp)

提供一個寬限期結束 Cookie

引數

struct srcu_struct *ssp

要提供 Cookie 的 srcu_struct。

描述

此函式返回一個 Cookie,可以將其傳遞給 poll_state_synchronize_srcu(),如果在此期間經過了完整的寬限期,則該函式將返回 true。呼叫者有責任確保發生寬限期,例如,透過在從 get_state_synchronize_srcu() 返回後呼叫 call_srcu() 來確保。

unsigned long start_poll_synchronize_srcu(struct srcu_struct *ssp)

提供 Cookie 並啟動寬限期

引數

struct srcu_struct *ssp

要提供 Cookie 的 srcu_struct。

描述

此函式返回一個 Cookie,可以將其傳遞給 poll_state_synchronize_srcu(),如果在此期間經過了完整的寬限期,則該函式將返回 true。與 get_state_synchronize_srcu() 不同,此函式還確保啟動任何需要的 SRCU 寬限期。這種便利性確實會帶來 CPU 開銷方面的成本。

bool poll_state_synchronize_srcu(struct srcu_struct *ssp, unsigned long cookie)

Cookie 的寬限期是否已結束?

引數

struct srcu_struct *ssp

要提供 Cookie 的 srcu_struct。

unsigned long cookie

get_state_synchronize_srcu()start_poll_synchronize_srcu() 返回的值。

描述

此函式獲取從 get_state_synchronize_srcu()start_poll_synchronize_srcu() 返回的 Cookie,如果自建立 Cookie 以來已經過 SRCU 寬限期,則返回 true

由於 Cookie 的大小有限,因此可能會發生包裝/溢位。在 32 位系統上,這種現象更為明顯,因為 Cookie 是 32 位的,理論上,假設 25 微秒的加速 SRCU 寬限期,大約 14 小時內可能會發生包裝。但是,在 1 毫秒 SRCU 寬限期的情況下,更可能的溢位下限約為 24 天。當然,在 64 位系統中,包裝需要地質時間跨度,即使對於加速的 SRCU 寬限期,也超過 700 萬年。

對於 CONFIG_SMP=n 系統(也具有 CONFIG_PREEMPTION=n)而言,包裝/溢位問題更為嚴重,該系統選擇 Tiny SRCU。這使用一個 16 位的 Cookie,rcutorture 通常在幾分鐘內包裝該 Cookie。如果這證明是一個問題,則此計數器將擴充套件到與 Tree SRCU 相同的大小。

void srcu_barrier(struct srcu_struct *ssp)

等待所有正在進行的 call_srcu() 回撥完成。

引數

struct srcu_struct *ssp

在其上等待正在進行的回撥的 srcu_struct。

unsigned long srcu_batches_completed(struct srcu_struct *ssp)

返回已完成的批次。

引數

struct srcu_struct *ssp

在其上報告批次完成情況的 srcu_struct。

描述

報告與已經過的寬限期數量相關聯,但不一定完全相同的批次數量。

void hlist_bl_del_rcu(struct hlist_bl_node *n)

從雜湊列表中刪除條目,而無需重新初始化

引數

struct hlist_bl_node *n

要從雜湊列表中刪除的元素。

注意

在此之後,hlist_bl_unhashed() 在條目上不返回 true,該條目處於未定義狀態。它對於基於 RCU 的無鎖遍歷很有用。

描述

特別是,這意味著我們無法破壞可能仍用於遍歷雜湊列表的前向指標。

呼叫者必須採取任何必要的預防措施(例如持有適當的鎖),以避免與在同一列表上執行的另一個列表變異原語(例如 hlist_bl_add_head_rcu()hlist_bl_del_rcu())競爭。但是,與 _rcu 列表遍歷原語(例如 hlist_bl_for_each_entry())併發執行是完全合法的。

void hlist_bl_add_head_rcu(struct hlist_bl_node *n, struct hlist_bl_head *h)

引數

struct hlist_bl_node *n

要新增到雜湊列表的元素。

struct hlist_bl_head *h

要新增到的列表。

描述

將指定的元素新增到指定的 hlist_bl,同時允許競爭遍歷。

呼叫者必須採取任何必要的預防措施(例如持有適當的鎖),以避免與在同一列表上執行的另一個列表變異原語(例如 hlist_bl_add_head_rcu()hlist_bl_del_rcu())競爭。但是,與 _rcu 列表遍歷原語(例如 hlist_bl_for_each_entry_rcu())併發執行是完全合法的,該原語用於防止 Alpha CPU 上的記憶體一致性問題。無論 CPU 的型別如何,列表遍歷原語都必須由 rcu_read_lock() 保護。

hlist_bl_for_each_entry_rcu

hlist_bl_for_each_entry_rcu (tpos, pos, head, member)

迭代給定型別的 rcu 列表

引數

tpos

用作循環遊標的 型別 *。

pos

用作循環遊標的 struct hlist_bl_node

head

連結串列的頭部。

member

結構中的 hlist_bl_node 的名稱。

list_tail_rcu

list_tail_rcu (head)

返回列表頭的 prev 指標

引數

head

列表的頭部

注意

這應該僅與列表頭一起使用,即使這樣,也只有在 list_del() 和類似的基元也沒有用於列表頭時才使用。

void list_add_rcu(struct list_head *new, struct list_head *head)

新增一個新條目到 rcu 保護的連結串列

引數

struct list_head *new

要新增的新條目

struct list_head *head

在其後新增的列表頭

描述

在指定的頭部之後插入一個新條目。 這對於實現堆疊很有用。

呼叫者必須採取必要的預防措施(例如持有適當的鎖),以避免與同一連結串列上執行的其他連結串列修改原語(例如 list_add_rcu()list_del_rcu())發生競爭。但是,與 _rcu 連結串列遍歷原語(例如 list_for_each_entry_rcu())併發執行是完全合法的。

void list_add_tail_rcu(struct list_head *new, struct list_head *head)

新增一個新條目到 rcu 保護的連結串列

引數

struct list_head *new

要新增的新條目

struct list_head *head

在其前新增的列表頭

描述

在指定的頭部之前插入一個新條目。 這對於實現佇列很有用。

呼叫者必須採取必要的預防措施(例如持有適當的鎖),以避免與同一連結串列上執行的其他連結串列修改原語(例如 list_add_tail_rcu()list_del_rcu())發生競爭。但是,與 _rcu 連結串列遍歷原語(例如 list_for_each_entry_rcu())併發執行是完全合法的。

void list_del_rcu(struct list_head *entry)

從連結串列中刪除條目,無需重新初始化

引數

struct list_head *entry

要從列表中刪除的元素。

注意

在此之後,entry 上的 list_empty() 不會返回 true,該條目處於未定義狀態。 它對於基於 RCU 的無鎖遍歷很有用。

描述

特別是,這意味著我們不能汙染可能仍用於遍歷列表的前向指標。

呼叫者必須採取必要的預防措施(例如持有適當的鎖),以避免與同一連結串列上執行的其他連結串列修改原語(例如 list_del_rcu()list_add_rcu())發生競爭。但是,與 _rcu 連結串列遍歷原語(例如 list_for_each_entry_rcu())併發執行是完全合法的。

請注意,不允許呼叫者立即釋放新刪除的條目。相反,必須使用 synchronize_rcu()call_rcu() 來延遲釋放,直到 RCU 寬限期過去。

void list_bidir_del_rcu(struct list_head *entry)

從連結串列中刪除條目,無需重新初始化

引數

struct list_head *entry

要從列表中刪除的元素。

描述

list_del_rcu() 相比,不會汙染 prev 指標,因此允許透過 list_bidir_prev_rcu() 進行向後遍歷。

呼叫者必須採取必要的預防措施(例如持有適當的鎖),以避免與同一連結串列上執行的其他連結串列修改原語(例如 list_bidir_del_rcu()list_add_rcu())發生競爭。但是,與 _rcu 連結串列遍歷原語(例如 list_for_each_entry_rcu())併發執行是完全合法的。

請注意,list_del_rcu()list_bidir_del_rcu() 不得在同一連結串列上使用。

請注意,不允許呼叫者立即釋放新刪除的條目。相反,必須使用 synchronize_rcu()call_rcu() 來延遲釋放,直到 RCU 寬限期過去。

注意

在此之後,entry 上的 list_empty() 不會返回 true,因為該條目處於特殊的未定義狀態,該狀態允許基於 RCU 的無鎖反向遍歷。特別是,這意味著我們不能汙染可能仍用於遍歷列表的前向和後向指標。

void hlist_del_init_rcu(struct hlist_node *n)

從雜湊連結串列中刪除條目,並重新初始化

引數

struct hlist_node *n

要從雜湊列表中刪除的元素。

注意

在此之後,節點上的 list_unhashed() 返回 true。如果寫入者需要知道連結串列條目是否仍然被雜湊或已經被取消雜湊,則這對於基於 RCU 的無鎖讀取遍歷很有用。

描述

特別是,這意味著我們不能汙染可能仍用於遍歷雜湊連結串列的前向指標,並且我們只能將 pprev 指標置零,以便在此之後 list_unhashed() 返回 true。

呼叫者必須採取必要的預防措施(例如持有適當的鎖),以避免與同一連結串列上執行的其他連結串列修改原語(例如 hlist_add_head_rcu()hlist_del_rcu())發生競爭。但是,與 _rcu 連結串列遍歷原語(例如 hlist_for_each_entry_rcu())併發執行是完全合法的。

void list_replace_rcu(struct list_head *old, struct list_head *new)

用新條目替換舊條目

引數

struct list_head *old

要替換的元素

struct list_head *new

要插入的新元素

描述

從併發讀取者的角度來看,**old** 條目將被 **new** 條目原子地替換。如果有任何併發更新程式,則由呼叫者負責與它們同步。

注意

**old** 不應為空。

void __list_splice_init_rcu(struct list_head *list, struct list_head *prev, struct list_head *next, void (*sync)(void))

將受 RCU 保護的列表連線到現有列表中。

引數

struct list_head *list

要拼接的受 RCU 保護的列表

struct list_head *prev

指向現有列表的最後一個元素

struct list_head *next

指向現有列表的第一個元素

void (*sync)(void)

synchronize_rcu, synchronize_rcu_expedited, ...

描述

由 **prev** 和 **next** 指向的列表可以與此函式併發地進行 RCU 讀取遍歷。

請注意,此函式會阻塞。

重要提示:呼叫者必須採取必要的措施來防止對現有列表進行任何其他更新。原則上,一旦 sync() 開始執行,就可以修改列表。如果必須這樣做,則可以建立基於 call_rcu() 的替代版本。但只有在 - 真正 - 需要時 -- RCU API 成員並不短缺。

void list_splice_init_rcu(struct list_head *list, struct list_head *head, void (*sync)(void))

將受 RCU 保護的列表拼接到一個現有列表中,專為堆疊設計。

引數

struct list_head *list

要拼接的受 RCU 保護的列表

struct list_head *head

現有列表中要將第一個列表拼接到的位置

void (*sync)(void)

synchronize_rcu, synchronize_rcu_expedited, ...

void list_splice_tail_init_rcu(struct list_head *list, struct list_head *head, void (*sync)(void))

將受 RCU 保護的列表拼接到一個現有列表中,專為佇列設計。

引數

struct list_head *list

要拼接的受 RCU 保護的列表

struct list_head *head

現有列表中要將第一個列表拼接到的位置

void (*sync)(void)

synchronize_rcu, synchronize_rcu_expedited, ...

list_entry_rcu

list_entry_rcu (ptr, type, member)

獲取此條目的結構體

引數

ptr

struct list_head 指標。

type

嵌入此結構的結構體型別。

member

結構體中 list_head 的名稱。

描述

只要由 rcu_read_lock() 保護,此原語就可以與 _rcu 連結串列修改原語(例如 list_add_rcu())安全地併發執行。

list_first_or_null_rcu

list_first_or_null_rcu (ptr, type, member)

從連結串列中獲取第一個元素

引數

ptr

從中獲取元素的連結串列頭。

type

嵌入此結構的結構體型別。

member

結構體中 list_head 的名稱。

描述

請注意,如果連結串列為空,則返回 NULL。

只要由 rcu_read_lock() 保護,此原語就可以與 _rcu 連結串列修改原語(例如 list_add_rcu())安全地併發執行。

list_next_or_null_rcu

list_next_or_null_rcu (head, ptr, type, member)

從列表中獲取下一個元素

引數

head

列表的頭部。

ptr

從中獲取下一個元素的連結串列頭部。

type

嵌入此結構的結構體型別。

member

結構體中 list_head 的名稱。

描述

請注意,如果 ptr 位於列表末尾,則返回 NULL。

只要由 rcu_read_lock() 保護,此原語就可以與 _rcu 連結串列修改原語(例如 list_add_rcu())安全地併發執行。

list_for_each_entry_rcu

list_for_each_entry_rcu (pos, head, member, cond...)

迭代給定型別的 rcu 列表

引數

pos

用作循環遊標的 型別 *。

head

連結串列的頭部。

member

結構體中 list_head 的名稱。

cond...

如果從非 RCU 保護呼叫,則為可選的 lockdep 表示式。

描述

只要由 rcu_read_lock() 保護,此連結串列遍歷原語就可以與 _rcu 連結串列修改原語(例如 list_add_rcu())安全地併發執行。

list_for_each_entry_srcu

list_for_each_entry_srcu (pos, head, member, cond)

迭代給定型別的 rcu 列表

引數

pos

用作循環遊標的 型別 *。

head

連結串列的頭部。

member

結構體中 list_head 的名稱。

cond

遍歷列表所需的鎖的 lockdep 表示式。

描述

只要由 srcu_read_lock() 保護,此連結串列遍歷原語就可以與 _rcu 連結串列修改原語(例如 list_add_rcu())安全地併發執行。從讀取端可以將 lockdep 表示式 srcu_read_lock_held() 作為 cond 引數傳遞。

list_entry_lockless

list_entry_lockless (ptr, type, member)

獲取此條目的結構體

引數

ptr

struct list_head 指標。

type

嵌入此結構的結構體型別。

member

結構體中 list_head 的名稱。

描述

此原語可以與 _rcu 連結串列修改原語(例如 list_add_rcu())安全地併發執行,但需要一些隱式 RCU 讀取端保護。一個例子是在一個特殊的異常時間環境中執行,在該環境中停用了搶佔並且無法呼叫 lockdep。另一個例子是當將專案新增到列表中,但從未刪除時。

list_for_each_entry_lockless

list_for_each_entry_lockless (pos, head, member)

迭代給定型別的 rcu 列表

引數

pos

用作循環遊標的 型別 *。

head

連結串列的頭部。

member

結構體中 list_struct 的名稱。

描述

此原語可以與 _rcu 連結串列修改原語(例如 list_add_rcu())安全地併發執行,但需要一些隱式 RCU 讀取端保護。一個例子是在一個特殊的異常時間環境中執行,在該環境中停用了搶佔並且無法呼叫 lockdep。另一個例子是當將專案新增到列表中,但從未刪除時。

list_for_each_entry_continue_rcu

list_for_each_entry_continue_rcu (pos, head, member)

繼續迭代給定型別的連結串列

引數

pos

用作循環遊標的 型別 *。

head

連結串列的頭部。

member

結構體中 list_head 的名稱。

描述

繼續迭代給定型別的列表,在當前位置之後繼續,該位置必須在獲取 RCU 讀取鎖時位於列表中。這通常需要您從同一 RCU 讀取端臨界區中先前遍歷列表獲得節點,或者您持有某種非 RCU 引用(例如引用計數)以保持節點活動 * 並且 * 在列表中。

此迭代器類似於 list_for_each_entry_from_rcu(),只是此迭代器從給定位置之後開始,而該迭代器從給定位置開始。

list_for_each_entry_from_rcu

list_for_each_entry_from_rcu (pos, head, member)

從當前點迭代列表

引數

pos

用作循環遊標的 型別 *。

head

連結串列的頭部。

member

結構體中 list_node 的名稱。

描述

從給定位置開始迭代列表的尾部,該位置必須在獲取 RCU 讀取鎖時位於列表中。這通常需要您從同一 RCU 讀取端臨界區中先前遍歷列表獲得節點,或者您持有某種非 RCU 引用(例如引用計數)以保持節點活動 * 並且 * 在列表中。

此迭代器類似於 list_for_each_entry_continue_rcu(),只是此迭代器從給定位置開始,而該迭代器從給定位置之後的位置開始。

void hlist_del_rcu(struct hlist_node *n)

從雜湊列表中刪除條目,而無需重新初始化

引數

struct hlist_node *n

要從雜湊列表中刪除的元素。

注意

在此之後,entry 上的 list_unhashed() 不會返回 true,該條目處於未定義狀態。它對於基於 RCU 的無鎖遍歷很有用。

描述

特別是,這意味著我們無法破壞可能仍用於遍歷雜湊列表的前向指標。

呼叫者必須採取必要的預防措施(例如持有適當的鎖),以避免與同一連結串列上執行的其他連結串列修改原語(例如 hlist_add_head_rcu()hlist_del_rcu())發生競爭。但是,與 _rcu 連結串列遍歷原語(例如 hlist_for_each_entry())併發執行是完全合法的。

void hlist_replace_rcu(struct hlist_node *old, struct hlist_node *new)

用新條目替換舊條目

引數

struct hlist_node *old

要替換的元素

struct hlist_node *new

要插入的新元素

描述

從併發讀取者的角度來看,**old** 條目將被 **new** 條目原子地替換。如果有任何併發更新程式,則由呼叫者負責與它們同步。

void hlists_swap_heads_rcu(struct hlist_head *left, struct hlist_head *right)

交換 hlist head 指向的列表

引數

struct hlist_head *left

左側的 hlist head

struct hlist_head *right

右側的 hlist head

描述

列表初始狀態為 [left ][node1 ... ] 和

[right ][node2 ... ]

列表最終狀態為 [left ][node2 ... ]

[right ][node1 ... ]

void hlist_add_head_rcu(struct hlist_node *n, struct hlist_head *h)

引數

struct hlist_node *n

要新增到雜湊列表的元素。

struct hlist_head *h

要新增到的列表。

描述

在允許併發遍歷的情況下,將指定的元素新增到指定的 hlist。

呼叫者必須採取必要的預防措施(例如持有適當的鎖),以避免與另一個列表修改原語(例如 hlist_add_head_rcu()hlist_del_rcu())在同一個列表上競爭。但是,完全可以與 _rcu 列表遍歷原語(例如 hlist_for_each_entry_rcu())併發執行,用於防止 Alpha CPU 上的記憶體一致性問題。無論 CPU 型別如何,列表遍歷原語都必須受到 rcu_read_lock() 的保護。

void hlist_add_tail_rcu(struct hlist_node *n, struct hlist_head *h)

引數

struct hlist_node *n

要新增到雜湊列表的元素。

struct hlist_head *h

要新增到的列表。

描述

在允許併發遍歷的情況下,將指定的元素新增到指定的 hlist。

呼叫者必須採取必要的預防措施(例如持有適當的鎖),以避免與另一個列表修改原語(例如 hlist_add_head_rcu()hlist_del_rcu())在同一個列表上競爭。但是,完全可以與 _rcu 列表遍歷原語(例如 hlist_for_each_entry_rcu())併發執行,用於防止 Alpha CPU 上的記憶體一致性問題。無論 CPU 型別如何,列表遍歷原語都必須受到 rcu_read_lock() 的保護。

void hlist_add_before_rcu(struct hlist_node *n, struct hlist_node *next)

引數

struct hlist_node *n

要新增到雜湊列表中的新元素。

struct hlist_node *next

在現有元素之前新增新元素。

描述

在允許併發遍歷的情況下,將指定的元素新增到指定的 hlist 中的指定節點之前。

呼叫者必須採取必要的預防措施(例如持有適當的鎖),以避免與另一個列表修改原語(例如 hlist_add_head_rcu()hlist_del_rcu())在同一個列表上競爭。但是,完全可以與 _rcu 列表遍歷原語(例如 hlist_for_each_entry_rcu())併發執行,用於防止 Alpha CPU 上的記憶體一致性問題。

void hlist_add_behind_rcu(struct hlist_node *n, struct hlist_node *prev)

引數

struct hlist_node *n

要新增到雜湊列表中的新元素。

struct hlist_node *prev

在現有元素之後新增新元素。

描述

在允許併發遍歷的情況下,將指定的元素新增到指定的 hlist 中的指定節點之後。

呼叫者必須採取必要的預防措施(例如持有適當的鎖),以避免與另一個列表修改原語(例如 hlist_add_head_rcu()hlist_del_rcu())在同一個列表上競爭。但是,完全可以與 _rcu 列表遍歷原語(例如 hlist_for_each_entry_rcu())併發執行,用於防止 Alpha CPU 上的記憶體一致性問題。

hlist_for_each_entry_rcu

hlist_for_each_entry_rcu (pos, head, member, cond...)

迭代給定型別的 rcu 列表

引數

pos

用作循環遊標的 型別 *。

head

連結串列的頭部。

member

結構體中 hlist_node 的名稱。

cond...

如果從非 RCU 保護呼叫,則為可選的 lockdep 表示式。

描述

只要遍歷受到 rcu_read_lock() 的保護,此列表遍歷原語就可以安全地與 _rcu 列表修改原語(例如 hlist_add_head_rcu())併發執行。

hlist_for_each_entry_srcu

hlist_for_each_entry_srcu (pos, head, member, cond)

迭代給定型別的 rcu 列表

引數

pos

用作循環遊標的 型別 *。

head

連結串列的頭部。

member

結構體中 hlist_node 的名稱。

cond

遍歷列表所需的鎖的 lockdep 表示式。

描述

只要遍歷受到 srcu_read_lock() 的保護,此列表遍歷原語就可以安全地與 _rcu 列表修改原語(例如 hlist_add_head_rcu())併發執行。lockdep 表示式 srcu_read_lock_held() 可以作為 cond 引數從讀取端傳遞。

hlist_for_each_entry_rcu_notrace

hlist_for_each_entry_rcu_notrace (pos, head, member)

迭代給定型別的 rcu 列表(用於跟蹤)

引數

pos

用作循環遊標的 型別 *。

head

連結串列的頭部。

member

結構體中 hlist_node 的名稱。

描述

只要遍歷受到 rcu_read_lock() 的保護,此列表遍歷原語就可以安全地與 _rcu 列表修改原語(例如 hlist_add_head_rcu())併發執行。

這與 hlist_for_each_entry_rcu() 相同,只是它不執行任何 RCU 除錯或跟蹤。

hlist_for_each_entry_rcu_bh

hlist_for_each_entry_rcu_bh (pos, head, member)

迭代給定型別的 rcu 列表

引數

pos

用作循環遊標的 型別 *。

head

連結串列的頭部。

member

結構體中 hlist_node 的名稱。

描述

只要遍歷受到 rcu_read_lock() 的保護,此列表遍歷原語就可以安全地與 _rcu 列表修改原語(例如 hlist_add_head_rcu())併發執行。

hlist_for_each_entry_continue_rcu

hlist_for_each_entry_continue_rcu (pos, member)

在當前點之後繼續迭代 hlist

引數

pos

用作循環遊標的 型別 *。

member

結構體中 hlist_node 的名稱。

hlist_for_each_entry_continue_rcu_bh

hlist_for_each_entry_continue_rcu_bh (pos, member)

在當前點之後繼續迭代 hlist

引數

pos

用作循環遊標的 型別 *。

member

結構體中 hlist_node 的名稱。

hlist_for_each_entry_from_rcu

hlist_for_each_entry_from_rcu (pos, member)

從當前點繼續迭代 hlist

引數

pos

用作循環遊標的 型別 *。

member

結構體中 hlist_node 的名稱。

void hlist_nulls_del_init_rcu(struct hlist_nulls_node *n)

從雜湊連結串列中刪除條目,並重新初始化

引數

struct hlist_nulls_node *n

要從雜湊列表中刪除的元素。

注意

在此之後,節點上的 hlist_nulls_unhashed() 返回 true。如果寫入方必須知道列表條目是否仍然雜湊或已經取消雜湊,則它對於基於 RCU 的讀取鎖無遍歷非常有用。

描述

特別是,這意味著我們不能汙染可能仍用於遍歷雜湊連結串列的前向指標,並且我們只能將 pprev 指標置零,以便在此之後 list_unhashed() 返回 true。

呼叫者必須採取必要的預防措施(例如持有適當的鎖),以避免與另一個列表修改原語(例如 hlist_nulls_add_head_rcu()hlist_nulls_del_rcu())在同一個列表上競爭。但是,完全可以與 _rcu 列表遍歷原語(例如 hlist_nulls_for_each_entry_rcu())併發執行。

hlist_nulls_first_rcu

hlist_nulls_first_rcu (head)

返回雜湊列表的第一個元素。

引數

head

列表的頭部。

hlist_nulls_next_rcu

hlist_nulls_next_rcu (node)

返回 node 之後的列表元素。

引數

節點

列表的元素。

void hlist_nulls_del_rcu(struct hlist_nulls_node *n)

從雜湊列表中刪除條目,而無需重新初始化

引數

struct hlist_nulls_node *n

要從雜湊列表中刪除的元素。

注意

在此之後,條目上的 hlist_nulls_unhashed() 不會返回 true,該條目處於未定義狀態。它對於基於 RCU 的鎖無遍歷非常有用。

描述

特別是,這意味著我們無法破壞可能仍用於遍歷雜湊列表的前向指標。

呼叫者必須採取必要的預防措施(例如持有適當的鎖),以避免與另一個列表修改原語(例如 hlist_nulls_add_head_rcu()hlist_nulls_del_rcu())在同一個列表上競爭。但是,完全可以與 _rcu 列表遍歷原語(例如 hlist_nulls_for_each_entry())併發執行。

void hlist_nulls_add_head_rcu(struct hlist_nulls_node *n, struct hlist_nulls_head *h)

引數

struct hlist_nulls_node *n

要新增到雜湊列表的元素。

struct hlist_nulls_head *h

要新增到的列表。

描述

在允許併發遍歷的情況下,將指定的元素新增到指定的 hlist_nulls。

呼叫者必須採取必要的預防措施(例如持有適當的鎖),以避免與另一個列表修改原語(例如 hlist_nulls_add_head_rcu()hlist_nulls_del_rcu())在同一個列表上競爭。但是,完全可以與 _rcu 列表遍歷原語(例如 hlist_nulls_for_each_entry_rcu())併發執行,用於防止 Alpha CPU 上的記憶體一致性問題。無論 CPU 型別如何,列表遍歷原語都必須受到 rcu_read_lock() 的保護。

void hlist_nulls_add_tail_rcu(struct hlist_nulls_node *n, struct hlist_nulls_head *h)

引數

struct hlist_nulls_node *n

要新增到雜湊列表的元素。

struct hlist_nulls_head *h

要新增到的列表。

描述

在允許併發遍歷的情況下,將指定的元素新增到指定的 hlist_nulls。

呼叫者必須採取必要的預防措施(例如持有適當的鎖),以避免與另一個列表修改原語(例如 hlist_nulls_add_head_rcu()hlist_nulls_del_rcu())在同一個列表上競爭。但是,完全可以與 _rcu 列表遍歷原語(例如 hlist_nulls_for_each_entry_rcu())併發執行,用於防止 Alpha CPU 上的記憶體一致性問題。無論 CPU 型別如何,列表遍歷原語都必須受到 rcu_read_lock() 的保護。

hlist_nulls_for_each_entry_rcu

hlist_nulls_for_each_entry_rcu (tpos, pos, head, member)

迭代給定型別的 rcu 列表

引數

tpos

用作循環遊標的 型別 *。

pos

要用作迴圈游標的 struct hlist_nulls_node

head

列表的頭部。

member

結構體中 hlist_nulls_node 的名稱。

描述

需要 barrier() 來確保編譯器不會快取第一個元素 [1],因為此迴圈可以重新啟動 [2] [1] Documentation/memory-barriers.txt 大約第 1533 行 [2] 使用 RCU hlist_nulls 來保護列表和物件 大約第 146 行

hlist_nulls_for_each_entry_safe

hlist_nulls_for_each_entry_safe (tpos, pos, head, member)

迭代給定型別的連結串列,防止刪除連結串列條目

引數

tpos

用作循環遊標的 型別 *。

pos

要用作迴圈游標的 struct hlist_nulls_node

head

列表的頭部。

member

結構體中 hlist_nulls_node 的名稱。

bool rcu_sync_is_idle(struct rcu_sync *rsp)

是否允許讀取器使用其快速路徑?

引數

struct rcu_sync *rsp

指向用於同步的 rcu_sync 結構的指標

描述

如果允許讀取器使用其快速路徑,則返回 true。必須在某種型別的 RCU 讀取端臨界區內呼叫。

void rcu_sync_init(struct rcu_sync *rsp)

初始化 rcu_sync 結構

引數

struct rcu_sync *rsp

指向要初始化的 rcu_sync 結構的指標

void rcu_sync_func(struct rcu_head *rhp)

管理讀取器對快速路徑訪問的回撥函式

引數

struct rcu_head *rhp

指向 rcu_sync 結構中用於同步的 rcu_head 的指標

描述

此函式由 rcu_sync_enter()rcu_sync_exit() 傳遞給 call_rcu() 函式,以便在呼叫 enter/exit 之後的寬限期後呼叫它。

如果它由 rcu_sync_enter() 呼叫,則表示所有讀取器都已切換到慢速路徑。

如果它由 rcu_sync_exit() 呼叫,它會根據在此期間發生的事件採取操作,以便緊密間隔的 rcu_sync_enter()rcu_sync_exit() 對不需要等待寬限期。

如果在寬限期結束前再次呼叫 rcu_sync_enter(),則重置狀態,以便下一個 rcu_sync_exit() 允許讀者返回到他們的快速路徑(在寬限期之後)。 如果在寬限期結束之前,rcu_sync_enter() 及其匹配的 rcu_sync_exit() 都被呼叫,則代表該 rcu_sync_exit() 重新呼叫 call_rcu()。 否則,將所有狀態設定回空閒,以便讀者可以再次使用他們的快速路徑。

void rcu_sync_enter(struct rcu_sync *rsp)

強制讀者進入慢速路徑

引數

struct rcu_sync *rsp

指向用於同步的 rcu_sync 結構的指標

描述

此函式由更新程式使用,這些更新程式需要讀者在更新期間使用慢速路徑。 此函式返回後,所有後續對 rcu_sync_is_idle() 的呼叫都將返回 false,這告訴讀者遠離他們的快速路徑。 稍後呼叫 rcu_sync_exit() 重新啟用讀者快速路徑。

當孤立呼叫時,rcu_sync_enter() 必須等待寬限期,但是,緊密間隔的 rcu_sync_enter() 呼叫可以透過由 rcu_sync_enter()rcu_sync_exit()rcu_sync_func() 實現的狀態機來最佳化掉寬限期等待。

void rcu_sync_exit(struct rcu_sync *rsp)

在寬限期後允許讀者返回到快速路徑

引數

struct rcu_sync *rsp

指向用於同步的 rcu_sync 結構的指標

描述

此函式由已完成的更新程式使用,因此現在可以允許讀者在經過寬限期後使用他們的快速路徑。 在此寬限期完成後,所有後續對 rcu_sync_is_idle() 的呼叫都將返回 true,這告訴讀者他們可以再次使用他們的快速路徑。

void rcu_sync_dtor(struct rcu_sync *rsp)

清理 rcu_sync 結構

引數

struct rcu_sync *rsp

指向要清理的 rcu_sync 結構的指標

struct rcu_tasks_percpu

類似於 Tasks-RCU 機制的定義的每個 CPU 元件。

定義:

struct rcu_tasks_percpu {
    struct rcu_segcblist cblist;
    raw_spinlock_t __private lock;
    unsigned long rtp_jiffies;
    unsigned long rtp_n_lock_retries;
    struct timer_list lazy_timer;
    unsigned int urgent_gp;
    struct work_struct rtp_work;
    struct irq_work rtp_irq_work;
    struct rcu_head barrier_q_head;
    struct list_head rtp_blkd_tasks;
    struct list_head rtp_exit_list;
    int cpu;
    int index;
    struct rcu_tasks *rtpp;
};

成員

cblist

回撥列表。

lock

鎖定保護每個 CPU 回撥列表。

rtp_jiffies

用於統計資訊的 Jiffies 計數器值。

rtp_n_lock_retries

粗略的鎖爭用統計資訊。

lazy_timer

用於取消延遲迴調的計時器。

urgent_gp

額外的非延遲寬限期的數量。

rtp_work

用於呼叫回撥的工作佇列。

rtp_irq_work

用於延遲喚醒的 IRQ 工作佇列。

barrier_q_head

用於屏障操作的 RCU 回撥。

rtp_blkd_tasks

作為讀者被阻止的任務列表。

rtp_exit_list

位於 do_exit() 後部分的任務列表。

cpu

與此條目對應的 CPU 編號。

index

此 CPU 在 rcu_tasks 結構的 rtpcp_array 中的索引。

rtpp

指向 rcu_tasks 結構的指標。

struct rcu_tasks

類似於 Tasks-RCU 機制的定義。

定義:

struct rcu_tasks {
    struct rcuwait cbs_wait;
    raw_spinlock_t cbs_gbl_lock;
    struct mutex tasks_gp_mutex;
    int gp_state;
    int gp_sleep;
    int init_fract;
    unsigned long gp_jiffies;
    unsigned long gp_start;
    unsigned long tasks_gp_seq;
    unsigned long n_ipis;
    unsigned long n_ipis_fails;
    struct task_struct *kthread_ptr;
    unsigned long lazy_jiffies;
    rcu_tasks_gp_func_t gp_func;
    pregp_func_t pregp_func;
    pertask_func_t pertask_func;
    postscan_func_t postscan_func;
    holdouts_func_t holdouts_func;
    postgp_func_t postgp_func;
    call_rcu_func_t call_func;
    unsigned int wait_state;
    struct rcu_tasks_percpu __percpu *rtpcpu;
    struct rcu_tasks_percpu **rtpcp_array;
    int percpu_enqueue_shift;
    int percpu_enqueue_lim;
    int percpu_dequeue_lim;
    unsigned long percpu_dequeue_gpseq;
    struct mutex barrier_q_mutex;
    atomic_t barrier_q_count;
    struct completion barrier_q_completion;
    unsigned long barrier_q_seq;
    unsigned long barrier_q_start;
    char *name;
    char *kname;
};

成員

cbs_wait

RCU 等待允許新的回撥引起 kthread 的注意。

cbs_gbl_lock

鎖定保護回撥列表。

tasks_gp_mutex

互斥鎖保護寬限期,在啟動中期死區期間需要。

gp_state

寬限期的最新狀態轉換(除錯)。

gp_sleep

每個寬限期的睡眠以防止 CPU 繫結的迴圈。

init_fract

初始退避睡眠間隔。

gp_jiffies

上次 gp_state 轉換的時間。

gp_start

最近一次寬限期開始的時間,以 jiffies 為單位。

tasks_gp_seq

自啟動以來完成的寬限期的數量,位於高位。

n_ipis

傳送以鼓勵寬限期結束的 IPI 的數量。

n_ipis_fails

IPI 傳送失敗的數量。

kthread_ptr

此風格的寬限期/回撥呼叫 kthread。

lazy_jiffies

允許回撥延遲的 jiffies 數量。

gp_func

此風格的寬限期等待函式。

pregp_func

此風格的寬限期前函式(可選)。

pertask_func

此風格的每個任務掃描函式(可選)。

postscan_func

此風格的任務後掃描函式(可選)。

holdouts_func

此風格的保留列表掃描函式(可選)。

postgp_func

此風格的寬限期後函式(可選)。

call_func

此風格的 call_rcu() 等效函式。

wait_state

同步寬限期等待的任務狀態(預設為 TASK_UNINTERRUPTIBLE)。

rtpcpu

此風格的 rcu_tasks_percpu 結構。

rtpcp_array

指向 cpu_possible_mask 中 CPU 的 rcu_tasks_percpu 結構的指標陣列。

percpu_enqueue_shift

在排隊回撥時,將 CPU ID 向下移動這麼多。

percpu_enqueue_lim

用於排隊的每個 CPU 回撥佇列的數量。

percpu_dequeue_lim

用於出隊的每個 CPU 回撥佇列的數量。

percpu_dequeue_gpseq

RCU 寬限期編號,用於將排隊限制傳播到出隊者。

barrier_q_mutex

序列化屏障操作。

barrier_q_count

正在等待的佇列數量。

barrier_q_completion

屏障等待/喚醒機制。

barrier_q_seq

屏障操作的序列號。

barrier_q_start

最近一次屏障開始的時間,以 jiffies 為單位。

name

此風格的文字名稱。

kname

此風格的 kthread 名稱。

void call_rcu_tasks(struct rcu_head *rhp, rcu_callback_t func)

將 RCU 排隊以呼叫基於任務的寬限期

引數

struct rcu_head *rhp

用於對 RCU 更新進行排隊的結構。

rcu_callback_t func

在寬限期後呼叫的實際回撥函式

描述

回撥函式將在完整的寬限期結束後一段時間後被呼叫,換句話說,在所有當前正在執行的 RCU 讀取端關鍵部分都已完成後。 call_rcu_tasks() 假設讀取端關鍵部分在自願上下文切換(不是搶佔!)、cond_resched_tasks_rcu_qs()、進入空閒或轉換到使用者模式執行時結束。 因此,沒有類似於 rcu_read_lock()rcu_read_unlock() 的讀取端原語,因為此原語旨在確定所有任務都已透過安全狀態,而不是用於資料結構同步。

有關記憶體排序保證的更多詳細資訊,請參見 call_rcu() 的描述。

void synchronize_rcu_tasks(void)

等待 rcu-tasks 寬限期過去。

引數

void

無引數

描述

在完整的 rcu-tasks 寬限期過去後一段時間後,控制將返回給呼叫者,換句話說,在所有當前正在執行的 rcu-tasks 讀取端關鍵部分都已過去後。 這些讀取端關鍵部分由對 schedule()、cond_resched_tasks_rcu_qs()、空閒執行、使用者空間執行、對 synchronize_rcu_tasks() 的呼叫以及(理論上)cond_resched() 的呼叫分隔。

這是一個非常專門的原語,僅用於跟蹤和其他需要操作函式序言和分析掛鉤的少數情況。 synchronize_rcu_tasks() 函式(尚未)打算從多個 CPU 大量使用。

有關記憶體排序保證的更多詳細資訊,請參見 synchronize_rcu() 的描述。

void rcu_barrier_tasks(void)

等待正在進行的 call_rcu_tasks() 回撥。

引數

void

無引數

描述

雖然當前的實現保證等待,但它沒有義務,例如,如果沒有掛起的回撥。

void synchronize_rcu_tasks_rude(void)

等待粗魯的 rcu-tasks 寬限期

引數

void

無引數

描述

在粗魯的 rcu-tasks 寬限期過去後一段時間後,控制將返回給呼叫者,換句話說,在所有當前正在執行的 rcu-tasks 讀取端關鍵部分都已過去後。 這些讀取端關鍵部分由對 schedule()、cond_resched_tasks_rcu_qs()、使用者空間執行(這是一個可排程的上下文)以及(理論上)cond_resched() 的呼叫分隔。

這是一個非常專門的原語,僅用於跟蹤和其他需要操作函式序言和分析掛鉤的少數情況。 synchronize_rcu_tasks_rude() 函式(尚未)打算從多個 CPU 大量使用。

有關記憶體排序保證的更多詳細資訊,請參見 synchronize_rcu() 的描述。

void call_rcu_tasks_trace(struct rcu_head *rhp, rcu_callback_t func)

將回調跟蹤任務排隊基於寬限期

引數

struct rcu_head *rhp

用於對 RCU 更新進行排隊的結構。

rcu_callback_t func

在寬限期後呼叫的實際回撥函式

描述

回撥函式將在跟蹤 rcu-tasks 寬限期過去後一段時間後被呼叫,換句話說,在所有當前正在執行的跟蹤 rcu-tasks 讀取端關鍵部分都已完成後。 這些讀取端關鍵部分由對 rcu_read_lock_trace()rcu_read_unlock_trace() 的呼叫分隔。

有關記憶體排序保證的更多詳細資訊,請參見 call_rcu() 的描述。

void synchronize_rcu_tasks_trace(void)

等待跟蹤 rcu-tasks 寬限期

引數

void

無引數

描述

在跟蹤 rcu-tasks 寬限期過去後一段時間後,控制將返回給呼叫者,換句話說,在所有當前正在執行的跟蹤 rcu-tasks 讀取端關鍵部分都已完成後。 這些讀取端關鍵部分由對 rcu_read_lock_trace()rcu_read_unlock_trace() 的呼叫分隔。

這是一個非常專門的原語,僅用於跟蹤和其他需要操作函式序言和分析掛鉤的少數情況。 synchronize_rcu_tasks_trace() 函式(尚未)打算從多個 CPU 大量使用。

有關記憶體排序保證的更多詳細資訊,請參見 synchronize_rcu() 的描述。

void rcu_barrier_tasks_trace(void)

等待正在進行的 call_rcu_tasks_trace() 回撥。

引數

void

無引數

描述

雖然當前的實現保證等待,但它沒有義務,例如,如果沒有掛起的回撥。

void rcu_cpu_stall_reset(void)

重新啟動當前寬限期的停止警告超時

引數

void

無引數

描述

為了從呼叫者執行重置請求,停用停止檢測,直到經過 3 個 fqs 迴圈。 這是為了確保載入新的 jiffies。 從 fqs 迴圈執行應該是安全的,因為應該已經過去了足夠的定時器中斷和上下文切換。

呼叫者必須停用硬 IRQ。

int rcu_stall_chain_notifier_register(struct notifier_block *n)

新增 RCU CPU 停止通知器

引數

struct notifier_block *n

要新增的條目。

描述

將 RCU CPU 停止通知器新增到原子通知器鏈。 傳遞給通知器的 action 將是 RCU_STALL_NOTIFY_NORM 或朋友。 data 將是停止的寬限期的持續時間,以 jiffies 為單位,強制轉換為 void* 指標。

成功時返回 0,錯誤時返回 -EEXIST

int rcu_stall_chain_notifier_unregister(struct notifier_block *n)

刪除 RCU CPU 停止通知器

引數

struct notifier_block *n

要新增的條目。

描述

從原子通知器鏈中刪除 RCU CPU 停止通知器。

成功時返回零,失敗時返回 -ENOENT

void rcu_read_lock_trace(void)

標記 RCU 跟蹤讀取端關鍵部分的開始

引數

void

無引數

描述

synchronize_rcu_tasks_trace() 由一個任務呼叫時,則保證該任務會阻塞,直到所有其他任務退出其讀取端關鍵部分。 同樣,如果在其他任務位於 RCU 讀取端關鍵部分內時在一個任務上呼叫 call_rcu_trace(),則對應 RCU 回撥的呼叫將延遲到所有其他任務退出其關鍵部分之後。

有關更多詳細資訊,請參見 rcu_read_lock() 的文件。

void rcu_read_unlock_trace(void)

標記 RCU 跟蹤讀取端關鍵部分的結束

引數

void

無引數

描述

與先前對 rcu_read_lock_trace() 的呼叫配對,並允許巢狀。如果在沒有匹配的 rcu_read_lock_trace() 的情況下呼叫 rcu_read_unlock_trace() 是禁止的,並且會導致 lockdep 抱怨。

更多細節,請參考 rcu_read_unlock() 的文件。

synchronize_rcu_mult

synchronize_rcu_mult (...)

併發等待多個寬限期

引數

...

要等待的不同寬限期的 call_rcu() 函式列表

描述

這個宏併發等待多種型別的 RCU 寬限期。例如,synchronize_rcu_mult(call_rcu, call_rcu_tasks) 將等待併發的 RCU 和 RCU-tasks 寬限期。等待給定的 SRCU 域需要您為該 SRCU 域的 call_srcu() 函式編寫一個包裝函式,該包裝函式提供指向相應 srcu_struct 的指標。

請注意,應使用 call_rcu_hurry() 而不是 call_rcu(),因為在用 CONFIG_RCU_LAZY=y 構建的核心中,call_rcu() 的呼叫與相應 RCU 回撥的呼叫之間的延遲可能長達數秒。

第一個引數告訴 Tiny RCU 的 _wait_rcu_gp() 不要費心等待 RCU。 原因是任何可以呼叫 synchronize_rcu_mult() 的地方都已經是一個完整的寬限期。

void rcuref_init(rcuref_t *ref, unsigned int cnt)

使用給定的引用計數初始化一個 rcuref 引用計數

引數

rcuref_t *ref

指向引用計數的指標

unsigned int cnt

初始引用計數通常為“1”

unsigned int rcuref_read(rcuref_t *ref)

讀取 rcuref 的持有引用計數數量

引數

rcuref_t *ref

指向引用計數的指標

返回

持有的引用數量 (0 ... N)。 值 0 並不表示可以安全地排程受此引用計數器保護的物件進行解構。 如果您想知道引用計數器是否已標記為 DEAD(由 rcuref_put() 發出訊號),請使用 rcuread_is_dead()。

bool rcuref_is_dead(rcuref_t *ref)

檢查 rcuref 是否已被標記為 dead

引數

rcuref_t *ref

指向引用計數的指標

返回

如果物件已被標記為 DEAD,則為 True。 這表示先前呼叫 rcuref_put() 在此引用計數器上返回 true,這意味著可以安全地排程受保護物件進行解構。 否則,返回 false。

bool rcuref_get(rcuref_t *ref)

獲取 rcuref 引用計數上的一個引用

引數

rcuref_t *ref

指向引用計數的指標

描述

類似於 atomic_inc_not_zero(),但在 RCUREF_MAXREF 處飽和。

不提供記憶體排序,假設呼叫者已保證物件記憶體穩定(RCU 等)。 它確實提供了一個控制依賴性,從而對未來的儲存進行排序。 請參閱 lib/rcuref.c 中的文件

返回

如果獲取引用的嘗試失敗,則為 False。 當最後一個引用已被放置時會發生這種情況

如果成功獲取了引用,則為 True

bool rcuref_put_rcusafe(rcuref_t *ref)
  • 釋放一個 rcuref 引用計數 RCU 安全的引用

引數

rcuref_t *ref

指向引用計數的指標

描述

提供釋放記憶體排序,以便在之前完成先前的載入和儲存,並在成功時提供獲取排序,以便 free() 必須在之後進行。

可以從上下文中呼叫,這些上下文保證如果遞減丟棄最後一個引用並且慢速路徑與併發的 get() 和 put() 對競爭,則不會發生寬限期,從而併發地釋放物件。 rcu_read_lock()'ed 和原子上下文符合條件。

返回

如果這是最後一個引用,並且將來沒有可能的引用,則為 True。 這向呼叫者發出訊號,表明它可以安全地釋放受引用計數器保護的物件。

如果仍然存在活動引用,或者 put() 與併發的 get()/put() 對競爭,則為 False。 不允許呼叫者釋放受保護的物件。

bool rcuref_put(rcuref_t *ref)
  • 釋放一個 rcuref 引用計數的引用

引數

rcuref_t *ref

指向引用計數的指標

描述

可以從任何上下文呼叫。

提供釋放記憶體排序,以便在之前完成先前的載入和儲存,並在成功時提供獲取排序,以便 free() 必須在之後進行。

返回

如果這是最後一個引用,並且將來沒有可能的引用,則為 True。 這向呼叫者發出訊號,表明它可以安全地排程受引用計數器保護的物件進行解構。

如果仍然存在活動引用,或者 put() 與併發的 get()/put() 對競爭,則為 False。 不允許呼叫者解構受保護的物件。

bool same_state_synchronize_rcu_full(struct rcu_gp_oldstate *rgosp1, struct rcu_gp_oldstate *rgosp2)

兩個舊狀態值是否相同?

引數

struct rcu_gp_oldstate *rgosp1

第一個舊狀態值。

struct rcu_gp_oldstate *rgosp2

第二個舊狀態值。

描述

這兩個 old-state 值必須從 get_state_synchronize_rcu_full()start_poll_synchronize_rcu_full()get_completed_synchronize_rcu_full() 中獲得。 如果這兩個值相同,則返回 true,否則返回 false。 這允許生命週期由 old-state 值跟蹤的結構將這些值推送到列表標頭,從而使這些結構稍微小一些。

請注意,等式是按位判斷的,因此在一個欄位中具有已完成狀態的 rcu_gp_oldstate 結構將與在另一個欄位中具有已完成狀態的結構進行比較而不相等。 畢竟,rcu_gp_oldstate 結構是不透明的,那麼這種情況最初是如何發生的呢?