struct page
struct page {
unsigned long flags;
union {
struct { /* Page cache and anonymous pages */
struct list_head lru;
struct address_space *mapping;
pgoff_t index; /* Our offset within mapping. */
unsigned long private;
};
struct { /* slab, slob and slub */
union {
struct list_head slab_list; /* uses lru */
struct { /* Partial pages */
struct page *next;
int pages; /* Nr of pages left */
int pobjects; /* Approximate count */
};
};
struct kmem_cache *slab_cache; /* not slob */
void *freelist; /* first free object */
union {
void *s_mem; /* slab: first object */
unsigned long counters; /* SLUB */
struct { /* SLUB */
unsigned inuse:16;
unsigned objects:15;
unsigned frozen:1;
};
};
};
struct { /* Tail pages of compound page */
unsigned long compound_head; /* Bit zero is set */
/* First tail page only */
unsigned char compound_dtor;
unsigned char compound_order;
atomic_t compound_mapcount;
};
struct { /* Second tail page of compound page */
unsigned long _compound_pad_1; /* compound_head */
unsigned long _compound_pad_2;
struct list_head deferred_list;
};
struct { /* Page table pages */
unsigned long _pt_pad_1; /* compound_head */
pgtable_t pmd_huge_pte; /* protected by page->ptl */
unsigned long _pt_pad_2; /* mapping */
union {
struct mm_struct *pt_mm; /* x86 pgds only */
atomic_t pt_frag_refcount; /* powerpc */
};
spinlock_t *ptl;
};
struct { /* ZONE_DEVICE pages */
/** @pgmap: Points to the hosting device page map. */
struct dev_pagemap *pgmap;
unsigned long hmm_data;
unsigned long _zd_pad_1; /* uses mapping */
};
struct rcu_head rcu_head; /** @rcu_head: You can use this to free a page by RCU. */
};
union { /* This union is 4 bytes in size. */
atomic_t _mapcount;
unsigned int page_type;
unsigned int active; /* SLAB */
int units; /* SLOB */
};
atomic_t _refcount;
struct mem_cgroup *mem_cgroup;
void *virtual; /* Kernel virtual address (NULL if not kmapped, ie. highmem) */
int _last_cpupid;
} _struct_page_alignment;
page flags标志
enum pageflags {
PG_locked, // 表示页面已经上锁了。如果该比特位置位,说明页面已经被锁定;内存管理其他模块不能访问这个页面,以防发生竞争。
PG_referenced, // 表示页面刚被访问过,控制页面活跃程度,在kswapd页面回收中使用。
PG_uptodate, // 表示page的数据已经与后备存储器是同步的。即页的数据已经从块设备读取,且没有出错,数据是最新的。
PG_dirty, // 表示页面内容发生改变,页面为脏,页面内容被改写后还没有和外部存储器进行同步操作。
PG_lru, // 表示页面加入了LRU链表,内核使用LRU链表管理活跃和不活跃页面。
PG_active, // 表示page处于inactive LRU链表,控制页面活跃程度,在kswapd页面回收中使用。
PG_workingset,
PG_waiters, // 页面有等待者,请检查其等待队列。本标志必须是bit7,并且与“ PG_locked”在同一字节中。
PG_error, // 页面操作过程中发生错误会设置该位。
PG_slab, // 用于slab分配器
PG_owner_priv_1, // 页面的所有者使用,如果是page cache页面,文件系统可能使用。
PG_arch_1, // 特定体系结构的页面状态位。一般的代码保证当页面首次进入页面缓存时,该位将被清除。
PG_reserved, // 表示该页不可被换出。
PG_private, // 表示该页是有效的,如果页面是page cache,那么包含一些文件系统相关的数据信息。
PG_private_2, // 如果是page cache,可能包含fs aux data。
PG_writeback, // 表示页面的内容正在向块设备进行回写。
PG_head, /* A head page */
PG_mappedtodisk, // Has blocks allocated on-disk
PG_reclaim, // 表示该页马上要被回收。
PG_swapbacked, // 表示该page的后备存储器是swap,通常匿名页面才可以写回swap分区。
PG_unevictable, // 表示页面不可回收。
PG_mlocked, // 表示页面对应的VMA处于locked状态。
PG_plink, /* page linked to a process */
PG_uncached, // Page has been mapped as uncached
PG_hwpoison, // hardware poisoned page. Don't touch
PG_young,
PG_idle,
PG_vital,
PG_staple,
PG_candi,
__NR_PAGEFLAGS,
PG_checked = PG_owner_priv_1, /* Filesystems */
PG_swapcache, // 表示页面处于交换缓存
PG_fscache = PG_private_2, /* page backed by cache */
PG_pinned = PG_owner_priv_1, /* Pinned in Xen as a read-only pagetable page. */
PG_savepinned = PG_dirty, /* Pinned as part of domain save (see xen_mm_pin_all()). */
PG_foreign = PG_owner_priv_1, /* Has a grant mapping of another (foreign) domain's page. */
PG_slob_free = PG_private, /* SLOB */
PG_double_map = PG_private_2, /* Compound pages. Stored in first tail page's flags */
PG_isolated = PG_reclaim, /* non-lru isolated movable page */
}
struct page数据结构成员flags定义了一个标志位PG_locked,内核利用PG_locked来设置一个页面锁。lock_page()函数用于申请页面锁,如果页面锁被其他进程占用了,那么会睡眠等待。
1)__lock_page(struct page *__page)
用于申请页面锁,若page被其他进程使用,则需要睡眠等待
2)trylock_page(struct page *page)
用于尝试申请页面锁,若page被其他进程使用,则直接返回false
test_and_set_bit函数详解:
test_and_set_bit(unsigned int nr, volatile unsigned long *p)
功能:设置指针p的第nr bit为1,然后返回指针p原来的nr bit的值
-->1)unsigned long mask = BIT_MASK(nr)
mask的nr bit值为1
-->2)p += BIT_WORD(nr)
一般BIT_WORD(nr)为0
-->3)if (READ_ONCE(*p) & mask) return 1;
判断指针p的第nr bit若为1,则直接返回1
-->4)old = atomic_long_fetch_or(mask, (atomic_long_t *)p)
给指针p与mask进行or运算,并返回指针p原来的nr bit值
-->5)return !!(old & mask)
返回指针p原来nr bit位的值