From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out-173.mta0.migadu.com (out-173.mta0.migadu.com [91.218.175.173]) (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 121483B47FA for ; Mon, 27 Apr 2026 10:06:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.173 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777284398; cv=none; b=nqQT+CNd+LitI9Nc8foeXya2Vx7RFXgtkv2+16w1inqiQy8uT+xfyb8tvAVRZj96NygqaXeLAUA7L5RYg9HWv5SmxF5VzX1m9TPyZiTvdn6lpuOzF0FUIje8j0cXHidba+TcXava8aGPQx1N/jimnN04tm54xqa+Lq4R4Gdb6Mg= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777284398; c=relaxed/simple; bh=RX0Tt0oVSJHkw6emmj2XdQXtXYBxnOwodUhW3O/eHeM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sKGejkRS49d4dimvHT6YGOBmxSguVqNLOLHPKaUQTeWK2o1dYyx7GW1Zz4ukBVmfEQEnYF3PBBqZk3lxCPCp3Evy3mHCaxnHe5oFEqoTutTqDb9HcRCUvwCl8Np9I8DXYDjh2NKErReHcegnpY+1BI1L4R/Sl0B9XASo3CN+piw= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=XbbNN6vI; arc=none smtp.client-ip=91.218.175.173 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="XbbNN6vI" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1777284390; 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=9Kp1QkYRXSgpi6gPGEgyWsBAfNXkVOPJekD3kea3f8U=; b=XbbNN6vI/PR6UOfzX8QZpOY22tWsYNCrev2+c0JZdgJY6eXgPdO5L77h6uoBAGi4E1O7vQ oFlj8f7QR0p3MHBO5TceOw1H7YLqhhitXGWfJXeKG0xH1JyscrXkRnG2FTk4wFnoJ47TtJ mX0PtfvtotW7COZ2K6HoX7mDWvQKivc= From: Usama Arif To: Andrew Morton , david@kernel.org, chrisl@kernel.org, kasong@tencent.com, ljs@kernel.org, ziy@nvidia.com Cc: bhe@redhat.com, willy@infradead.org, youngjun.park@lge.com, hannes@cmpxchg.org, riel@surriel.com, shakeel.butt@linux.dev, alex@ghiti.fr, kas@kernel.org, baohua@kernel.org, dev.jain@arm.com, baolin.wang@linux.alibaba.com, npache@redhat.com, Liam.Howlett@oracle.com, ryan.roberts@arm.com, Vlastimil Babka , lance.yang@linux.dev, linux-kernel@vger.kernel.org, nphamcs@gmail.com, shikemeng@huaweicloud.com, kernel-team@meta.com, Usama Arif Subject: [PATCH 06/13] mm: add PMD swap entry splitting support Date: Mon, 27 Apr 2026 03:01:55 -0700 Message-ID: <20260427100553.2754667-7-usama.arif@linux.dev> In-Reply-To: <20260427100553.2754667-1-usama.arif@linux.dev> References: <20260427100553.2754667-1-usama.arif@linux.dev> 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-Migadu-Flow: FLOW_OUT Add a swap branch in __split_huge_pmd_locked() that splits a PMD swap entry into 512 PTE swap entries. Unlike migration splits, no folio reference is needed because swap entries point to swap slots, not pages. Each PTE inherits the correct sub-slot offset and preserves soft_dirty, uffd_wp, and exclusive flags. This branch is reached from the explicit __split_huge_pmd() callers that hit a non-present PMD: partial-range mprotect / munmap, the wp_huge_pmd() PMD-COW fallback, and the swap-in / swapoff fallbacks added in later patches when the cached folio is no longer PMD-sized. page_vma_mapped_walk() does not iterate PMD swap entries, so try_to_unmap_one() and try_to_migrate_one() do not reach this branch and freeze=true cannot occur in this branch today. page and folio are therefore left uninitialized in the swap branch; a VM_WARN_ON_ONCE(freeze) catches any future caller that breaks this invariant before the freeze path dereferences page_to_pfn(page + i) or put_page(page). Signed-off-by: Usama Arif --- include/linux/leafops.h | 6 +++--- mm/huge_memory.c | 27 ++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/include/linux/leafops.h b/include/linux/leafops.h index 79e04db45bfb..2c0dfce6d0f0 100644 --- a/include/linux/leafops.h +++ b/include/linux/leafops.h @@ -657,9 +657,9 @@ static inline bool pmd_is_swap_entry(pmd_t pmd) * pmd_is_valid_softleaf() - Is this PMD entry a valid softleaf entry? * @pmd: PMD entry. * - * PMD leaf entries are valid only if they are device private or migration - * entries. This function asserts that a PMD leaf entry is valid in this - * respect. + * PMD leaf entries are valid only if they are device private, migration, + * or swap entries. This function asserts that a PMD leaf entry is valid + * in this respect. * * Returns: true if the PMD entry is a valid leaf entry, otherwise false. */ diff --git a/mm/huge_memory.c b/mm/huge_memory.c index d82a19b5e276..9f67638e43c8 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -3201,6 +3201,12 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd, folio_add_anon_rmap_ptes(folio, page, HPAGE_PMD_NR, vma, haddr, rmap_flags); } + } else if (pmd_is_swap_entry(*pmd)) { + VM_WARN_ON_ONCE(freeze); + old_pmd = *pmd; + soft_dirty = pmd_swp_soft_dirty(old_pmd); + uffd_wp = pmd_swp_uffd_wp(old_pmd); + anon_exclusive = pmd_swp_exclusive(old_pmd); } else { /* * Up to this point the pmd is present and huge and userland has @@ -3337,6 +3343,25 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd, VM_WARN_ON(!pte_none(ptep_get(pte + i))); set_pte_at(mm, addr, pte + i, entry); } + } else if (pmd_is_swap_entry(old_pmd)) { + softleaf_t sl_entry = softleaf_from_pmd(old_pmd); + pte_t swp_pte; + swp_entry_t sub_entry; + + for (i = 0, addr = haddr; i < HPAGE_PMD_NR; + i++, addr += PAGE_SIZE) { + sub_entry = swp_entry(swp_type(sl_entry), + swp_offset(sl_entry) + i); + swp_pte = swp_entry_to_pte(sub_entry); + if (soft_dirty) + swp_pte = pte_swp_mksoft_dirty(swp_pte); + if (uffd_wp) + swp_pte = pte_swp_mkuffd_wp(swp_pte); + if (anon_exclusive) + swp_pte = pte_swp_mkexclusive(swp_pte); + VM_WARN_ON(!pte_none(ptep_get(pte + i))); + set_pte_at(mm, addr, pte + i, swp_pte); + } } else { pte_t entry; @@ -3360,7 +3385,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd, } pte_unmap(pte); - if (!pmd_is_migration_entry(*pmd)) + if (!pmd_is_migration_entry(*pmd) && !pmd_is_swap_entry(*pmd)) folio_remove_rmap_pmd(folio, page, vma); if (freeze) put_page(page); -- 2.52.0