From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (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 44AA6345EAD for ; Mon, 21 Sep 2026 04:09:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789963794; cv=none; b=qc+OtTklHQ0VPTgvUQpOrcVWWbpcMY9/MlVb9a/DgXhsDiiWXzW3U8tCGsaH4EvJ6/K+iCVPI9DLWMHoIjKsT8Y8kyuS2ghn+U9ND4TqBfRaFE4//KFuBvZpvCxU5vz3ps5Ja9/fK7MVu6SNIOJm3eWXDBymSuz2zUwrBt5okPk= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789963794; c=relaxed/simple; bh=qedrqCg6aMhP3i1rgWo0nsJ3jFfOO3yFDXeAmjpMb8o=; h=Date:To:From:Subject:Message-Id; b=FrmlsGpShyUJFG3mC7VEhtVBgYQROogACGAST7pCi+qmSVAJmq4UjU1VkuwjviQSBQRJJzOh5gHj+2QLWqp6FnGJHR0/i8bZyzsN/GrRs5x8+g2iOxddd5Un3psRBIpBhNSVmx14eCj9LKXnR2/frxe05PxilU040qerfVwXALc= 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=r+2jDc94; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux-foundation.org header.i=@linux-foundation.org header.b="r+2jDc94" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CB4951F000FF; Mon, 21 Sep 2026 04:09:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux-foundation.org; s=korg; t=1789963792; bh=srhQ7ZoRQr2/rG9WdbhYQtPfpTW4/Yu6r9dQBATRszU=; h=Date:To:From:Subject; b=r+2jDc94lQHnnseE/FCAZ6YMFxx8MZVOC8+P2nNvcFsPdVgi4bBhtvdOH1qyBhPFw Nyu2sb5UTZwbGQkX9ixPTs9XZzbqb0vokxeI51p6dSL9v5zXNomPq+sAkWOXEawrrU JuerdKhMYCZIa90Absf9xeozPvukC2/Nd9gy/a70= Date: Sun, 20 Sep 2026 21:09:52 -0700 To: mm-commits@vger.kernel.org,ziy@nvidia.com,akpm@linux-foundation.org From: Andrew Morton Subject: + erofs-mm-pagemap-add-readahead_folio_last-to-avoid-folio-private.patch added to mm-unstable branch Message-Id: <20260921040952.CB4951F000FF@smtp.kernel.org> Precedence: bulk X-Mailing-List: mm-commits@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: The patch titled Subject: erofs: mm/pagemap: add readahead_folio_last() to avoid folio->private has been added to the -mm mm-unstable branch. Its filename is erofs-mm-pagemap-add-readahead_folio_last-to-avoid-folio-private.patch This patch will shortly appear at https://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new.git/tree/patches/erofs-mm-pagemap-add-readahead_folio_last-to-avoid-folio-private.patch This patch will later appear in the mm-unstable branch at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm 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 various branches at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm and is updated there most days ------------------------------------------------------ From: Zi Yan Subject: erofs: mm/pagemap: add readahead_folio_last() to avoid folio->private Date: Sun, 20 Sep 2026 22:28:04 -0400 erofs needs to traverse readahead folios in reverse order to achieve maximum performance by 1. reading all folios from readahead_folio(); 2. storing the prior folio pointer in folio->private; 3. traverse from the last folio to the first one. Add readahead_folio_last() to achieve the same function without using folio->private. __readahead_advance() helper shares readahead_control adjustment code among __readahead_folio(), readahead_folio_last(), and __readahead_batch() by checking new private member, _forward, of readahead_control. It prepares for a future commit that replaces PG_private checks with !folio->private checks. After switching the checks, erofs's use of folio->private without bumping folio refcount can cause unexpected outcomes, e.g., in filemap_release_folio(), try_to_free_buffers() becomes reachable. No functional change intended. Assisted-by: LLM Link: https://lore.kernel.org/20260920-remove-pg_private-v5-8-bb68b6a21869@nvidia.com Signed-off-by: Zi Yan Signed-off-by: Andrew Morton Acked-by: David Hildenbrand (Arm) Cc: Yue Hu Cc: Jeffle Xu Cc: Sandeep Dhavale Cc: Hongbo Li Cc: Chunhai Guo Cc: Gao Xiang Cc: Chao Yu Cc: "Matthew Wilcox (Oracle)" Cc: Jan Kara --- fs/erofs/zdata.c | 13 +------- include/linux/pagemap.h | 60 ++++++++++++++++++++++++++++++++------ 2 files changed, 55 insertions(+), 18 deletions(-) --- a/fs/erofs/zdata.c~erofs-mm-pagemap-add-readahead_folio_last-to-avoid-folio-private +++ a/fs/erofs/zdata.c @@ -1898,21 +1898,14 @@ static void z_erofs_readahead(struct rea struct inode *realinode = erofs_real_inode(sharedinode, &need_iput); Z_EROFS_DEFINE_FRONTEND(f, realinode, sharedinode, readahead_pos(rac)); unsigned int nrpages = readahead_count(rac); - struct folio *head = NULL, *folio; + struct folio *folio; int err; trace_erofs_readahead(realinode, readahead_index(rac), nrpages, false); z_erofs_pcluster_readmore(&f, rac, true); - while ((folio = readahead_folio(rac))) { - folio->private = head; - head = folio; - } - - /* traverse in reverse order for best metadata I/O performance */ - while (head) { - folio = head; - head = folio_get_private(folio); + /* traverse from last to first for best metadata I/O performance */ + while ((folio = readahead_folio_last(rac))) { err = z_erofs_scan_folio(&f, folio, true); if (err && err != -EINTR) erofs_err(realinode->i_sb, "readahead error at folio %lu @ nid %llu", --- a/include/linux/pagemap.h~erofs-mm-pagemap-add-readahead_folio_last-to-avoid-folio-private +++ a/include/linux/pagemap.h @@ -1415,6 +1415,7 @@ struct readahead_control { bool dropbehind; bool _workingset; unsigned long _pflags; + bool _forward; }; #define DEFINE_READAHEAD(ractl, f, r, m, i) \ @@ -1479,18 +1480,29 @@ void page_cache_async_readahead(struct a page_cache_async_ra(&ractl, folio, req_count); } +/* + * Adjust readahead_control to ensure next folio comes from + * [_index, _index + _nr_pages) afterwards and reset _batch_count. + */ +static inline void __readahead_advance(struct readahead_control *rac) +{ + if (rac->_forward) + rac->_index += rac->_batch_count; + + rac->_nr_pages -= rac->_batch_count; + rac->_batch_count = 0; +} + static inline struct folio *__readahead_folio(struct readahead_control *ractl) { struct folio *folio; BUG_ON(ractl->_batch_count > ractl->_nr_pages); - ractl->_nr_pages -= ractl->_batch_count; - ractl->_index += ractl->_batch_count; + __readahead_advance(ractl); + ractl->_forward = true; - if (!ractl->_nr_pages) { - ractl->_batch_count = 0; + if (!ractl->_nr_pages) return NULL; - } folio = xa_load(&ractl->mapping->i_pages, ractl->_index); VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio); @@ -1516,6 +1528,39 @@ static inline struct folio *readahead_fo return folio; } +/** + * readahead_folio_last - Get the next folio to read, from the tail. + * @ractl: The current readahead request. + * + * Like readahead_folio(), but walks the range back-to-front. The folio is + * returned locked with its refcount dropped; the caller unlocks it once I/O + * completes. Compound folios are returned once, at their head index. + * + * Context: The folio is locked. + * Return: A pointer to the next folio, or %NULL when done. + */ +static inline struct folio *readahead_folio_last(struct readahead_control *ractl) +{ + struct folio *folio; + + /* Drop the previously returned batch from the remaining range. */ + __readahead_advance(ractl); + ractl->_forward = false; + + if (!ractl->_nr_pages) + return NULL; + + /* xa_load() follows sibling entries, so a tail index returns the head */ + folio = xa_load(&ractl->mapping->i_pages, + ractl->_index + ractl->_nr_pages - 1); + VM_WARN_ON_ONCE_FOLIO(!folio_test_locked(folio), folio); + + ractl->_batch_count = folio_nr_pages(folio); + + folio_put(folio); + return folio; +} + static inline unsigned int __readahead_batch(struct readahead_control *rac, struct page **array, unsigned int array_sz) { @@ -1524,9 +1569,8 @@ static inline unsigned int __readahead_b struct folio *folio; BUG_ON(rac->_batch_count > rac->_nr_pages); - rac->_nr_pages -= rac->_batch_count; - rac->_index += rac->_batch_count; - rac->_batch_count = 0; + __readahead_advance(rac); + rac->_forward = true; xas_set(&xas, rac->_index); rcu_read_lock(); _ Patches currently in -mm which might be from ziy@nvidia.com are mm-zsmalloc-replace-pg_private-with-pointer-comparison.patch perf-ring_buffer-stop-using-pg_private-as-aux-page-high-order-marker.patch xen-grant-table-stop-setting-pg_private-on-pages-for-grant-mapping.patch fscrypt-stop-setting-pg_private-on-bounce-page.patch mm-hugetlb-use-direct-assignment-instead-of-folio_change_private.patch f2fs-stop-using-pg_private.patch f2fs-convert-the-private-flag-helpers-to-folio-only.patch erofs-mm-pagemap-add-readahead_folio_last-to-avoid-folio-private.patch erofs-use-folio_attach-detach_private-instead-of-direct-assignment.patch mm-page-flags-check-page-folio-private-instead-of-pg_private.patch treewide-remove-folio_set-clear_private-usage.patch ceph-replace-pageprivate-with-page_private.patch treewide-remove-pageprivate-and-pg_private-from-comments-and-docs.patch mm-page-flags-remove-pg_private.patch usb-gadgetfs-do-not-warn-about-excessively-large-memory-allocations.patch