2、linux page结构体详解

209 阅读3分钟

linux内核把物理页作为内存管理的基本单位。MMU通常是以页为单位来查找页表,内核用 struct page结构体来表示系统的每个页。不同的体系支持的页大小不同。arm64处理器支持3种页长度:4KB、16KB、64KB。

linux内核将整个物理内存按照页对齐方式划分成千上万个页进行管理。由于一个物理页用一个struct page表示,那么系统会有成千上万个struct page结构体,这些结构体也会占用实际的物理内存。因此,内核选择用union联合体来减少内存的使用。

在linux内核版本5.0中,page结构体成员如下:

struct page {
        unsigned long flags;            /* Atomic flags, some possibly
                                         * updated asynchronously */
        /*
         * Five words (20/40 bytes) are available in this union.
         * WARNING: bit 0 of the first word is used for PageTail(). That
         * means the other users of this union MUST NOT use the bit to
         * avoid collision and false-positive PageTail().
         */
        union {
                struct {        /* Page cache and anonymous pages */
                        /**
                         * @lru: Pageout list, eg. active_list protected by
                         * zone_lru_lock.  Sometimes used as a generic list
                         * by the page owner.
                         */
                        struct list_head lru;
                        /* See page-flags.h for PAGE_MAPPING_FLAGS */
                        struct address_space *mapping;
                        pgoff_t index;          /* Our offset within mapping. */
                        /**
                         * @private: Mapping-private opaque data.
                         * Usually used for buffer_heads if PagePrivate.
                         * Used for swp_entry_t if PageSwapCache.
                         * Indicates order in the buddy system if PageBuddy.
                         */
                        unsigned long private;
                };
                struct {        /* slab, slob and slub */
                        union {
                                struct list_head slab_list;     /* uses lru */
                                struct {        /* Partial pages */
                                        struct page *next;
#ifdef CONFIG_64BIT
                                        int pages;      /* Nr of pages left */
                                        int pobjects;   /* Approximate count */
#else
                                        short int pages;
                                        short int pobjects;
#endif
                                };
                        };
                        struct kmem_cache *slab_cache; /* not slob */
                        /* Double-word boundary */
                        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 */
                        };
#if ALLOC_SPLIT_PTLOCKS
                        spinlock_t *ptl;
#else
                        spinlock_t ptl;
#endif
                };
                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 */
                };

                /** @rcu_head: You can use this to free a page by RCU. */
                struct rcu_head rcu_head;
        };

        union {         /* This union is 4 bytes in size. */
                /*
                 * If the page can be mapped to userspace, encodes the number
                 * of times this page is referenced by a page table.
                 */
                atomic_t _mapcount;

                /*
                 * If the page is neither PageSlab nor mappable to userspace,
                 * the value stored here may help determine what this page
                 * is used for.  See page-flags.h for a list of page types
                 * which are currently stored here.
                 */
                unsigned int page_type;

                unsigned int active;            /* SLAB */
                int units;                      /* SLOB */
        };

        /* Usage count. *DO NOT USE DIRECTLY*. See page_ref.h */
        atomic_t _refcount;

#ifdef CONFIG_MEMCG
        struct mem_cgroup *mem_cgroup;
#endif

        /*
         * 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 LAST_CPUPID_NOT_IN_PAGE_FLAGS
        int _last_cpupid;
#endif
} _struct_page_alignment;

通过crash工具查看,page结构体大小占64bytes:

crash> struct page -o
struct page {
   [0] unsigned long flags;
       union {
           struct {
   [8]         struct list_head lru;
  [24]         struct address_space *mapping;
  [32]         unsigned long index;
  [40]         unsigned long private;
           };
           struct {
               union {
   [8]             struct list_head slab_list;
                   struct {
   [8]                 struct page *next;
  [16]                 int pages;
  [20]                 int pobjects;
                   };
               };
  [24]         struct kmem_cache *slab_cache;
  [32]         void *freelist;
               union {
  [40]             void *s_mem;
  [40]             unsigned long counters;
                   struct {
  [40]                 unsigned int inuse : 16;
  [42]                 unsigned int objects : 15;
  [43]                 unsigned int frozen : 1;
                   };
               };
           };
           struct {
   [8]         unsigned long compound_head;
  [16]         unsigned char compound_dtor;
  [17]         unsigned char compound_order;
  [20]         atomic_t compound_mapcount;
           };
           struct {
   [8]         unsigned long _compound_pad_1;
  [16]         unsigned long _compound_pad_2;
  [24]         struct list_head deferred_list;
           };
           struct {
   [8]         unsigned long _pt_pad_1;
  [16]         pgtable_t pmd_huge_pte;
  [24]         unsigned long _pt_pad_2;
               union {
  [32]             struct mm_struct *pt_mm;
  [32]             atomic_t pt_frag_refcount;
               };
  [40]         spinlock_t ptl;
           };
           struct {
   [8]         struct dev_pagemap *pgmap;
  [16]         unsigned long hmm_data;
  [24]         unsigned long _zd_pad_1;
           };
   [8]     struct callback_head callback_head;
       };
       union {
  [48]     atomic_t _mapcount;
  [48]     unsigned int page_type;
  [48]     unsigned int active;
  [48]     int units;
       };
  [52] atomic_t _refcount;
  [56] struct mem_cgroup *mem_cgroup;
}
SIZE: 64

page结构体每个字段的含义: www.processon.com/view/link/6…