From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ABDD7AD23 for ; Tue, 3 Jun 2025 02:14:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748916889; cv=none; b=FFnS/df861yPgBbLP6+NvcWVbLFUvqxxICYjMyykuu6IOPLGIyXPwCiNld8h6+DdD8tpQ83ND5rz5L3ZibwOxjLSXfWOmy5hZ+5gMciLdpKlkaPBPZ1KYsK9oGm3nsfoLJZv9OTXCq4AbVzYlahvFq8NIhCfPOAnAUTg7VVcYoM= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1748916889; c=relaxed/simple; bh=JqUjAK8kb2/arZDULqAhrR5f/jSpf+sIqez87juTj74=; h=Date:To:From:Subject:Message-Id; b=nC5EnF/9OrEi2kRmEWD5akGePc85ux6NLiBTwoYyMheTJpU0zkInCwzjaacPMyjU995S9WXxInenWviTXck49xgnP3+N4mnr2vevcNlq2eItalKvtUYTlvFsRCSbAnVlaXXLfpTSZIEnFncCc6ggX0nOHSIw0jzd4jbMkqLYDTM= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux-foundation.org header.i=@linux-foundation.org header.b=ZzG1XegL; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux-foundation.org header.i=@linux-foundation.org header.b="ZzG1XegL" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1891DC4CEEB; Tue, 3 Jun 2025 02:14:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linux-foundation.org; s=korg; t=1748916889; bh=JqUjAK8kb2/arZDULqAhrR5f/jSpf+sIqez87juTj74=; h=Date:To:From:Subject:From; b=ZzG1XegLDWDE4KlvTArfnHMb9A5b4cNCF5VNhaAzklyFkAn86W+YK3oIYiMKPfwvD QN3dnnMxJOp0kpvl1iHfBwNMI8T2qBhuNXFC0sc4iBuShAFYX6MB3ES7NhD32gQTsG +11IERMRJvktaqsPzSRigfx15bEIRYM5JN8bJ+Eo= Date: Mon, 02 Jun 2025 19:14:48 -0700 To: mm-commits@vger.kernel.org,sweettea-kernel@dorminy.me,stephen.s.brennan@oracle.com,sj@kernel.org,paulmck@kernel.org,osandov@osandov.com,fweimer@redhat.com,liuye@kylinos.cn,akpm@linux-foundation.org From: Andrew Morton Subject: + tools-mm-add-script-to-display-page-state-for-a-given-pid-and-vaddr.patch added to mm-new branch Message-Id: <20250603021449.1891DC4CEEB@smtp.kernel.org> Precedence: bulk X-Mailing-List: mm-commits@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: The patch titled Subject: tools/mm: add script to display page state for a given PID and VADDR has been added to the -mm mm-new branch. Its filename is tools-mm-add-script-to-display-page-state-for-a-given-pid-and-vaddr.patch This patch will shortly appear at https://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new.git/tree/patches/tools-mm-add-script-to-display-page-state-for-a-given-pid-and-vaddr.patch This patch will later appear in the mm-new branch at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm Note, mm-new is a provisional staging ground for work-in-progress patches, and acceptance into mm-new is a notification for others take notice and to finish up reviews. Please do not hesitate to respond to review feedback and post updated versions to replace or incrementally fixup patches in mm-new. Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/process/submit-checklist.rst when testing your code *** The -mm tree is included into linux-next via the mm-everything branch at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm and is updated there every 2-3 working days ------------------------------------------------------ From: Ye Liu Subject: tools/mm: add script to display page state for a given PID and VADDR Date: Fri, 30 May 2025 13:58:55 +0800 Introduces a new drgn script, `show_page_info.py`, which allows users to analyze the state of a page given a process ID (PID) and a virtual address (VADDR). This can help kernel developers or debuggers easily inspect page-related information in a live kernel or vmcore. The script extracts information such as the page flags, mapping, and other metadata relevant to diagnosing memory issues. Output example: sudo ./show_page_info.py 1 0x7fc988181000 PID: 1 Comm: systemd mm: 0xffff8d22c4089700 RAW: 0017ffffc000416c fffff939062ff708 fffff939062ffe08 ffff8d23062a12a8 RAW: 0000000000000000 ffff8d2323438f60 0000002500000007 ffff8d23203ff500 Page Address: 0xfffff93905664e00 Page Flags: PG_referenced|PG_uptodate|PG_lru|PG_head|PG_active| PG_private|PG_reported|PG_has_hwpoisoned Page Size: 4096 Page PFN: 0x159938 Page Physical: 0x159938000 Page Virtual: 0xffff8d2319938000 Page Refcount: 37 Page Mapcount: 7 Page Index: 0x0 Page Memcg Data: 0xffff8d23203ff500 Memcg Name: init.scope Memcg Path: /sys/fs/cgroup/memory/init.scope Page Mapping: 0xffff8d23062a12a8 Page Anon/File: File Page VMA: 0xffff8d22e06e0e40 VMA Start: 0x7fc988181000 VMA End: 0x7fc988185000 This page is part of a compound page. This page is the head page of a compound page. Head Page: 0xfffff93905664e00 Compound Order: 2 Number of Pages: 4 Link: https://lkml.kernel.org/r/20250530055855.687067-1-ye.liu@linux.dev Signed-off-by: Ye Liu Tested-by: SeongJae Park Reviewed-by: Stephen Brennan Cc: Florian Weimer Cc: Omar Sandoval Cc: "Paul E . McKenney" Cc: Sweet Tea Dorminy Signed-off-by: Andrew Morton --- MAINTAINERS | 5 + tools/mm/show_page_info.py | 169 +++++++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+) --- a/MAINTAINERS~tools-mm-add-script-to-display-page-state-for-a-given-pid-and-vaddr +++ a/MAINTAINERS @@ -18678,6 +18678,11 @@ F: Documentation/mm/page_table_check.rst F: include/linux/page_table_check.h F: mm/page_table_check.c +PAGE STATE DEBUG SCRIPT +M: Ye Liu +S: Maintained +F: tools/mm/show_page_info.py + PANASONIC LAPTOP ACPI EXTRAS DRIVER M: Kenneth Chan L: platform-driver-x86@vger.kernel.org diff --git a/tools/mm/show_page_info.py a/tools/mm/show_page_info.py new file mode 100644 --- /dev/null +++ a/tools/mm/show_page_info.py @@ -0,0 +1,169 @@ +#!/usr/bin/env drgn +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (C) 2025 Ye Liu + +import argparse +import sys +from drgn import Object, FaultError, PlatformFlags, cast +from drgn.helpers.linux import find_task, follow_page, page_size +from drgn.helpers.linux.mm import ( + decode_page_flags, page_to_pfn, page_to_phys, page_to_virt, vma_find, + PageSlab, PageCompound, PageHead, PageTail, compound_head, compound_order, compound_nr +) +from drgn.helpers.linux.cgroup import cgroup_name, cgroup_path + +DESC = """ +This is a drgn script to show the page state. +For more info on drgn, visit https://github.com/osandov/drgn. +""" + +def format_page_data(page): + """ + Format raw page data into a readable hex dump with "RAW:" prefix. + + :param page: drgn.Object instance representing the page. + :return: Formatted string of memory contents. + """ + try: + address = page.value_() + size = prog.type("struct page").size + + if prog.platform.flags & PlatformFlags.IS_64_BIT: + word_size = 8 + else: + word_size = 4 + num_words = size // word_size + + values = [] + for i in range(num_words): + word_address = address + i * word_size + word = prog.read_word(word_address) + values.append(f"{word:0{word_size * 2}x}") + + lines = [f"RAW: {' '.join(values[i:i + 4])}" for i in range(0, len(values), 4)] + + return "\n".join(lines) + + except FaultError as e: + return f"Error reading memory: {e}" + except Exception as e: + return f"Unexpected error: {e}" + +def get_memcg_info(page): + """Retrieve memory cgroup information for a page.""" + try: + MEMCG_DATA_OBJEXTS = prog.constant("MEMCG_DATA_OBJEXTS").value_() + MEMCG_DATA_KMEM = prog.constant("MEMCG_DATA_KMEM").value_() + mask = prog.constant('__NR_MEMCG_DATA_FLAGS').value_() - 1 + memcg_data = page.memcg_data.read_() + if memcg_data & MEMCG_DATA_OBJEXTS: + slabobj_ext = cast("struct slabobj_ext *", memcg_data & ~mask) + memcg = slabobj_ext.objcg.memcg.value_() + elif memcg_data & MEMCG_DATA_KMEM: + objcg = cast("struct obj_cgroup *", memcg_data & ~mask) + memcg = objcg.memcg.value_() + else: + memcg = cast("struct mem_cgroup *", memcg_data & ~mask) + + if memcg.value_() == 0: + return "none", "/sys/fs/cgroup/memory/" + cgrp = memcg.css.cgroup + return cgroup_name(cgrp).decode(), f"/sys/fs/cgroup/memory{cgroup_path(cgrp).decode()}" + except FaultError as e: + return "unknown", f"Error retrieving memcg info: {e}" + except Exception as e: + return "unknown", f"Unexpected error: {e}" + +def show_page_state(page, addr, mm, pid, task): + """Display detailed information about a page.""" + try: + print(f'PID: {pid} Comm: {task.comm.string_().decode()} mm: {hex(mm)}') + try: + print(format_page_data(page)) + except FaultError as e: + print(f"Error reading page data: {e}") + fields = { + "Page Address": hex(page.value_()), + "Page Flags": decode_page_flags(page), + "Page Size": prog["PAGE_SIZE"].value_(), + "Page PFN": hex(page_to_pfn(page).value_()), + "Page Physical": hex(page_to_phys(page).value_()), + "Page Virtual": hex(page_to_virt(page).value_()), + "Page Refcount": page._refcount.counter.value_(), + "Page Mapcount": page._mapcount.counter.value_(), + "Page Index": hex(page.__folio_index.value_()), + "Page Memcg Data": hex(page.memcg_data.value_()), + } + + memcg_name, memcg_path = get_memcg_info(page) + fields["Memcg Name"] = memcg_name + fields["Memcg Path"] = memcg_path + fields["Page Mapping"] = hex(page.mapping.value_()) + fields["Page Anon/File"] = "Anon" if page.mapping.value_() & 0x1 else "File" + + try: + vma = vma_find(mm, addr) + fields["Page VMA"] = hex(vma.value_()) + fields["VMA Start"] = hex(vma.vm_start.value_()) + fields["VMA End"] = hex(vma.vm_end.value_()) + except FaultError as e: + fields["Page VMA"] = "Unavailable" + fields["VMA Start"] = "Unavailable" + fields["VMA End"] = "Unavailable" + print(f"Error retrieving VMA information: {e}") + + # Calculate the maximum field name length for alignment + max_field_len = max(len(field) for field in fields) + + # Print aligned fields + for field, value in fields.items(): + print(f"{field}:".ljust(max_field_len + 2) + f"{value}") + + # Additional information about the page + if PageSlab(page): + print("This page belongs to the slab allocator.") + + if PageCompound(page): + print("This page is part of a compound page.") + if PageHead(page): + print("This page is the head page of a compound page.") + if PageTail(page): + print("This page is the tail page of a compound page.") + print(f"{'Head Page:'.ljust(max_field_len + 2)}{hex(compound_head(page).value_())}") + print(f"{'Compound Order:'.ljust(max_field_len + 2)}{compound_order(page).value_()}") + print(f"{'Number of Pages:'.ljust(max_field_len + 2)}{compound_nr(page).value_()}") + else: + print("This page is not part of a compound page.") + except FaultError as e: + print(f"Error accessing page state: {e}") + except Exception as e: + print(f"Unexpected error: {e}") + +def main(): + """Main function to parse arguments and display page state.""" + parser = argparse.ArgumentParser(description=DESC, formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('pid', metavar='PID', type=int, help='Target process ID (PID)') + parser.add_argument('vaddr', metavar='VADDR', type=str, help='Target virtual address in hexadecimal format (e.g., 0x7fff1234abcd)') + args = parser.parse_args() + + try: + vaddr = int(args.vaddr, 16) + except ValueError: + sys.exit(f"Error: Invalid virtual address format: {args.vaddr}") + + try: + task = find_task(args.pid) + mm = task.mm + page = follow_page(mm, vaddr) + + if page: + show_page_state(page, vaddr, mm, args.pid, task) + else: + sys.exit(f"Address {hex(vaddr)} is not mapped.") + except FaultError as e: + sys.exit(f"Error accessing task or memory: {e}") + except Exception as e: + sys.exit(f"Unexpected error: {e}") + +if __name__ == "__main__": + main() _ Patches currently in -mm which might be from liuye@kylinos.cn are tools-mm-add-script-to-display-page-state-for-a-given-pid-and-vaddr.patch