Received: by 2002:ab2:6309:0:b0:1fb:d597:ff75 with SMTP id s9csp998999lqt; Fri, 7 Jun 2024 05:26:32 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCVLs2MFAUbK3b3gyyKGZAOVb36qFtBPDufJyuQASHxUgSIowKVqkCpX4rV79K/O5qHIMmCkVxQ+hh1Ec0gKbrDY8xoyOLXrGCH2DodiMQ== X-Google-Smtp-Source: AGHT+IE5b9ADu1nWGyZ6++uswCo2In4k3BE9jzR7/r86P/8wUnGAIxwXwdZTngNmDB9FBq0LJLec X-Received: by 2002:a05:6512:2f1:b0:52b:798f:cd7e with SMTP id 2adb3069b0e04-52bb9f62696mr2039875e87.12.1717763192259; Fri, 07 Jun 2024 05:26:32 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1717763192; cv=pass; d=google.com; s=arc-20160816; b=rdxVY57g+P5eoqONgoUspMHOdtpgCMMtTCNi4Ilt6YKry2SlRdgVnDhrkzdtJSnYrR kfG4C8mBPgIRQjK54UoCYrKvwRrYpVdIqe04NUB774eYZ6ZDa662o206+28QPGHtgnFL 9yBMbnvfVB1A0tNjHSPJ2C2E5g53qcsIibrlglWwCZPImdzm1jWp4sSWKi3GuASi8shw x3IwN5V/C4vktyL+bh0xLpuUoL2ue8R8ldSCB+KY+MbRgnPJDvsATzuVSBWJ4RgFqPKB r1dJqzRfwj8MnWgN+rqxLlrCo87ubNPUFqidD8yqqkEPFMNa51G2/IsrJ0Jj4ISNwFGB VCNg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=NeGZgl6bcZJYszXPuGofZHugwXu/JCr74XswxhNWa/0=; fh=CIaeNsHvdnbvngJjnzLDSb2UCdCi60rbbZWKayXDh6A=; b=RiYG3XSFt0VHWVeHp9VFhp33agXuJC/iVp9C3/pWWsql1pNlJU4Sn57EVzu0ZQdsIq NWeMWJVssYv73diuI+Y6KzCJn6HTuEhT5flhqTHrXQaPtIcHKVubpZHJ3qw4GByLhlXo 6TrAQLxK8gKLtPT5kACSLhOhyHB6mWMoS0p8ynHHlZB9lSQ4InO/HcZTPG1SZf7+SCuQ 2krFEp0Gz4DFcgyajgV65Xhch0bN9eqHtuEHaCjhdyUC1EnfzYix/Xshn7qN8iCPUO6j g3RZP164vEmMF3ZuuuuaN2yh8fz/Pyple1LtG3GI0XJCQp5ajN49yj9GxediJIeEpuNN /9Tg==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=HKAWUino; arc=pass (i=1 spf=pass spfdomain=redhat.com dkim=pass dkdomain=redhat.com dmarc=pass fromdomain=redhat.com); spf=pass (google.com: domain of linux-kernel+bounces-206024-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.80.249 as permitted sender) smtp.mailfrom="linux-kernel+bounces-206024-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from am.mirrors.kernel.org (am.mirrors.kernel.org. [147.75.80.249]) by mx.google.com with ESMTPS id a640c23a62f3a-a6c806dbc96si175019966b.375.2024.06.07.05.26.32 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Jun 2024 05:26:32 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel+bounces-206024-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.80.249 as permitted sender) client-ip=147.75.80.249; Authentication-Results: mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=HKAWUino; arc=pass (i=1 spf=pass spfdomain=redhat.com dkim=pass dkdomain=redhat.com dmarc=pass fromdomain=redhat.com); spf=pass (google.com: domain of linux-kernel+bounces-206024-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.80.249 as permitted sender) smtp.mailfrom="linux-kernel+bounces-206024-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by am.mirrors.kernel.org (Postfix) with ESMTPS id BB47B1F24AD0 for ; Fri, 7 Jun 2024 12:26:31 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 73066196C9D; Fri, 7 Jun 2024 12:24:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="HKAWUino" Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (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 866B9194C68 for ; Fri, 7 Jun 2024 12:24:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717763057; cv=none; b=L9pcDwdVjMaZaEp/fgyNnn6sNcv2i1VdKnyuFmpMzXa3RxGKYVYz+4ulsRTkiueWSVMDzvJEUbjydDnrt1vomfep8O/gH0YF/wLaKRHikGYxEZ5HSeiGdBNQWjP72XFbhDANybNq5khdHgS0eG2v1RXm1Nhgfb+gzJ/n/AA5Eto= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1717763057; c=relaxed/simple; bh=D8neSebn0iVXy/d3rMysrVlVhegLU3wixnvVMIn532U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RyxWIwESnf+/CGoyv/UeNaZPDx8WHEkVxtcIByyMOOMpmcaq/zF8QHAzriEbvAhmaHlhRfoorwEtP1CYkoZsCN/hIUVms0enZnE2U6T+ydVR39ohroPB+UXKMH67DZRKdPt912zsbUOFgovCHXY17IcGszCOiMzQbXCDEMsCRNA= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=HKAWUino; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717763054; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=NeGZgl6bcZJYszXPuGofZHugwXu/JCr74XswxhNWa/0=; b=HKAWUinoPH7AC3KjJf5xEMCjP9mdBBvDFAOGEll+W21E8IGfyfQEsqrvptdtAhbvns47i7 n4xmQFtcnuYqJigb7SKrfAspQ+itXfkBJ3jS7kmCCoMK7ZlkPjPUxzttPmoPQlcd+C+G8w jLk7QEXinWSZGl7JStci4lkB644wso0= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-567-PkT7xXgBOK2Dyd-86yhZpg-1; Fri, 07 Jun 2024 08:24:11 -0400 X-MC-Unique: PkT7xXgBOK2Dyd-86yhZpg-1 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 00F2E185A780; Fri, 7 Jun 2024 12:24:11 +0000 (UTC) Received: from t14s.fritz.box (unknown [10.39.192.109]) by smtp.corp.redhat.com (Postfix) with ESMTP id 72622492BCE; Fri, 7 Jun 2024 12:24:09 +0000 (UTC) From: David Hildenbrand To: linux-kernel@vger.kernel.org Cc: linux-mm@kvack.org, linux-doc@vger.kernel.org, linux-fsdevel@vger.kernel.org, David Hildenbrand , Andrew Morton , Jonathan Corbet Subject: [PATCH v1 5/6] fs/proc: move page_mapcount() to fs/proc/internal.h Date: Fri, 7 Jun 2024 14:23:56 +0200 Message-ID: <20240607122357.115423-6-david@redhat.com> In-Reply-To: <20240607122357.115423-1-david@redhat.com> References: <20240607122357.115423-1-david@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.10 ... and rename it to folio_precise_page_mapcount(). fs/proc is the last remaining user, and that should stay that way. While at it, cleanup kpagecount_read() a bit: there are still some legacy leftovers -- when the interface was introduced it returned the page refcount, but was changed briefly afterwards to return the page mapcount. Further, some simple folio conversion. Once we stop using the per-page mapcounts of large folios, all folio_precise_page_mapcount() users will have to implement an alternative way to achieve what they are trying to achieve, possibly in a less precise way. Signed-off-by: David Hildenbrand --- fs/proc/internal.h | 33 +++++++++++++++++++++++++++++++++ fs/proc/page.c | 21 ++++++++++----------- fs/proc/task_mmu.c | 35 ++++++++++++++++++++++------------- include/linux/mm.h | 27 +-------------------------- 4 files changed, 66 insertions(+), 50 deletions(-) diff --git a/fs/proc/internal.h b/fs/proc/internal.h index a71ac5379584a..a8a8576d8592e 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -13,6 +13,7 @@ #include #include #include +#include struct ctl_table_header; struct mempolicy; @@ -142,6 +143,38 @@ unsigned name_to_int(const struct qstr *qstr); /* Worst case buffer size needed for holding an integer. */ #define PROC_NUMBUF 13 +/** + * folio_precise_page_mapcount() - Number of mappings of this folio page. + * @folio: The folio. + * @page: The page. + * + * The number of present user page table entries that reference this page + * as tracked via the RMAP: either referenced directly (PTE) or as part of + * a larger area that covers this page (e.g., PMD). + * + * Use this function only for the calculation of existing statistics + * (USS, PSS, mapcount_max) and for debugging purposes (/proc/kpagecount). + * + * Do not add new users. + * + * Returns: The number of mappings of this folio page. 0 for + * folios that are not mapped to user space or are not tracked via the RMAP + * (e.g., shared zeropage). + */ +static inline int folio_precise_page_mapcount(struct folio *folio, + struct page *page) +{ + int mapcount = atomic_read(&page->_mapcount) + 1; + + /* Handle page_has_type() pages */ + if (mapcount < PAGE_MAPCOUNT_RESERVE + 1) + mapcount = 0; + if (folio_test_large(folio)) + mapcount += folio_entire_mapcount(folio); + + return mapcount; +} + /* * array.c */ diff --git a/fs/proc/page.c b/fs/proc/page.c index 2fb64bdb64eb1..e8440db8cfbf9 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c @@ -37,21 +37,19 @@ static inline unsigned long get_max_dump_pfn(void) #endif } -/* /proc/kpagecount - an array exposing page counts +/* /proc/kpagecount - an array exposing page mapcounts * * Each entry is a u64 representing the corresponding - * physical page count. + * physical page mapcount. */ static ssize_t kpagecount_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { const unsigned long max_dump_pfn = get_max_dump_pfn(); u64 __user *out = (u64 __user *)buf; - struct page *ppage; unsigned long src = *ppos; unsigned long pfn; ssize_t ret = 0; - u64 pcount; pfn = src / KPMSIZE; if (src & KPMMASK || count & KPMMASK) @@ -61,18 +59,19 @@ 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) { + struct page *page; + u64 mapcount = 0; + /* * TODO: ZONE_DEVICE support requires to identify * memmaps that were actually initialized. */ - ppage = pfn_to_online_page(pfn); - - if (!ppage) - pcount = 0; - else - pcount = page_mapcount(ppage); + page = pfn_to_online_page(pfn); + if (page) + mapcount = folio_precise_page_mapcount(page_folio(page), + page); - if (put_user(pcount, out)) { + if (put_user(mapcount, out)) { ret = -EFAULT; break; } diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 67d9b406c7586..631371cb80a05 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -488,12 +488,12 @@ static void smaps_account(struct mem_size_stats *mss, struct page *page, return; } /* - * The page_mapcount() is called to get a snapshot of the mapcount. - * Without holding the folio lock this snapshot can be slightly wrong as - * we cannot always read the mapcount atomically. + * We obtain a snapshot of the mapcount. Without holding the folio lock + * this snapshot can be slightly wrong as we cannot always read the + * mapcount atomically. */ for (i = 0; i < nr; i++, page++) { - int mapcount = page_mapcount(page); + int mapcount = folio_precise_page_mapcount(folio, page); unsigned long pss = PAGE_SIZE << PSS_SHIFT; if (mapcount >= 2) pss /= mapcount; @@ -1424,6 +1424,7 @@ static pagemap_entry_t pte_to_pagemap_entry(struct pagemapread *pm, { u64 frame = 0, flags = 0; struct page *page = NULL; + struct folio *folio; if (pte_present(pte)) { if (pm->show_pfn) @@ -1461,10 +1462,14 @@ static pagemap_entry_t pte_to_pagemap_entry(struct pagemapread *pm, flags |= PM_UFFD_WP; } - if (page && !PageAnon(page)) - flags |= PM_FILE; - if (page && (flags & PM_PRESENT) && page_mapcount(page) == 1) - flags |= PM_MMAP_EXCLUSIVE; + if (page) { + folio = page_folio(page); + if (!folio_test_anon(folio)) + flags |= PM_FILE; + if ((flags & PM_PRESENT) && + folio_precise_page_mapcount(folio, page) == 1) + flags |= PM_MMAP_EXCLUSIVE; + } if (vma->vm_flags & VM_SOFTDIRTY) flags |= PM_SOFT_DIRTY; @@ -1487,6 +1492,7 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end, u64 flags = 0, frame = 0; pmd_t pmd = *pmdp; struct page *page = NULL; + struct folio *folio; if (vma->vm_flags & VM_SOFTDIRTY) flags |= PM_SOFT_DIRTY; @@ -1525,15 +1531,18 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end, } #endif - if (page && !PageAnon(page)) - flags |= PM_FILE; + if (page) { + folio = page_folio(page); + if (!folio_test_anon(folio)) + flags |= PM_FILE; + } for (; addr != end; addr += PAGE_SIZE, idx++) { unsigned long cur_flags = flags; pagemap_entry_t pme; - if (page && (flags & PM_PRESENT) && - page_mapcount(page + idx) == 1) + if (folio && (flags & PM_PRESENT) && + folio_precise_page_mapcount(folio, page + idx) == 1) cur_flags |= PM_MMAP_EXCLUSIVE; pme = make_pme(frame, cur_flags); @@ -2572,7 +2581,7 @@ static void gather_stats(struct page *page, struct numa_maps *md, int pte_dirty, unsigned long nr_pages) { struct folio *folio = page_folio(page); - int count = page_mapcount(page); + int count = folio_precise_page_mapcount(folio, page); md->pages += nr_pages; if (pte_dirty || folio_test_dirty(folio)) diff --git a/include/linux/mm.h b/include/linux/mm.h index 04795a5090267..42e3752b5eed5 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1197,8 +1197,7 @@ static inline int is_vmalloc_or_module_addr(const void *x) /* * How many times the entire folio is mapped as a single unit (eg by a * PMD or PUD entry). This is probably not what you want, except for - * debugging purposes - it does not include PTE-mapped sub-pages; look - * at folio_mapcount() or page_mapcount() instead. + * debugging purposes or implementation of other core folio_*() primitives. */ static inline int folio_entire_mapcount(const struct folio *folio) { @@ -1206,30 +1205,6 @@ static inline int folio_entire_mapcount(const struct folio *folio) return atomic_read(&folio->_entire_mapcount) + 1; } -/** - * page_mapcount() - Number of times this precise page is mapped. - * @page: The page. - * - * The number of times this page is mapped. If this page is part of - * a large folio, it includes the number of times this page is mapped - * as part of that folio. - * - * Will report 0 for pages which cannot be mapped into userspace, eg - * slab, page tables and similar. - */ -static inline int page_mapcount(struct page *page) -{ - int mapcount = atomic_read(&page->_mapcount) + 1; - - /* Handle page_has_type() pages */ - if (mapcount < PAGE_MAPCOUNT_RESERVE + 1) - mapcount = 0; - if (unlikely(PageCompound(page))) - mapcount += folio_entire_mapcount(page_folio(page)); - - return mapcount; -} - static inline int folio_large_mapcount(const struct folio *folio) { VM_WARN_ON_FOLIO(!folio_test_large(folio), folio); -- 2.45.2