diff mbox series

[v3,2/2] proc: Add getting pages info of ZONE_DEVICE support

Message ID 20220112143517.262143-3-sxwjean@me.com (mailing list archive)
State New
Headers show
Series Add support for getting page info of ZONE_DEVICE by /proc/kpage* | expand

Commit Message

Xiongwei Song Jan. 12, 2022, 2:35 p.m. UTC
From: Xiongwei Song <sxwjean@gmail.com>

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@gmail.com>
---
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(-)

Comments

Michal Hocko Jan. 13, 2022, 3:31 p.m. UTC | #1
On Wed 12-01-22 22:35:17, sxwjean@me.com wrote:
> From: Xiongwei Song <sxwjean@gmail.com>
> 
> 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.

Why is this needed? Who would consume that information and what for?
Xiongwei Song Jan. 14, 2022, 10:03 a.m. UTC | #2
HI Michal,

On Thu, Jan 13, 2022 at 11:31 PM Michal Hocko <mhocko@suse.com> wrote:
>
> On Wed 12-01-22 22:35:17, sxwjean@me.com wrote:
> > From: Xiongwei Song <sxwjean@gmail.com>
> >
> > 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.
>
> Why is this needed? Who would consume that information and what for?

It's for debug purpose, which checks page flags in system wide. No any other
special thought. But it looks like it's not appropriate to expose now from my
understand, which is from David's comment.
https://lore.kernel.org/linux-mm/20220110141957.259022-1-sxwjean@me.com/T/#m4eccbb2698dbebc80ec00be47382b34b0f64b4fc

Regards,
Xingwei
Michal Hocko Jan. 14, 2022, 10:18 a.m. UTC | #3
On Fri 14-01-22 18:03:04, Xiongwei Song wrote:
> HI Michal,
> 
> On Thu, Jan 13, 2022 at 11:31 PM Michal Hocko <mhocko@suse.com> wrote:
> >
> > On Wed 12-01-22 22:35:17, sxwjean@me.com wrote:
> > > From: Xiongwei Song <sxwjean@gmail.com>
> > >
> > > 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.
> >
> > Why is this needed? Who would consume that information and what for?
> 
> It's for debug purpose, which checks page flags in system wide. No any other
> special thought. But it looks like it's not appropriate to expose now from my
> understand, which is from David's comment.
> https://lore.kernel.org/linux-mm/20220110141957.259022-1-sxwjean@me.com/T/#m4eccbb2698dbebc80ec00be47382b34b0f64b4fc

yes, I do agree with David. This is the reason I am asking because I do
remember we have deliberately excluded those pages. If there is no real
user to use that information then I do not think we want to make the
code more complex and check for memmap and other peculiarities.

Thanks!
diff mbox series

Patch

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;