From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id BFFB6B67E for ; Fri, 16 Jan 2026 08:27:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768552071; cv=none; b=TyAl7KzXg0nmqq4jbEEAEmAqUn+P4s83KJnGobVab0mVR3pzTfcCw4IMJiLSD3dLKgn8QqsdBIF5zcA1yICsfTDzh292KBvensRigDnVf3qBjgE5DKtAAYXemnm92+rqwZEQl9RVKR/kEoET4CDyX7eTBbODoCJR/vrQVe+xiKY= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768552071; c=relaxed/simple; bh=YofC2b2XU20cv5xXmAOE7WNprw+c3MGIP1Je4A3PBw4=; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version; b=Y8ZaNdSDq0fLWO6WuzL+SNSoKVmD0BPpoD/RQEgS8T0kZLrnN8HTGXpYh/rdt8sriRpzxmnbguHrXqe5cUw/Qi2DyCHDXQFkrWvufniEWMX2TtstzZn1sy1T2vBwcEpC9FZ9Dv0FFxZrfWFKLrG2GPNCQn9tSODBDANrG2NhVG4= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 07186FEC; Fri, 16 Jan 2026 00:27:41 -0800 (PST) Received: from a080796.blr.arm.com (a080796.arm.com [10.164.21.51]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 37D7D3F694; Fri, 16 Jan 2026 00:27:41 -0800 (PST) From: Dev Jain To: akpm@linux-foundation.org Cc: axelrasmussen@google.com, yuanchu@google.com, weixugc@google.com, david@kernel.org, lorenzo.stoakes@oracle.com, Liam.Howlett@oracle.com, vbabka@suse.cz, rppt@kernel.org, surenb@google.com, mhocko@suse.com, riel@surriel.com, harry.yoo@oracle.com, jannh@google.com, ryan.roberts@arm.com, baohua@kernel.org, baolin.wang@linux.alibaba.com, linux-mm@kvack.org, linux-kernel@vger.kernel.org, Dev Jain Subject: [PATCH mm-unstable] mm: Fix uffd-wp bit loss when batching file folio unmapping Date: Fri, 16 Jan 2026 13:57:21 +0530 Message-Id: <20260116082721.275178-1-dev.jain@arm.com> X-Mailer: git-send-email 2.34.1 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit The recently added file folio unmap batching support forgets to update pte_install_uffd_wp_if_needed(), which still updates a single pte. We end up jumping to the end of the folio in page_vma_mapped_walk(), thus setting the uffd-wp marker only on a single pte in the batch. Fix this by passing nr_pages into the function, and set the uffd-wp marker on all ptes. Note that, since the nr_pages passed to this function is always derived by some sort of batching, it is guaranteed that the set of old ptevals of the batch have uffd-wp bit on all ptes or no ptes, therefore it is safe to derive the value of the local variable "arm_uffd_pte" from only the particular pteval passed to this function, but apply the result on all ptes of the batch. Use set_pte_at() in a loop to set the markers - we cannot use set_ptes() as that will increment the PFN, but we don't have any PFN to update here. The userspace visible effect of the bug is inaccuracy observed by workloads relying on uffd-wp regions to install their own pages. Fixes: 8798e255b5ec ("mm: rmap: support batched unmapping for file large folios") Signed-off-by: Dev Jain --- Patch applies on mm-unstable, commit f8ed52ac0cfb. I observed this bug during code inspection, but it turns out that the uffd-wp-mremap selftest will skip some tests with a bogus complain that "MADV_PAGEOUT didn't work, is swap enabled?" even when swap is enabled. It first sets the region uffd-wp, then swaps it out, then checks through pagemap whether it got swapped out. For file folios, this check makes no sense since the ptes are simply cleared, but in this particular case, because of uffd-wp preservation, we need to store PTE_MARKER_UFFD_WP, which is stored as a swap entry, that is why the test works out on a non-buggy kernel. include/linux/mm_inline.h | 7 ++++--- mm/memory.c | 14 +------------- mm/rmap.c | 2 +- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h index fa2d6ba811b5..adec1dcb8793 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h @@ -568,7 +568,7 @@ static inline pte_marker copy_pte_marker( */ static inline bool pte_install_uffd_wp_if_needed(struct vm_area_struct *vma, unsigned long addr, - pte_t *pte, pte_t pteval) + pte_t *pte, pte_t pteval, unsigned int nr_pages) { bool arm_uffd_pte = false; @@ -599,8 +599,9 @@ pte_install_uffd_wp_if_needed(struct vm_area_struct *vma, unsigned long addr, arm_uffd_pte = true; if (unlikely(arm_uffd_pte)) { - set_pte_at(vma->vm_mm, addr, pte, - make_pte_marker(PTE_MARKER_UFFD_WP)); + for (int i = 0; i < nr_pages; ++i, ++pte, addr += PAGE_SIZE) + set_pte_at(vma->vm_mm, addr, pte, + make_pte_marker(PTE_MARKER_UFFD_WP)); return true; } diff --git a/mm/memory.c b/mm/memory.c index 6b22dd72ebc8..35ac86d29e77 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1588,8 +1588,6 @@ zap_install_uffd_wp_if_needed(struct vm_area_struct *vma, unsigned long addr, pte_t *pte, int nr, struct zap_details *details, pte_t pteval) { - bool was_installed = false; - if (!uffd_supports_wp_marker()) return false; @@ -1600,17 +1598,7 @@ zap_install_uffd_wp_if_needed(struct vm_area_struct *vma, if (zap_drop_markers(details)) return false; - for (;;) { - /* the PFN in the PTE is irrelevant. */ - if (pte_install_uffd_wp_if_needed(vma, addr, pte, pteval)) - was_installed = true; - if (--nr == 0) - break; - pte++; - addr += PAGE_SIZE; - } - - return was_installed; + return pte_install_uffd_wp_if_needed(vma, addr, pte, pteval, nr); } static __always_inline void zap_present_folio_ptes(struct mmu_gather *tlb, diff --git a/mm/rmap.c b/mm/rmap.c index f13480cb9f2e..d6ca002bf79c 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -2171,7 +2171,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma, * we may want to replace a none pte with a marker pte if * it's file-backed, so we don't lose the tracking info. */ - pte_install_uffd_wp_if_needed(vma, address, pvmw.pte, pteval); + pte_install_uffd_wp_if_needed(vma, address, pvmw.pte, pteval, nr_pages); /* Update high watermark before we lower rss */ update_hiwater_rss(mm); -- 2.34.1