接下来就是page,该结构的定义如下:
悲剧,总算找着page的源码了,在include/linux/Mm_types.h里面,貌似很多参考资料都说在include/linux/mm.h里,坑爹啊,废话不多说了,上代码
- struct page {
- unsigned long flags; /* Atomic flags, some possibly
- * updated asynchronously */
- atomic_t _count; /* Usage count, see below. */
- union {
- atomic_t _mapcount; /* Count of ptes mapped in mms,
- * to show when page is mapped
- * & limit reverse map searches.
- */
- struct { /* SLUB */
- u16 inuse;
- u16 objects;
- };
- };
- union {
- struct {
- unsigned long private; /* Mapping-private opaque data:
- * usually used for buffer_heads
- * if PagePrivate set; used for
- * swp_entry_t if PageSwapCache;
- * indicates order in the buddy
- * system if PG_buddy is set.
- */
- struct address_space *mapping; /* If low bit clear, points to
- * inode address_space, or NULL.
- * If page mapped as anonymous
- * memory, low bit is set, and
- * it points to anon_vma object:
- * see PAGE_MAPPING_ANON below.
- */
- };
- #if USE_SPLIT_PTLOCKS
- spinlock_t ptl;
- #endif
- struct kmem_cache *slab; /* SLUB: Pointer to slab */
- struct page *first_page; /* Compound tail pages */
- };
- union {
- pgoff_t index; /* Our offset within mapping. */
- void *freelist; /* SLUB: freelist req. slab lock */
- };
- struct list_head lru; /* Pageout list, eg. active_list
- * protected by zone->lru_lock !
- */
- /*
- * On machines where all RAM is mapped into kernel address space,
- * we can simply calculate the virtual address. On machines with
- * highmem some memory is mapped into kernel virtual memory
- * dynamically, so we need a place to store that address.
- * Note that this field could be 16 bits on x86 ... ;)
- *
- * Architectures with slow multiplication can define
- * WANT_PAGE_VIRTUAL in asm/page.h
- */
- #if defined(WANT_PAGE_VIRTUAL)
- void *virtual; /* Kernel virtual address (NULL if
- not kmapped, ie. highmem) */
- #endif /* WANT_PAGE_VIRTUAL */
- #ifdef CONFIG_WANT_PAGE_DEBUG_FLAGS
- unsigned long debug_flags; /* Use atomic bitops on this */
- #endif
- #ifdef CONFIG_KMEMCHECK
- /*
- * kmemcheck wants to track the status of each byte in a page; this
- * is a pointer to such a status block. NULL if not tracked.
- */
- void *shadow;
- #endif
- };
page这个结构是比较值得仔细斟酌的,因为页帧是系统管理内存的最小单位,对于内存中的每个页都会创建struct page的一个实例,所以这个结构要尽量保持小,但是页帧在系统内部广泛使用,内核的很多部分都依赖页帧所提供的信息,但是这些信息也有可能对其他部分完全没有用。所以,用union来维护一些数据是比较合适的。另外,由于页帧的广泛使用,所以对其所作的任何修改都有可能导致保持所有page实例所需的内存暴涨。
下面简单讲解一下各个字段的意义:
- flags:描叙了体系结构无关的一些标志,用于描叙页的属性,定义如下:
- enum pageflags {
- PG_locked, /* Page is locked. Don't touch. */
- PG_error,
- PG_referenced,
- PG_uptodate,
- PG_dirty,
- PG_lru,
- PG_active,
- PG_slab,
- PG_owner_priv_1, /* Owner use. If pagecache, fs may use*/
- PG_arch_1,
- PG_reserved,
- PG_private, /* If pagecache, has fs-private data */
- PG_private_2, /* If pagecache, has fs aux data */
- PG_writeback, /* Page is under writeback */
- #ifdef CONFIG_PAGEFLAGS_EXTENDED
- PG_head, /* A head page */
- PG_tail, /* A tail page */
- #else
- PG_compound, /* A compound page */
- #endif
- PG_swapcache, /* Swap page: swp_entry_t in private */
- PG_mappedtodisk, /* Has blocks allocated on-disk */
- PG_reclaim, /* To be reclaimed asap */
- PG_swapbacked, /* Page is backed by RAM/swap */
- PG_unevictable, /* Page is "unevictable" */
- #ifdef CONFIG_MMU
- PG_mlocked, /* Page is vma mlocked */
- #endif
- #ifdef CONFIG_ARCH_USES_PG_UNCACHED
- PG_uncached, /* Page has been mapped as uncached */
- #endif
- #ifdef CONFIG_MEMORY_FAILURE
- PG_hwpoison, /* hardware poisoned page. Don't touch */
- #endif
- #ifdef CONFIG_TRANSPARENT_HUGEPAGE
- PG_compound_lock,
- #endif
- __NR_PAGEFLAGS,
- /* Filesystems */
- PG_checked = PG_owner_priv_1,
- /* Two page bits are conscripted by FS-Cache to maintain local caching
- * state. These bits are set on pages belonging to the netfs's inodes
- * when those inodes are being locally cached.
- */
- PG_fscache = PG_private_2, /* page backed by cache */
- /* XEN */
- PG_pinned = PG_owner_priv_1,
- PG_savepinned = PG_dirty,
- /* SLOB */
- PG_slob_free = PG_private,
- /* SLUB */
- PG_slub_frozen = PG_active,
- };
- PG_locked指定了页是否锁定。如果该位置位,内核的其他部分不允许访问该页
- PG_error如果在设计该页的I/O操作期间发生错误,则置该位
- PG_referenced和PG_active控制了系统使用该页的活动程度
- PG_update表示页的数据已经从块设备读取,没有出错
- PG_dirty如果内存页上的数据有修改,但是没有同步到硬盘上,则置位
- PG_lru内核用LRU算法来回收页帧,如果页在活动或不活动页链表其中一个,则设置该标志
- PG_high表示页在高端内存中,无法持久映射到内核内存中
- PG_writeback表示页的内容处于想块设备歇会的过程中
- PG_slab如果页是slab分配器的一部分,则设置PG_slab位
- PG_swapcache如果页处于交换缓存,则置位
- PG_reclaim如果内存打算回收某页,会设置该标志
- PG_buddy,若果空闲页包含在伙伴系统的列表中
- PG_compound表示页属于一个更大的复合页
同时,内核也提供了一些标准宏,用于检查标志位,或者操作某个标志位
- PageXXX(page)会检查是否设置了PG_XXX位,例如,PageDirty检查是否设置了PG_dirty位
- SetPageXXX会在比特位没有设置的情况下设置PG_XXX位,并返回原值
- ClearPageXXX无条件地清除某个特定的比特位
- TestClearPageXXX清除某个设置的比特位,并返回原值
- atomic_t _count 引用计数器,表示内核中引用该页的次数
- atomic_t _mapcount 表示在页表中有多少个pte指向该页
- struct { /* SLUB */
- u16 inuse;
- u16 objects;
- };
用于SLUB分配器,对象的数目- lru是一个表头,用于在各种链表上维护该页,一遍将页按照不同类别分组,主要是按照活动页和不活动页分组
- mapping 指定了页帧所在的地址空间。
- private是一个指向私有数据的指针
- virtual用于高端内存域中的页,
阅读(4001) | 评论(0) | 转发(0) |