Linux PageDirty系列函数定义
Kernel版本:Linux 6.1.0
1. PG_Flags检测类型
1.1 分为以下三类
#define PAGEFLAG(uname, lname, policy) \
TESTPAGEFLAG(uname, lname, policy) \
SETPAGEFLAG(uname, lname, policy) \
CLEARPAGEFLAG(uname, lname, policy)
#define __PAGEFLAG(uname, lname, policy) \
TESTPAGEFLAG(uname, lname, policy) \
__SETPAGEFLAG(uname, lname, policy) \
__CLEARPAGEFLAG(uname, lname, policy)
#define TESTSCFLAG(uname, lname, policy) \
TESTSETFLAG(uname, lname, policy) \
TESTCLEARFLAG(uname, lname, policy)
1.2 对应的函数定义与实现
以上定义的实际实现为函数定义的拼装
包括:
Page##uname
SetPage##uname
ClearPage##uname
__SetPage##uname
__ClearPage##uname
TestSetPage##uname
TestClearPage##uname
他们的定义为:
/*
* Macros to create function definitions for page flags
*/
#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); }
#define SETPAGEFLAG(uname, lname, policy) \
static __always_inline \
void folio_set_##lname(struct folio *folio) \
{ set_bit(PG_##lname, folio_flags(folio, FOLIO_##policy)); } \
static __always_inline void SetPage##uname(struct page *page) \
{ set_bit(PG_##lname, &policy(page, 1)->flags); }
#define CLEARPAGEFLAG(uname, lname, policy) \
static __always_inline \
void folio_clear_##lname(struct folio *folio) \
{ clear_bit(PG_##lname, folio_flags(folio, FOLIO_##policy)); } \
static __always_inline void ClearPage##uname(struct page *page) \
{ clear_bit(PG_##lname, &policy(page, 1)->flags); }
#define __SETPAGEFLAG(uname, lname, policy) \
static __always_inline \
void __folio_set_##lname(struct folio *folio) \
{ __set_bit(PG_##lname, folio_flags(folio, FOLIO_##policy)); } \
static __always_inline void __SetPage##uname(struct page *page) \
{ __set_bit(PG_##lname, &policy(page, 1)->flags); }
#define __CLEARPAGEFLAG(uname, lname, policy) \
static __always_inline \
void __folio_clear_##lname(struct folio *folio) \
{ __clear_bit(PG_##lname, folio_flags(folio, FOLIO_##policy)); } \
static __always_inline void __ClearPage##uname(struct page *page) \
{ __clear_bit(PG_##lname, &policy(page, 1)->flags); }
#define TESTSETFLAG(uname, lname, policy) \
static __always_inline \
bool folio_test_set_##lname(struct folio *folio) \
{ return test_and_set_bit(PG_##lname, folio_flags(folio, FOLIO_##policy)); } \
static __always_inline int TestSetPage##uname(struct page *page) \
{ return test_and_set_bit(PG_##lname, &policy(page, 1)->flags); }
#define TESTCLEARFLAG(uname, lname, policy) \
static __always_inline \
bool folio_test_clear_##lname(struct folio *folio) \
{ return test_and_clear_bit(PG_##lname, folio_flags(folio, FOLIO_##policy)); } \
static __always_inline int TestClearPage##uname(struct page *page) \
{ return test_and_clear_bit(PG_##lname, &policy(page, 1)->flags); }
2. 定义位置
include/linux/page-flags.h
3. 定义函数
以Dirty标志的检测为例
PAGEFLAG(Dirty, dirty, PF_HEAD) TESTSCFLAG(Dirty, dirty, PF_HEAD)
__CLEARPAGEFLAG(Dirty, dirty, PF_HEAD)
该定义根据如下代码在编译阶段被解析
#define PAGEFLAG(uname, lname, policy) \
TESTPAGEFLAG(uname, lname, policy) \
SETPAGEFLAG(uname, lname, policy) \
CLEARPAGEFLAG(uname, lname, policy)
解析结果为
TESTPAGEFLAG(Dirty, dirty, PF_HEAD)
SETPAGEFLAG(Dirty, dirty, PF_HEAD)
CLEARPAGEFLAG(Dirty, dirty, PF_HEAD)
进一步被解析为
static __always_inline bool folio_test_dirty(struct folio *folio)
{ return test_bit(PG_dirty, folio_flags(folio, FOLIO_PF_HEAD)); }
static __always_inline int PageDirty(struct page *page)
{ return test_bit(PG_dirty, &PF_HEAD(page, 0)->flags); }
static __always_inline
void folio_set_dirty(struct folio *folio)
{ set_bit(PG_dirty, folio_flags(folio, FOLIO_PF_HEAD)); }
static __always_inline void SetPageDirty(struct page *page)
{ set_bit(PG_dirty, &PF_HEAD(page, 1)->flags); }
static __always_inline
void folio_clear_dirty(struct folio *folio)
{ clear_bit(PG_##dirty, folio_flags(folio, FOLIO_PF_HEAD)); }
static __always_inline void ClearPageDirty(struct page *page)
{ clear_bit(PG_##dirty, &PF_HEAD(page, 1)->flags); }
解析后的函数为别为
folio_test_dirty
PageDirty
folio_set_dirty
SetPageDirty
folio_clear_dirty
ClearPageDirty
3.1 进一步分析函数实现
以PageDirty为例
static __always_inline int PageDirty(struct page *page)
{ return test_bit(PG_dirty, &PF_HEAD(page, 0)->flags); }
根据宏定义
#define PF_POISONED_CHECK(page) ({ \
VM_BUG_ON_PGFLAGS(PagePoisoned(page), page); \
page; })
#define PF_HEAD(page, enforce) PF_POISONED_CHECK(compound_head(page))
进一步解析为
static __always_inline int PageDirty(struct page *page)
{ return test_bit(PG_dirty, &({
VM_BUG_ON_PGFLAGS(PagePoisoned(compound_head(page)), compound_head(page));
compound_head(page); })->flags); }
其中可以简化为如下定义
static __always_inline int PageDirty(struct page *page)
{ return test_bit(PG_dirty, &page->flags); }
page->flags
的定义为
include/linux/mm_types.h
struct page {
unsigned long flags; /* Atomic flags, some possibly
其类型为 enum pageflags
函数的第一个参数PG_dirty正是其中的一个bit位
4. 结论
所以PageDirty函数的作用是检测page->flags中是否将PG_dirty置位。