Blame view

fs/proc/page.c 6.94 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
6d80e53f0   Alexey Dobriyan   proc: move pageco...
2
3
4
5
  #include <linux/bootmem.h>
  #include <linux/compiler.h>
  #include <linux/fs.h>
  #include <linux/init.h>
9a8408951   Hugh Dickins   ksm: identify Pag...
6
  #include <linux/ksm.h>
6d80e53f0   Alexey Dobriyan   proc: move pageco...
7
8
  #include <linux/mm.h>
  #include <linux/mmzone.h>
56873f43a   Wang, Yalin   mm:add KPF_ZERO_P...
9
  #include <linux/huge_mm.h>
6d80e53f0   Alexey Dobriyan   proc: move pageco...
10
11
  #include <linux/proc_fs.h>
  #include <linux/seq_file.h>
20a0307c0   Wu Fengguang   mm: introduce Pag...
12
  #include <linux/hugetlb.h>
80ae2fdce   Vladimir Davydov   proc: add kpagecg...
13
  #include <linux/memcontrol.h>
33c3fc71c   Vladimir Davydov   mm: introduce idl...
14
15
  #include <linux/mmu_notifier.h>
  #include <linux/page_idle.h>
1a9b5b7fe   Wu Fengguang   mm: export stable...
16
  #include <linux/kernel-page-flags.h>
7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
17
  #include <linux/uaccess.h>
6d80e53f0   Alexey Dobriyan   proc: move pageco...
18
19
20
21
  #include "internal.h"
  
  #define KPMSIZE sizeof(u64)
  #define KPMMASK (KPMSIZE - 1)
33c3fc71c   Vladimir Davydov   mm: introduce idl...
22
  #define KPMBITS (KPMSIZE * BITS_PER_BYTE)
ed7ce0f10   Wu Fengguang   proc: kpagecount/...
23

6d80e53f0   Alexey Dobriyan   proc: move pageco...
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  /* /proc/kpagecount - an array exposing page counts
   *
   * Each entry is a u64 representing the corresponding
   * physical page count.
   */
  static ssize_t kpagecount_read(struct file *file, char __user *buf,
  			     size_t count, loff_t *ppos)
  {
  	u64 __user *out = (u64 __user *)buf;
  	struct page *ppage;
  	unsigned long src = *ppos;
  	unsigned long pfn;
  	ssize_t ret = 0;
  	u64 pcount;
  
  	pfn = src / KPMSIZE;
  	count = min_t(size_t, count, (max_pfn * KPMSIZE) - src);
  	if (src & KPMMASK || count & KPMMASK)
  		return -EINVAL;
  
  	while (count > 0) {
6d80e53f0   Alexey Dobriyan   proc: move pageco...
45
46
  		if (pfn_valid(pfn))
  			ppage = pfn_to_page(pfn);
ed7ce0f10   Wu Fengguang   proc: kpagecount/...
47
48
  		else
  			ppage = NULL;
a6fc86d2b   Petr Holasek   kpagecount: add s...
49
  		if (!ppage || PageSlab(ppage))
6d80e53f0   Alexey Dobriyan   proc: move pageco...
50
51
52
  			pcount = 0;
  		else
  			pcount = page_mapcount(ppage);
ed7ce0f10   Wu Fengguang   proc: kpagecount/...
53
  		if (put_user(pcount, out)) {
6d80e53f0   Alexey Dobriyan   proc: move pageco...
54
55
56
  			ret = -EFAULT;
  			break;
  		}
ed7ce0f10   Wu Fengguang   proc: kpagecount/...
57
58
  		pfn++;
  		out++;
6d80e53f0   Alexey Dobriyan   proc: move pageco...
59
  		count -= KPMSIZE;
d3691d2c6   Vladimir Davydov   proc: add cond_re...
60
61
  
  		cond_resched();
6d80e53f0   Alexey Dobriyan   proc: move pageco...
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
  	}
  
  	*ppos += (char __user *)out - buf;
  	if (!ret)
  		ret = (char __user *)out - buf;
  	return ret;
  }
  
  static const struct file_operations proc_kpagecount_operations = {
  	.llseek = mem_lseek,
  	.read = kpagecount_read,
  };
  
  /* /proc/kpageflags - an array exposing page flags
   *
   * Each entry is a u64 representing the corresponding
   * physical page flags.
   */
