From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out-183.mta0.migadu.com (out-183.mta0.migadu.com [91.218.175.183]) (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 4E23937F726 for ; Wed, 22 Jul 2026 15:22:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.183 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784733748; cv=none; b=AZMYTezE0aBuymsKvWDJ3sTS5YROuZgtw+MbzslLczH2sqmJosVn8VuD+z6m3t+tFp0OnDHW0nHXrx9LdIcLy5R1o+X8rg7NEGAOVKpy5w3CStCsTp3UJZ+qn5E+J9h35HXLiSaR1nnA+nWE03mySMzbC9rDL0MrpTw5oR4FliM= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784733748; c=relaxed/simple; bh=WePN0/wZNYVvVmY8BzdyIKd9MIwMdla1EXEiXxopD5k=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tp8xE8VxvSMONG8bGDMZ3a2QMV5l04i9mji/KNvqNHK6VrSDSzdwo80W4GqTS4+YvxE3y6mZ93jmRapC+efyefm533ZBvKS8lfqNqZGNyrICtrT4le4FhceqZ3NMq9yynEeMdQlgMeLfr41yWiSumkf7NxrmbHdFEzLpi8wRGis= 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=K+9ewz8I; arc=none smtp.client-ip=91.218.175.183 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="K+9ewz8I" 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=1784733739; 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=yJyGxOkNDorXjAH0XOOahAgzY2eO5p0zRfJGy6LO4qg=; b=K+9ewz8IKoFjnuzUA45sDYVWWpjLp2t4ZQwUEjtcMC9py8yly1xikJwHxGKWKvuFVsUKjD hYwl8wvWHF7eg729d26HrVVTJOihOb3Sv4Zb4iEVQMNJQmqR1cWqaB9ZQ8tax/V3dsFQ3w it7T76wZM+4mziB7wVK1j+FxsRg2hpc= From: Usama Arif To: Andrew Morton , david@kernel.org, chrisl@kernel.org, kasong@tencent.com, ljs@kernel.org, ziy@nvidia.com, linux-mm@kvack.org Cc: ying.huang@linux.alibaba.com, Baoquan He , 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, Nico Pache , Liam R. Howlett , ryan.roberts@arm.com, Vlastimil Babka , lance.yang@linux.dev, linux-kernel@vger.kernel.org, nphamcs@gmail.com, shikemeng@huaweicloud.com, yosry@kernel.org, kernel-team@meta.com, Usama Arif Subject: [PATCH v5 07/11] mm: handle PMD swap entries in MADV_WILLNEED Date: Wed, 22 Jul 2026 08:19:38 -0700 Message-ID: <20260722152043.2273289-8-usama.arif@linux.dev> In-Reply-To: <20260722152043.2273289-1-usama.arif@linux.dev> References: <20260722152043.2273289-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 swapin_walk_pmd_entry() walks PTEs and skips non-present PMDs, so MADV_WILLNEED is a no-op on a PMD swap entry. Handle PMD swap entries under pmd_trans_huge_lock(). If the covered swap-cache range already has a PMD-sized folio, there is nothing left to prefetch. If the range has split cache state, or any covered slot currently has a zswap entry, split the PMD swap entry and ask the walker to retry so the PTE path can handle the individual slots. Otherwise pin the swap device and read the folio in at PMD order via swapin_sync(BIT(HPAGE_PMD_ORDER)). This keeps the subsequent fault on the do_huge_pmd_swap_page() path and avoids order-0 readahead needlessly splitting the PMD swap entry. If PMD-order swapin races with per-slot swap-cache population after dropping the PMD lock, split and retry through the PTE path instead. If per-page zswap state reappears during the read, remove the failed clean PMD-sized folio from swap cache before splitting so the PTE path can load each slot. Signed-off-by: Usama Arif --- mm/madvise.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/mm/madvise.c b/mm/madvise.c index 81ccdd6a5140..1d5154b10dfc 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -193,6 +194,91 @@ static int swapin_walk_pmd_entry(pmd_t *pmd, unsigned long start, spinlock_t *ptl; unsigned long addr; + ptl = pmd_trans_huge_lock(pmd, vma); + if (ptl) { + pmd_t pmdval = *pmd; + + if (pmd_is_swap_entry(pmdval)) { + softleaf_t entry = softleaf_from_pmd(pmdval); + struct vm_fault vmf = { + .vma = vma, + .address = start, + .real_address = start, + .pmd = pmd, + }; + struct swap_info_struct *si; + struct folio *folio; + enum swap_pmd_cache cache_state; + bool split = false; + + cache_state = swap_pmd_cache_lookup(entry, &folio); + if (cache_state == SWAP_PMD_CACHE_HUGE) { + folio_put(folio); + spin_unlock(ptl); + goto ret; + } + if (cache_state == SWAP_PMD_CACHE_SPLIT || + zswap_is_present(entry, HPAGE_PMD_NR)) { + spin_unlock(ptl); + __split_huge_pmd(vma, pmd, start, false); + walk->action = ACTION_AGAIN; + goto ret; + } + + /* + * Pin the swap device under the PMD lock so the + * PMD-swap-entry observation keeps the entry valid for + * swapin_sync(). + */ + si = get_swap_device(entry); + spin_unlock(ptl); + if (!si) + goto ret; + + folio = swapin_sync(entry, GFP_HIGHUSER_MOVABLE, + BIT(HPAGE_PMD_ORDER), &vmf, + NULL, 0); + /* + * The empty-cache observation was made under the PMD + * lock, but swap cache can change after dropping it. If + * PMD-order swapin lost a race to per-slot cache state, + * retry through the PTE path. + */ + if (IS_ERR(folio)) { + if (PTR_ERR(folio) == -EBUSY) + split = true; + } else if (folio) { + if (folio_nr_pages(folio) != HPAGE_PMD_NR) { + split = true; + } else if (!folio_test_locked(folio) && + !folio_test_uptodate(folio) && + zswap_is_present(entry, HPAGE_PMD_NR)) { + folio_lock(folio); + /* + * A failed PMD-order zswap load leaves the + * folio clean and not uptodate, but another + * thread can remove it from swap cache before + * we acquire the lock. Revalidate the + * association before deleting it so the PTE + * retry can load the per-page state. + */ + if (folio_matches_swap_entry(folio, entry)) + swap_cache_del_folio(folio); + folio_unlock(folio); + split = true; + } + folio_put(folio); + } + put_swap_device(si); + if (split) { + __split_huge_pmd(vma, pmd, start, false); + walk->action = ACTION_AGAIN; + } + goto ret; + } + spin_unlock(ptl); + } + for (addr = start; addr < end; addr += PAGE_SIZE) { pte_t pte; softleaf_t entry; @@ -221,6 +307,7 @@ static int swapin_walk_pmd_entry(pmd_t *pmd, unsigned long start, if (ptep) pte_unmap_unlock(ptep, ptl); swap_read_submit(&ctx); +ret: cond_resched(); return 0; -- 2.53.0-Meta