第62章 ページ記述子( struct page )

ページ記述子は物理ページと関連したオブジェクトです。

カーネル側としてはページ記述子が物理ページ・物理アドレスの情報を持っていてくれることで、システムにあるページの情報を把握することができます。

例えばページが未使用(未割り当て)なのか、使用中(割り当て済み)ならば誰が所有者なのかという情報も含まれます。

所有者については必ずしもユーザープロセスに限定されず、以下のようなケースもありえますね。

ではコードも見てみましょう。

ページ記述子は構造体としては複雑な方に部類されるかと…

まあ、とりあえず宣言・定義を見ちゃってくださいな。

// /usr/src/linux-headers-4.18.16-041816-generic/include/linux/mm_types.h
 70 struct page {
 71   unsigned long flags;    /* Atomic flags, some possibly
 72            * updated asynchronously */
 73   /*
 74    * Five words (20/40 bytes) are available in this union.
 75    * WARNING: bit 0 of the first word is used for PageTail(). That
 76    * means the other users of this union MUST NOT use the bit to
 77    * avoid collision and false-positive PageTail().
 78    */
 79   union {
 80     struct {  /* Page cache and anonymous pages */
 81       /**
 82        * @lru: Pageout list, eg. active_list protected by
 83        * zone_lru_lock.  Sometimes used as a generic list
 84        * by the page owner.
 85        */
 86       struct list_head lru;
 87       /* See page-flags.h for PAGE_MAPPING_FLAGS */
 88       struct address_space *mapping;
 89       pgoff_t index;    /* Our offset within mapping. */
 90       /**
 91        * @private: Mapping-private opaque data.
 92        * Usually used for buffer_heads if PagePrivate.
 93        * Used for swp_entry_t if PageSwapCache.
 94        * Indicates order in the buddy system if PageBuddy.
 95        */
 96       unsigned long private;
 97     };
 98     struct {  /* slab, slob and slub */
 99       union {
100         struct list_head slab_list; /* uses lru */
101         struct {  /* Partial pages */
102           struct page *next;
103 #ifdef CONFIG_64BIT
104           int pages;  /* Nr of pages left */
105           int pobjects; /* Approximate count */
106 #else
107           short int pages;
108           short int pobjects;
109 #endif
110         };
111       };
112       struct kmem_cache *slab_cache; /* not slob */
113       /* Double-word boundary */
114       void *freelist;   /* first free object */
115       union {
116         void *s_mem;  /* slab: first object */
117         unsigned long counters;   /* SLUB */
118         struct {      /* SLUB */
119           unsigned inuse:16;
120           unsigned objects:15;
121           unsigned frozen:1;
122         };
123       };
124     };
125     struct {  /* Tail pages of compound page */
126       unsigned long compound_head;  /* Bit zero is set */
127
128       /* First tail page only */
129       unsigned char compound_dtor;
130       unsigned char compound_order;
131       atomic_t compound_mapcount;
132     };
133     struct {  /* Second tail page of compound page */
134       unsigned long _compound_pad_1;  /* compound_head */
135       unsigned long _compound_pad_2;
136       struct list_head deferred_list;
137     };
138     struct {  /* Page table pages */
139       unsigned long _pt_pad_1;  /* compound_head */
140       pgtable_t pmd_huge_pte; /* protected by page->ptl */
141       unsigned long _pt_pad_2;  /* mapping */
142       union {
143         struct mm_struct *pt_mm; /* x86 pgds only */
144         atomic_t pt_frag_refcount; /* powerpc */
145       };
146 #if ALLOC_SPLIT_PTLOCKS
147       spinlock_t *ptl;
148 #else
149       spinlock_t ptl;
150 #endif
151     };
152     struct {  /* ZONE_DEVICE pages */
153       /** @pgmap: Points to the hosting device page map. */
154       struct dev_pagemap *pgmap;
155       unsigned long hmm_data;
156       unsigned long _zd_pad_1;  /* uses mapping */
157     };
158
159     /** @rcu_head: You can use this to free a page by RCU. */
160     struct rcu_head rcu_head;
161   };
162
163   union {   /* This union is 4 bytes in size. */
164     /*
165      * If the page can be mapped to userspace, encodes the number
166      * of times this page is referenced by a page table.
167      */
168     atomic_t _mapcount;
169
170     /*
171      * If the page is neither PageSlab nor mappable to userspace,
172      * the value stored here may help determine what this page
173      * is used for.  See page-flags.h for a list of page types
174      * which are currently stored here.
175      */
176     unsigned int page_type;
177
178     unsigned int active;    /* SLAB */
179     int units;      /* SLOB */
180   };
181
182   /* Usage count. *DO NOT USE DIRECTLY*. See page_ref.h */
183   atomic_t _refcount;
184
185 #ifdef CONFIG_MEMCG
186   struct mem_cgroup *mem_cgroup;
187 #endif
188
189   /*
190    * On machines where all RAM is mapped into kernel address space,
191    * we can simply calculate the virtual address. On machines with
192    * highmem some memory is mapped into kernel virtual memory
193    * dynamically, so we need a place to store that address.
194    * Note that this field could be 16 bits on x86 ... ;)
195    *
196    * Architectures with slow multiplication can define
197    * WANT_PAGE_VIRTUAL in asm/page.h
198    */
199 #if defined(WANT_PAGE_VIRTUAL)
200   void *virtual;      /* Kernel virtual address (NULL if
201              not kmapped, ie. highmem) */
202 #endif /* WANT_PAGE_VIRTUAL */
203
204 #ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
205   int _last_cpupid;
206 #endif
207 } _struct_page_alignment;

この中で特に重要なメンバー変数は flags です。

flags はページが dirty かロック状態か等の情報を保持します。

まあ dirty が何かどかロックどかは重要じゃないんで覚える必要は無いです。

それと _refcount はページへの参照の数をキープしてくれます。

virtual はページの仮想アドレスを保持します。

まあ、こんなもんですかね。

Copyright 2018-2019, by Masaki Komatsu