177975495   Wu Fengguang   proc: export more...
80
81
82
83
  static inline u64 kpf_copy_bit(u64 kflags, int ubit, int kbit)
  {
  	return ((kflags >> kbit) & 1) << ubit;
  }
1a9b5b7fe   Wu Fengguang   mm: export stable...
84
  u64 stable_page_flags(struct page *page)
177975495   Wu Fengguang   proc: export more...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
  {
  	u64 k;
  	u64 u;
  
  	/*
  	 * pseudo flag: KPF_NOPAGE
  	 * it differentiates a memory hole from a page with no flags
  	 */
  	if (!page)
  		return 1 << KPF_NOPAGE;
  
  	k = page->flags;
  	u = 0;
  
  	/*
  	 * pseudo flags for the well known (anonymous) memory mapped pages
  	 *
  	 * Note that page->_mapcount is overloaded in SLOB/SLUB/SLQB, so the
832fc1de0   Naoya Horiguchi   /proc/kpageflags:...
103
  	 * simple test in page_mapped() is not enough.
177975495   Wu Fengguang   proc: export more...
104
  	 */
832fc1de0   Naoya Horiguchi   /proc/kpageflags:...
105
  	if (!PageSlab(page) && page_mapped(page))
177975495   Wu Fengguang   proc: export more...
106
107
108
  		u |= 1 << KPF_MMAP;
  	if (PageAnon(page))
  		u |= 1 << KPF_ANON;
9a8408951   Hugh Dickins   ksm: identify Pag...
109
110
  	if (PageKsm(page))
  		u |= 1 << KPF_KSM;
177975495   Wu Fengguang   proc: export more...
111
112
113
114
115
116
117
118
119
120
121
  
  	/*
  	 * compound pages: export both head/tail info
  	 * they together define a compound page's start/end pos and order
  	 */
  	if (PageHead(page))
  		u |= 1 << KPF_COMPOUND_HEAD;
  	if (PageTail(page))
  		u |= 1 << KPF_COMPOUND_TAIL;
  	if (PageHuge(page))
  		u |= 1 << KPF_HUGE;
7a71932d5   Naoya Horiguchi   kpageflags: fix w...
122
123
124
  	/*
  	 * PageTransCompound can be true for non-huge compound pages (slab
  	 * pages or pages allocated by drivers with __GFP_COMP) because it
e3bba3c3c   Naoya Horiguchi   fs/proc/page.c: a...
125
126
  	 * just checks PG_head/PG_tail, so we need to check PageLRU/PageAnon
  	 * to make sure a given page is a thp, not a non-huge compound page.
7a71932d5   Naoya Horiguchi   kpageflags: fix w...
127
  	 */
56873f43a   Wang, Yalin   mm:add KPF_ZERO_P...
128
129
130
131
132
133
134
135
136
137
138
  	else if (PageTransCompound(page)) {
  		struct page *head = compound_head(page);
  
  		if (PageLRU(head) || PageAnon(head))
  			u |= 1 << KPF_THP;
  		else if (is_huge_zero_page(head)) {
  			u |= 1 << KPF_ZERO_PAGE;
  			u |= 1 << KPF_THP;
  		}
  	} else if (is_zero_pfn(page_to_pfn(page)))
  		u |= 1 << KPF_ZERO_PAGE;
177975495   Wu Fengguang   proc: export more...
139

177975495   Wu Fengguang   proc: export more...
140
  	/*
0139aa7b7   Joonsoo Kim   mm: rename _count...
141
  	 * Caveats on high order pages: page->_refcount will only be set
5f24ce5fd   Andrea Arcangeli   thp: remove PG_buddy
142
143
  	 * -1 on the head page; SLUB/SLQB do the same for PG_slab;
  	 * SLOB won't set PG_slab at all on compound pages.
177975495   Wu Fengguang   proc: export more...
144
  	 */
5f24ce5fd   Andrea Arcangeli   thp: remove PG_buddy
145
146
  	if (PageBuddy(page))
  		u |= 1 << KPF_BUDDY;
832fc1de0   Naoya Horiguchi   /proc/kpageflags:...
147
148
  	else if (page_count(page) == 0 && is_free_buddy_page(page))
  		u |= 1 << KPF_BUDDY;
5f24ce5fd   Andrea Arcangeli   thp: remove PG_buddy
149

09316c09d   Konstantin Khlebnikov   mm/balloon_compac...
150
151
  	if (PageBalloon(page))
  		u |= 1 << KPF_BALLOON;
f074a8f49   Vladimir Davydov   proc: export idle...
152
153
  	if (page_is_idle(page))
  		u |= 1 << KPF_IDLE;
5f24ce5fd   Andrea Arcangeli   thp: remove PG_buddy
154
  	u |= kpf_copy_bit(k, KPF_LOCKED,	PG_locked);
177975495   Wu Fengguang   proc: export more...
155
  	u |= kpf_copy_bit(k, KPF_SLAB,		PG_slab);
0a71649cb   Naoya Horiguchi   /proc/kpageflags:...
156
157
  	if (PageTail(page) && PageSlab(compound_head(page)))
  		u |= 1 << KPF_SLAB;
177975495   Wu Fengguang   proc: export more...
158
159
160
161
162
163
164
165
166
167
  
  	u |= kpf_copy_bit(k, KPF_ERROR,		PG_error);
  	u |= kpf_copy_bit(k, KPF_DIRTY,		PG_dirty);
  	u |= kpf_copy_bit(k, KPF_UPTODATE,	PG_uptodate);
  	u |= kpf_copy_bit(k, KPF_WRITEBACK,	PG_writeback);
  
  	u |= kpf_copy_bit(k, KPF_LRU,		PG_lru);
  	u |= kpf_copy_bit(k, KPF_REFERENCED,	PG_referenced);
  	u |= kpf_copy_bit(k, KPF_ACTIVE,	PG_active);
  	u |= kpf_copy_bit(k, KPF_RECLAIM,	PG_reclaim);
b6789123b   Hugh Dickins   mm: fix KPF_SWAPC...
168
169
  	if (PageSwapCache(page))
  		u |= 1 << KPF_SWAPCACHE;
177975495   Wu Fengguang   proc: export more...
170
  	u |= kpf_copy_bit(k, KPF_SWAPBACKED,	PG_swapbacked);
177975495   Wu Fengguang   proc: export more...
171
172
  	u |= kpf_copy_bit(k, KPF_UNEVICTABLE,	PG_unevictable);
  	u |= kpf_copy_bit(k, KPF_MLOCKED,	PG_mlocked);
177975495   Wu Fengguang   proc: export more...
173

253fb02d6   Wu Fengguang   pagemap: export K...
174
175
176
  #ifdef CONFIG_MEMORY_FAILURE
  	u |= kpf_copy_bit(k, KPF_HWPOISON,	PG_hwpoison);
  #endif
ed430fec7   Takashi Iwai   proc: export unca...
177
  #ifdef CONFIG_ARCH_USES_PG_UNCACHED
177975495   Wu Fengguang   proc: export more...
178
179
180
181
182
183
184
185
186
187
188
189
  	u |= kpf_copy_bit(k, KPF_UNCACHED,	PG_uncached);
  #endif
  
  	u |= kpf_copy_bit(k, KPF_RESERVED,	PG_reserved);
  	u |= kpf_copy_bit(k, KPF_MAPPEDTODISK,	PG_mappedtodisk);
  	u |= kpf_copy_bit(k, KPF_PRIVATE,	PG_private);
  	u |= kpf_copy_bit(k, KPF_PRIVATE_2,	PG_private_2);
  	u |= kpf_copy_bit(k, KPF_OWNER_PRIVATE,	PG_owner_priv_1);
  	u |= kpf_copy_bit(k, KPF_ARCH,		PG_arch_1);
  
  	return u;
  };
