From: Xiongwei Song <sxwjean@xxxxxxxxx> When requesting pages info by /proc/kpage*, the pages in ZONE_DEVICE were ignored. The pfn_to_devmap_page() function can help to get page that belongs to ZONE_DEVICE. Signed-off-by: Xiongwei Song <sxwjean@xxxxxxxxx> --- V3: Reset pgmap to NULL after putting dev_pagemap to prevent false non-NULL. --- fs/proc/page.c | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/fs/proc/page.c b/fs/proc/page.c index 9f1077d94cde..d4fc308765f5 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c @@ -15,6 +15,7 @@ #include <linux/page_idle.h> #include <linux/kernel-page-flags.h> #include <linux/uaccess.h> +#include <linux/memremap.h> #include "internal.h" #define KPMSIZE sizeof(u64) @@ -46,6 +47,7 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf, { const unsigned long max_dump_pfn = get_max_dump_pfn(); u64 __user *out = (u64 __user *)buf; + struct dev_pagemap *pgmap = NULL; struct page *ppage; unsigned long src = *ppos; unsigned long pfn; @@ -60,17 +62,20 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf, count = min_t(unsigned long, count, (max_dump_pfn * KPMSIZE) - src); while (count > 0) { - /* - * TODO: ZONE_DEVICE support requires to identify - * memmaps that were actually initialized. - */ ppage = pfn_to_online_page(pfn); + if (!ppage) + ppage = pfn_to_devmap_page(pfn, &pgmap); if (!ppage || PageSlab(ppage) || page_has_type(ppage)) pcount = 0; else pcount = page_mapcount(ppage); + if (pgmap) { + put_dev_pagemap(pgmap); + pgmap = NULL; + } + if (put_user(pcount, out)) { ret = -EFAULT; break; @@ -229,10 +234,12 @@ static ssize_t kpageflags_read(struct file *file, char __user *buf, { const unsigned long max_dump_pfn = get_max_dump_pfn(); u64 __user *out = (u64 __user *)buf; + struct dev_pagemap *pgmap = NULL; struct page *ppage; unsigned long src = *ppos; unsigned long pfn; ssize_t ret = 0; + u64 flags; pfn = src / KPMSIZE; if (src & KPMMASK || count & KPMMASK) @@ -242,13 +249,17 @@ static ssize_t kpageflags_read(struct file *file, char __user *buf, count = min_t(unsigned long, count, (max_dump_pfn * KPMSIZE) - src); while (count > 0) { - /* - * TODO: ZONE_DEVICE support requires to identify - * memmaps that were actually initialized. - */ ppage = pfn_to_online_page(pfn); + if (!ppage) + ppage = pfn_to_devmap_page(pfn, &pgmap); + + flags = stable_page_flags(ppage); + if (pgmap) { + put_dev_pagemap(pgmap); + pgmap = NULL; + } - if (put_user(stable_page_flags(ppage), out)) { + if (put_user(flags, out)) { ret = -EFAULT; break; } @@ -277,6 +288,7 @@ static ssize_t kpagecgroup_read(struct file *file, char __user *buf, { const unsigned long max_dump_pfn = get_max_dump_pfn(); u64 __user *out = (u64 __user *)buf; + struct dev_pagemap *pgmap = NULL; struct page *ppage; unsigned long src = *ppos; unsigned long pfn; @@ -291,17 +303,20 @@ static ssize_t kpagecgroup_read(struct file *file, char __user *buf, count = min_t(unsigned long, count, (max_dump_pfn * KPMSIZE) - src); while (count > 0) { - /* - * TODO: ZONE_DEVICE support requires to identify - * memmaps that were actually initialized. - */ ppage = pfn_to_online_page(pfn); + if (!ppage) + ppage = pfn_to_devmap_page(pfn, &pgmap); if (ppage) ino = page_cgroup_ino(ppage); else ino = 0; + if (pgmap) { + put_dev_pagemap(pgmap); + pgmap = NULL; + } + if (put_user(ino, out)) { ret = -EFAULT; break; -- 2.30.2