.. | .. |
---|
1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
---|
2 | | -#include <linux/bootmem.h> |
---|
| 2 | +#include <linux/memblock.h> |
---|
3 | 3 | #include <linux/compiler.h> |
---|
4 | 4 | #include <linux/fs.h> |
---|
5 | 5 | #include <linux/init.h> |
---|
.. | .. |
---|
21 | 21 | #define KPMMASK (KPMSIZE - 1) |
---|
22 | 22 | #define KPMBITS (KPMSIZE * BITS_PER_BYTE) |
---|
23 | 23 | |
---|
| 24 | +static inline unsigned long get_max_dump_pfn(void) |
---|
| 25 | +{ |
---|
| 26 | +#ifdef CONFIG_SPARSEMEM |
---|
| 27 | + /* |
---|
| 28 | + * The memmap of early sections is completely populated and marked |
---|
| 29 | + * online even if max_pfn does not fall on a section boundary - |
---|
| 30 | + * pfn_to_online_page() will succeed on all pages. Allow inspecting |
---|
| 31 | + * these memmaps. |
---|
| 32 | + */ |
---|
| 33 | + return round_up(max_pfn, PAGES_PER_SECTION); |
---|
| 34 | +#else |
---|
| 35 | + return max_pfn; |
---|
| 36 | +#endif |
---|
| 37 | +} |
---|
| 38 | + |
---|
24 | 39 | /* /proc/kpagecount - an array exposing page counts |
---|
25 | 40 | * |
---|
26 | 41 | * Each entry is a u64 representing the corresponding |
---|
.. | .. |
---|
29 | 44 | static ssize_t kpagecount_read(struct file *file, char __user *buf, |
---|
30 | 45 | size_t count, loff_t *ppos) |
---|
31 | 46 | { |
---|
| 47 | + const unsigned long max_dump_pfn = get_max_dump_pfn(); |
---|
32 | 48 | u64 __user *out = (u64 __user *)buf; |
---|
33 | 49 | struct page *ppage; |
---|
34 | 50 | unsigned long src = *ppos; |
---|
.. | .. |
---|
37 | 53 | u64 pcount; |
---|
38 | 54 | |
---|
39 | 55 | pfn = src / KPMSIZE; |
---|
40 | | - count = min_t(size_t, count, (max_pfn * KPMSIZE) - src); |
---|
41 | 56 | if (src & KPMMASK || count & KPMMASK) |
---|
42 | 57 | return -EINVAL; |
---|
| 58 | + if (src >= max_dump_pfn * KPMSIZE) |
---|
| 59 | + return 0; |
---|
| 60 | + count = min_t(unsigned long, count, (max_dump_pfn * KPMSIZE) - src); |
---|
43 | 61 | |
---|
44 | 62 | while (count > 0) { |
---|
45 | 63 | /* |
---|
.. | .. |
---|
48 | 66 | */ |
---|
49 | 67 | ppage = pfn_to_online_page(pfn); |
---|
50 | 68 | |
---|
51 | | - if (!ppage || PageSlab(ppage)) |
---|
| 69 | + if (!ppage || PageSlab(ppage) || page_has_type(ppage)) |
---|
52 | 70 | pcount = 0; |
---|
53 | 71 | else |
---|
54 | 72 | pcount = page_mapcount(ppage); |
---|
.. | .. |
---|
71 | 89 | return ret; |
---|
72 | 90 | } |
---|
73 | 91 | |
---|
74 | | -static const struct file_operations proc_kpagecount_operations = { |
---|
75 | | - .llseek = mem_lseek, |
---|
76 | | - .read = kpagecount_read, |
---|
| 92 | +static const struct proc_ops kpagecount_proc_ops = { |
---|
| 93 | + .proc_lseek = mem_lseek, |
---|
| 94 | + .proc_read = kpagecount_read, |
---|
77 | 95 | }; |
---|
78 | 96 | |
---|
79 | 97 | /* /proc/kpageflags - an array exposing page flags |
---|
.. | .. |
---|
154 | 172 | else if (page_count(page) == 0 && is_free_buddy_page(page)) |
---|
155 | 173 | u |= 1 << KPF_BUDDY; |
---|
156 | 174 | |
---|
157 | | - if (PageBalloon(page)) |
---|
158 | | - u |= 1 << KPF_BALLOON; |
---|
| 175 | + if (PageOffline(page)) |
---|
| 176 | + u |= 1 << KPF_OFFLINE; |
---|
159 | 177 | if (PageTable(page)) |
---|
160 | 178 | u |= 1 << KPF_PGTABLE; |
---|
161 | 179 | |
---|
.. | .. |
---|
199 | 217 | u |= kpf_copy_bit(k, KPF_PRIVATE_2, PG_private_2); |
---|
200 | 218 | u |= kpf_copy_bit(k, KPF_OWNER_PRIVATE, PG_owner_priv_1); |
---|
201 | 219 | u |= kpf_copy_bit(k, KPF_ARCH, PG_arch_1); |
---|
| 220 | +#ifdef CONFIG_64BIT |
---|
| 221 | + u |= kpf_copy_bit(k, KPF_ARCH_2, PG_arch_2); |
---|
| 222 | +#endif |
---|
202 | 223 | |
---|
203 | 224 | return u; |
---|
204 | 225 | }; |
---|
.. | .. |
---|
206 | 227 | static ssize_t kpageflags_read(struct file *file, char __user *buf, |
---|
207 | 228 | size_t count, loff_t *ppos) |
---|
208 | 229 | { |
---|
| 230 | + const unsigned long max_dump_pfn = get_max_dump_pfn(); |
---|
209 | 231 | u64 __user *out = (u64 __user *)buf; |
---|
210 | 232 | struct page *ppage; |
---|
211 | 233 | unsigned long src = *ppos; |
---|
.. | .. |
---|
213 | 235 | ssize_t ret = 0; |
---|
214 | 236 | |
---|
215 | 237 | pfn = src / KPMSIZE; |
---|
216 | | - count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src); |
---|
217 | 238 | if (src & KPMMASK || count & KPMMASK) |
---|
218 | 239 | return -EINVAL; |
---|
| 240 | + if (src >= max_dump_pfn * KPMSIZE) |
---|
| 241 | + return 0; |
---|
| 242 | + count = min_t(unsigned long, count, (max_dump_pfn * KPMSIZE) - src); |
---|
219 | 243 | |
---|
220 | 244 | while (count > 0) { |
---|
221 | 245 | /* |
---|
.. | .. |
---|
242 | 266 | return ret; |
---|
243 | 267 | } |
---|
244 | 268 | |
---|
245 | | -static const struct file_operations proc_kpageflags_operations = { |
---|
246 | | - .llseek = mem_lseek, |
---|
247 | | - .read = kpageflags_read, |
---|
| 269 | +static const struct proc_ops kpageflags_proc_ops = { |
---|
| 270 | + .proc_lseek = mem_lseek, |
---|
| 271 | + .proc_read = kpageflags_read, |
---|
248 | 272 | }; |
---|
249 | 273 | |
---|
250 | 274 | #ifdef CONFIG_MEMCG |
---|
251 | 275 | static ssize_t kpagecgroup_read(struct file *file, char __user *buf, |
---|
252 | 276 | size_t count, loff_t *ppos) |
---|
253 | 277 | { |
---|
| 278 | + const unsigned long max_dump_pfn = get_max_dump_pfn(); |
---|
254 | 279 | u64 __user *out = (u64 __user *)buf; |
---|
255 | 280 | struct page *ppage; |
---|
256 | 281 | unsigned long src = *ppos; |
---|
.. | .. |
---|
259 | 284 | u64 ino; |
---|
260 | 285 | |
---|
261 | 286 | pfn = src / KPMSIZE; |
---|
262 | | - count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src); |
---|
263 | 287 | if (src & KPMMASK || count & KPMMASK) |
---|
264 | 288 | return -EINVAL; |
---|
| 289 | + if (src >= max_dump_pfn * KPMSIZE) |
---|
| 290 | + return 0; |
---|
| 291 | + count = min_t(unsigned long, count, (max_dump_pfn * KPMSIZE) - src); |
---|
265 | 292 | |
---|
266 | 293 | while (count > 0) { |
---|
267 | 294 | /* |
---|
.. | .. |
---|
293 | 320 | return ret; |
---|
294 | 321 | } |
---|
295 | 322 | |
---|
296 | | -static const struct file_operations proc_kpagecgroup_operations = { |
---|
297 | | - .llseek = mem_lseek, |
---|
298 | | - .read = kpagecgroup_read, |
---|
| 323 | +static const struct proc_ops kpagecgroup_proc_ops = { |
---|
| 324 | + .proc_lseek = mem_lseek, |
---|
| 325 | + .proc_read = kpagecgroup_read, |
---|
299 | 326 | }; |
---|
300 | 327 | #endif /* CONFIG_MEMCG */ |
---|
301 | 328 | |
---|
302 | 329 | static int __init proc_page_init(void) |
---|
303 | 330 | { |
---|
304 | | - proc_create("kpagecount", S_IRUSR, NULL, &proc_kpagecount_operations); |
---|
305 | | - proc_create("kpageflags", S_IRUSR, NULL, &proc_kpageflags_operations); |
---|
| 331 | + proc_create("kpagecount", S_IRUSR, NULL, &kpagecount_proc_ops); |
---|
| 332 | + proc_create("kpageflags", S_IRUSR, NULL, &kpageflags_proc_ops); |
---|
306 | 333 | #ifdef CONFIG_MEMCG |
---|
307 | | - proc_create("kpagecgroup", S_IRUSR, NULL, &proc_kpagecgroup_operations); |
---|
| 334 | + proc_create("kpagecgroup", S_IRUSR, NULL, &kpagecgroup_proc_ops); |
---|
308 | 335 | #endif |
---|
309 | 336 | return 0; |
---|
310 | 337 | } |
---|