А ещё я кого-то учу...
Флаги страниц памяти

Предыстория этой заметки

Пока не вижу её будущего, но не могу записать это в ту, которую сейчас пишу. В общем, я сломался об исходный код, а оказалось, что всё макросами генерится.

Цимес

Изучал я код __free_pages из mm/page_alloc.c. И в нём упоминается некий PageHead(), который я не смог ни нагрепать, ни найти его в elixir. Даже поиск в гитхабе ничего путного не дал. Зато, нашёл эту функцию в ядрах v4.3 и младше. Даже нашёл коммит, который удаляет эту функцию. В нём же он добавляет её использование. Я долго недоумевал по поводу. Пока не обратил внимание:

 __PAGEFLAG(Head, head) CLEARPAGEFLAG(Head, head)
-__PAGEFLAG(Tail, tail)

 ...

+static inline int PageTail(struct page *page)
 {
-    BUG_ON(!PageHead(page));
-    ClearPageHead(page);
+    return READ_ONCE(page->compound_head) & 1;
 }

Человек убрал использование макроса __PAGEFLAG с аргументами Tail, tail и добавил функцию PageTail. Использование макроса с аргументами Head, head он не добавил. Это навело меня на мысль, что эти макросы могут использоваться для генерации кода для доступа к флагам страницы. И действительно, определение макроса чётко даёт понять:

#define __PAGEFLAG(uname, lname, policy) \
    TESTPAGEFLAG(uname, lname, policy) \
    __SETPAGEFLAG(uname, lname, policy) \
    __CLEARPAGEFLAG(uname, lname, policy)

Внутри этого макроса есть заветный TESTPAGEFLAG(uname, lname, policy), который раскрывается в:

#define TESTPAGEFLAG(uname, lname, policy) \
static __always_inline bool folio_test_##lname(struct folio *folio) \
{ return test_bit(PG_##lname, folio_flags(folio, FOLIO_##policy)); } \
static __always_inline int Page##uname(struct page *page) \
{ return test_bit(PG_##lname, &policy(page, 0)->flags); }

— именно этот макрос и генерирует заветный PageHead(Page##uname).


2022-02-18 10:38