aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/vm/page-types.c154
1 files changed, 89 insertions, 65 deletions
diff --git a/Documentation/vm/page-types.c b/Documentation/vm/page-types.c
index 6bdcc0632c24..18e891a329e0 100644
--- a/Documentation/vm/page-types.c
+++ b/Documentation/vm/page-types.c
@@ -161,8 +161,6 @@ static unsigned long pg_start[MAX_VMAS];
161static unsigned long pg_end[MAX_VMAS]; 161static unsigned long pg_end[MAX_VMAS];
162static unsigned long voffset; 162static unsigned long voffset;
163 163
164static int pagemap_fd;
165
166#define MAX_BIT_FILTERS 64 164#define MAX_BIT_FILTERS 64
167static int nr_bit_filters; 165static int nr_bit_filters;
168static uint64_t opt_mask[MAX_BIT_FILTERS]; 166static uint64_t opt_mask[MAX_BIT_FILTERS];
@@ -170,7 +168,7 @@ static uint64_t opt_bits[MAX_BIT_FILTERS];
170 168
171static int page_size; 169static int page_size;
172 170
173#define PAGES_BATCH (64 << 10) /* 64k pages */ 171static int pagemap_fd;
174static int kpageflags_fd; 172static int kpageflags_fd;
175 173
176#define HASH_SHIFT 13 174#define HASH_SHIFT 13
@@ -226,6 +224,62 @@ int checked_open(const char *pathname, int flags)
226 return fd; 224 return fd;
227} 225}
228 226
227/*
228 * pagemap/kpageflags routines
229 */
230
231static unsigned long do_u64_read(int fd, char *name,
232 uint64_t *buf,
233 unsigned long index,
234 unsigned long count)
235{
236 long bytes;
237
238 if (index > ULONG_MAX / 8)
239 fatal("index overflow: %lu\n", index);
240
241 if (lseek(fd, index * 8, SEEK_SET) < 0) {
242 perror(name);
243 exit(EXIT_FAILURE);
244 }
245
246 bytes = read(fd, buf, count * 8);
247 if (bytes < 0) {
248 perror(name);
249 exit(EXIT_FAILURE);
250 }
251 if (bytes % 8)
252 fatal("partial read: %lu bytes\n", bytes);
253
254 return bytes / 8;
255}
256
257static unsigned long kpageflags_read(uint64_t *buf,
258 unsigned long index,
259 unsigned long pages)
260{
261 return do_u64_read(kpageflags_fd, PROC_KPAGEFLAGS, buf, index, pages);
262}
263
264static unsigned long pagemap_read(uint64_t *buf,
265 unsigned long index,
266 unsigned long pages)
267{
268 return do_u64_read(pagemap_fd, "/proc/pid/pagemap", buf, index, pages);
269}
270
271static unsigned long pagemap_pfn(uint64_t val)
272{
273 unsigned long pfn;
274
275 if (val & PM_PRESENT)
276 pfn = PM_PFRAME(val);
277 else
278 pfn = 0;
279
280 return pfn;
281}
282
229 283
230/* 284/*
231 * page flag names 285 * page flag names
@@ -432,79 +486,53 @@ static void add_page(unsigned long offset, uint64_t flags)
432 total_pages++; 486 total_pages++;
433} 487}
434 488
489#define KPAGEFLAGS_BATCH (64 << 10) /* 64k pages */
435static void walk_pfn(unsigned long index, unsigned long count) 490static void walk_pfn(unsigned long index, unsigned long count)
436{ 491{
492 uint64_t buf[KPAGEFLAGS_BATCH];
437 unsigned long batch; 493 unsigned long batch;
438 unsigned long n; 494 unsigned long pages;
439 unsigned long i; 495 unsigned long i;
440 496
441 if (index > ULONG_MAX / KPF_BYTES)
442 fatal("index overflow: %lu\n", index);
443
444 lseek(kpageflags_fd, index * KPF_BYTES, SEEK_SET);
445
446 while (count) { 497 while (count) {
447 uint64_t kpageflags_buf[KPF_BYTES * PAGES_BATCH]; 498 batch = min_t(unsigned long, count, KPAGEFLAGS_BATCH);
448 499 pages = kpageflags_read(buf, index, batch);
449 batch = min_t(unsigned long, count, PAGES_BATCH); 500 if (pages == 0)
450 n = read(kpageflags_fd, kpageflags_buf, batch * KPF_BYTES);
451 if (n == 0)
452 break; 501 break;
453 if (n < 0) {
454 perror(PROC_KPAGEFLAGS);
455 exit(EXIT_FAILURE);
456 }
457
458 if (n % KPF_BYTES != 0)
459 fatal("partial read: %lu bytes\n", n);
460 n = n / KPF_BYTES;
461 502
462 for (i = 0; i < n; i++) 503 for (i = 0; i < pages; i++)
463 add_page(index + i, kpageflags_buf[i]); 504 add_page(index + i, buf[i]);
464 505
465 index += batch; 506 index += pages;
466 count -= batch; 507 count -= pages;
467 } 508 }
468} 509}
469 510
470 511#define PAGEMAP_BATCH (64 << 10)
471#define PAGEMAP_BATCH 4096 512static void walk_vma(unsigned long index, unsigned long count)
472static unsigned long task_pfn(unsigned long pgoff)
473{ 513{
474 static uint64_t buf[PAGEMAP_BATCH]; 514 uint64_t buf[PAGEMAP_BATCH];
475 static unsigned long start; 515 unsigned long batch;
476 static long count; 516 unsigned long pages;
477 uint64_t pfn; 517 unsigned long pfn;
518 unsigned long i;
478 519
479 if (pgoff < start || pgoff >= start + count) { 520 while (count) {
480 if (lseek64(pagemap_fd, 521 batch = min_t(unsigned long, count, PAGEMAP_BATCH);
481 (uint64_t)pgoff * PM_ENTRY_BYTES, 522 pages = pagemap_read(buf, index, batch);
482 SEEK_SET) < 0) { 523 if (pages == 0)
483 perror("pagemap seek"); 524 break;
484 exit(EXIT_FAILURE);
485 }
486 count = read(pagemap_fd, buf, sizeof(buf));
487 if (count == 0)
488 return 0;
489 if (count < 0) {
490 perror("pagemap read");
491 exit(EXIT_FAILURE);
492 }
493 if (count % PM_ENTRY_BYTES) {
494 fatal("pagemap read not aligned.\n");
495 exit(EXIT_FAILURE);
496 }
497 count /= PM_ENTRY_BYTES;
498 start = pgoff;
499 }
500 525
501 pfn = buf[pgoff - start]; 526 for (i = 0; i < pages; i++) {
502 if (pfn & PM_PRESENT) 527 pfn = pagemap_pfn(buf[i]);
503 pfn = PM_PFRAME(pfn); 528 voffset = index + i;
504 else 529 if (pfn)
505 pfn = 0; 530 walk_pfn(pfn, 1);
531 }
506 532
507 return pfn; 533 index += pages;
534 count -= pages;
535 }
508} 536}
509 537
510static void walk_task(unsigned long index, unsigned long count) 538static void walk_task(unsigned long index, unsigned long count)
@@ -524,11 +552,7 @@ static void walk_task(unsigned long index, unsigned long count)
524 index = min_t(unsigned long, pg_end[i], end); 552 index = min_t(unsigned long, pg_end[i], end);
525 553
526 assert(voffset < index); 554 assert(voffset < index);
527 for (; voffset < index; voffset++) { 555 walk_vma(voffset, index - voffset);
528 unsigned long pfn = task_pfn(voffset);
529 if (pfn)
530 walk_pfn(pfn, 1);
531 }
532 } 556 }
533} 557}
534 558