6d80e53f0   Alexey Dobriyan   proc: move pageco...
190
191
192
193
194
195
196
197
198
  
  static ssize_t kpageflags_read(struct file *file, char __user *buf,
  			     size_t count, loff_t *ppos)
  {
  	u64 __user *out = (u64 __user *)buf;
  	struct page *ppage;
  	unsigned long src = *ppos;
  	unsigned long pfn;
  	ssize_t ret = 0;
6d80e53f0   Alexey Dobriyan   proc: move pageco...
199
200
201
202
203
204
205
  
  	pfn = src / KPMSIZE;
  	count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src);
  	if (src & KPMMASK || count & KPMMASK)
  		return -EINVAL;
  
  	while (count > 0) {
6d80e53f0   Alexey Dobriyan   proc: move pageco...
206
207
  		if (pfn_valid(pfn))
  			ppage = pfn_to_page(pfn);
ed7ce0f10   Wu Fengguang   proc: kpagecount/...
208
209
  		else
  			ppage = NULL;
177975495   Wu Fengguang   proc: export more...
210

1a9b5b7fe   Wu Fengguang   mm: export stable...
211
  		if (put_user(stable_page_flags(ppage), out)) {
6d80e53f0   Alexey Dobriyan   proc: move pageco...
212
213
214
  			ret = -EFAULT;
  			break;
  		}
ed7ce0f10   Wu Fengguang   proc: kpagecount/...
215
216
  		pfn++;
  		out++;
6d80e53f0   Alexey Dobriyan   proc: move pageco...
217
  		count -= KPMSIZE;
d3691d2c6   Vladimir Davydov   proc: add cond_re...
218
219
  
  		cond_resched();
6d80e53f0   Alexey Dobriyan   proc: move pageco...
220
221
222
223
224
225
226
227
228
229
230
231
  	}
  
  	*ppos += (char __user *)out - buf;
  	if (!ret)
  		ret = (char __user *)out - buf;
  	return ret;
  }
  
  static const struct file_operations proc_kpageflags_operations = {
  	.llseek = mem_lseek,
  	.read = kpageflags_read,
  };
