mm/page_owner.c: add llseek for page_owner
authorKassey Li <quic_yingangl@quicinc.com>
Thu, 18 Aug 2022 02:24:25 +0000 (10:24 +0800)
committerAndrew Morton <akpm@linux-foundation.org>
Mon, 12 Sep 2022 03:25:59 +0000 (20:25 -0700)
It is too slow to dump all the pages, in some usage we just want to dump a
given start pfn, for example: a CMA range or a single page.

To speed up and save time, this change allows specifying of a start pfn by
adding llseek for page_owner.

Link: https://lkml.kernel.org/r/20220818022425.31056-1-quic_yingangl@quicinc.com
Signed-off-by: Kassey Li <quic_yingangl@quicinc.com>
Suggested-by: Vlastimil Babka <vbabka@suse.cz>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Minchan Kim <minchan@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Documentation/mm/page_owner.rst
mm/page_owner.c

index f5c954a..f18fd89 100644 (file)
@@ -94,6 +94,11 @@ Usage
        Page allocated via order XXX, ...
        PFN XXX ...
        // Detailed stack
+    By default, it will do full pfn dump, to start with a given pfn,
+    page_owner supports fseek.
+
+    FILE *fp = fopen("/sys/kernel/debug/page_owner", "r");
+    fseek(fp, pfn_start, SEEK_SET);
 
    The ``page_owner_sort`` tool ignores ``PFN`` rows, puts the remaining rows
    in buf, uses regexp to extract the page order value, counts the times
index 72839a6..90023f9 100644 (file)
@@ -516,8 +516,10 @@ read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)
                return -EINVAL;
 
        page = NULL;
-       pfn = min_low_pfn + *ppos;
-
+       if (*ppos == 0)
+               pfn = min_low_pfn;
+       else
+               pfn = *ppos;
        /* Find a valid PFN or the start of a MAX_ORDER_NR_PAGES area */
        while (!pfn_valid(pfn) && (pfn & (MAX_ORDER_NR_PAGES - 1)) != 0)
                pfn++;
@@ -588,7 +590,7 @@ read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)
                        goto ext_put_continue;
 
                /* Record the next PFN to read in the file offset */
-               *ppos = (pfn - min_low_pfn) + 1;
+               *ppos = pfn + 1;
 
                page_owner_tmp = *page_owner;
                page_ext_put(page_ext);
@@ -601,6 +603,21 @@ ext_put_continue:
        return 0;
 }
 
+static loff_t lseek_page_owner(struct file *file, loff_t offset, int orig)
+{
+       switch (orig) {
+       case SEEK_SET:
+               file->f_pos = offset;
+               break;
+       case SEEK_CUR:
+               file->f_pos += offset;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return file->f_pos;
+}
+
 static void init_pages_in_zone(pg_data_t *pgdat, struct zone *zone)
 {
        unsigned long pfn = zone->zone_start_pfn;
@@ -693,6 +710,7 @@ static void init_early_allocated_pages(void)
 
 static const struct file_operations proc_page_owner_operations = {
        .read           = read_page_owner,
+       .llseek         = lseek_page_owner,
 };
 
 static int __init pageowner_init(void)