linux 的 page 结构体的一点笔记

来源:互联网 发布:中美合作 规范网络 编辑:程序博客网 时间:2024/05/01 16:04

http://bbs.bccn.net/thread-374463-1-1.html

Linux的内核在内存管理中处理的最小单位是physical pages

然而处理器的的最小的可寻址的单位是byte 或者是 word

很多32位系统构架都是4k的页,64位则是8k的页

所以对于4k的页,1G的内存就有262144个不同的页

内核通过struct page 结构体来表示每一个页,定义在<linux/mm_types.h>中

程序代码:
/*
* Each physical page in the system has a struct page associated with
* it to keep track of whatever it is we are using the page for at the
* moment. Note that we have no way to track which tasks are using
* a page, though if it is a pagecache page, rmap structures can tell us
* who is mapping it.
*/
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
};


flags 里面存储勒页的状态,比如这个页是不是dirty啊,

是不是locked in memory啊

它是用bit flags来表示这些不同的值

flags的值则被定义在了<linux/page-flags.h>里面
程序代码:
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_buddy,        /* Page is free, on buddy lists */
    PG_swapbacked,        /* Page is backed by RAM/swap */
    PG_unevictable,        /* Page is "unevictable"  */
#ifdef CONFIG_HAVE_MLOCKED_PAGE_BIT
    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
    __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_slub_debug = PG_error,
};

page 结构体中的_count 则表示和这个页关联的references,

当为-1时,则表示没人在用这个页了

当然内核不会直接检查这一项,而是通过page_count()函数来检查

返回0则表示page free

page还可以被page cache 使用,(这种情况时

mapping field points to the address_space object associated with this page

上面不怎么懂,一会儿看一下page cache)

也可以作为private data,也可以as  a mapping in a process's page table

virtual 里面是page的 virtual address ,这里还有一些high memory 的问题,

接下来弄明白
 


有一点很重要,page 结构体是和physical pages相关联的,

不是virtual address

即使page里面的内容也许会继续存在下去,但因为swapping之类的东西的原因


it might not always be associated with the same page structure 

这个结构体的目标是描述物理内存,而不是里面的数据。

假设page 结构体40 字节的大小, 对于8k的physical pages,

在 4G内存上则有524288个页,所以页结构体则消耗20MB左右的空间。Fair enough

0 0
原创粉丝点击