80ae2fdce   Vladimir Davydov   proc: add kpagecg...
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
  #ifdef CONFIG_MEMCG
  static ssize_t kpagecgroup_read(struct file *file, char __user *buf,
  				size_t count, loff_t *ppos)
  {
  	u64 __user *out = (u64 __user *)buf;
  	struct page *ppage;
  	unsigned long src = *ppos;
  	unsigned long pfn;
  	ssize_t ret = 0;
  	u64 ino;
  
  	pfn = src / KPMSIZE;
  	count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src);
  	if (src & KPMMASK || count & KPMMASK)
  		return -EINVAL;
  
  	while (count > 0) {
  		if (pfn_valid(pfn))
  			ppage = pfn_to_page(pfn);
  		else
  			ppage = NULL;
  
  		if (ppage)
  			ino = page_cgroup_ino(ppage);
  		else
  			ino = 0;
  
  		if (put_user(ino, out)) {
  			ret = -EFAULT;
  			break;
  		}
  
  		pfn++;
  		out++;
  		count -= KPMSIZE;
d3691d2c6   Vladimir Davydov   proc: add cond_re...
267
268
  
  		cond_resched();
80ae2fdce   Vladimir Davydov   proc: add kpagecg...
269
270
271
272
273
274
275
276
277
278
279
280
281
  	}
  
  	*ppos += (char __user *)out - buf;
  	if (!ret)
  		ret = (char __user *)out - buf;
  	return ret;
  }
  
  static const struct file_operations proc_kpagecgroup_operations = {
  	.llseek = mem_lseek,
  	.read = kpagecgroup_read,
  };
  #endif /* CONFIG_MEMCG */
6d80e53f0   Alexey Dobriyan   proc: move pageco...
282
283
284
285
  static int __init proc_page_init(void)
  {
  	proc_create("kpagecount", S_IRUSR, NULL, &proc_kpagecount_operations);
  	proc_create("kpageflags", S_IRUSR, NULL, &proc_kpageflags_operations);
80ae2fdce   Vladimir Davydov   proc: add kpagecg...
286
287
288
  #ifdef CONFIG_MEMCG
  	proc_create("kpagecgroup", S_IRUSR, NULL, &proc_kpagecgroup_operations);
  #endif
6d80e53f0   Alexey Dobriyan   proc: move pageco...
289
290
  	return 0;
  }
abaf3787a   Paul Gortmaker   fs/proc: don't us...
291
  fs_initcall(proc_page_init);