From nobody Mon May 25 02:41:55 2026 Received: from out-170.mta0.migadu.com (out-170.mta0.migadu.com [91.218.175.170]) (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 02AEA33F5BE for ; Tue, 19 May 2026 12:17:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779193062; cv=none; b=BfO1l+TI+ylTsDeFu+ohnkES8VIOE/nuF3YDDXgizSF4zfzgS78VAK4otx1PrvMUDVbMmoXWHXuMB+35Tu9yy0AxJkhMlfh+F/l1lbSk0ckKbPNz5M2aqiTIFzw0qLtNHgUNGKti/MFEUAwOivEQyOUZs0RW2yfzhoWzoI8RRV0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779193062; c=relaxed/simple; bh=k7tc4ncFnwikL1VoXjoNwU+MdybLntsEUpooLLn53Zc=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=NvC7GeF2gnDaIpKfCku7e1OUkVo2jwkjzzoejYdTM/98z++BWJtFsGhvoaiwCWZDqMbDDtgu50zrfg4SnxPblW5K5od0r7/D5dbApXFoD14kg/XIEj8MVDp3Wriwwhe7muxk2uQPiGvze0E8XmOWCrxeLgVvRkPfSI6G6KEhoqU= 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=T57vD/Jb; arc=none smtp.client-ip=91.218.175.170 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="T57vD/Jb" 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=1779193057; 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; bh=XEMPGbEHhCu5DMoe1MyIoAfJdd0UluJOXNzfWSjHHX4=; b=T57vD/JbaVffczEmaAEIFywhqXaJx2llXP9Bf9TNayRRWYQiMTnlkp5gG2zx39v1nKrq/f MQxwymDzYCPoZ/vY1j+s5v7EPgfsNKEgiksr71KFDpZWoCBxEQW85gvb/+/XQ+q4m+u4ln 9m3LW3JBRL1bQBuQnppcl2vG4ta2FO0= From: Kaitao Cheng To: akpm@linux-foundation.org, vbabka@kernel.org, surenb@google.com, mhocko@suse.com, jackmanb@google.com, hannes@cmpxchg.org, ziy@nvidia.com Cc: liushixin2@huawei.com, david@kernel.org, osalvador@suse.de, linux-mm@kvack.org, linux-kernel@vger.kernel.org, Kaitao Cheng Subject: [PATCH] mm: page_isolation: Avoid hugepage scan step underflow Date: Tue, 19 May 2026 20:16:46 +0800 Message-ID: <20260519121646.40833-1-kaitao.cheng@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: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Kaitao Cheng page_is_unmovable() checks HugeTLB pages without holding hugetlb_lock and without pinning the folio. This is intentional for the pageblock scanning paths, but it means the HugeTLB folio can be freed concurrently after PageHuge() or folio_test_hugetlb() succeeds. The existing code avoids folio_hstate() and uses size_to_hstate() because the HugeTLB flag may already have been cleared. However, if size_to_hstate() returns NULL, the code still falls through and computes the scan step from folio_nr_pages(). If the folio has been freed and the head/large state has been cleared, folio_nr_pages() can return 1. When the current page is a tail page, subtracting folio_page_idx() from 1 can underflow and make the scanner skip too far. Treat a NULL hstate as unmovable so the scanner does not try to skip over an unstable HugeTLB folio. Once a valid hstate is found, derive the number of pages from the hstate instead of reading the folio size again. Also validate the page index before computing the step to avoid underflow if the page/folio relationship changed concurrently. Fixes: a0a9f2180b90 ("mm: page_isolation: avoid calling folio_hstate() with= out hugetlb_lock") Signed-off-by: Kaitao Cheng --- mm/page_isolation.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/mm/page_isolation.c b/mm/page_isolation.c index c48ff5c00244..99f0b06efaf6 100644 --- a/mm/page_isolation.c +++ b/mm/page_isolation.c @@ -43,6 +43,7 @@ bool page_is_unmovable(struct zone *zone, struct page *pa= ge, */ if (PageHuge(page) || PageCompound(page)) { struct folio *folio =3D page_folio(page); + unsigned long idx, nr_pages; =20 if (folio_test_hugetlb(folio)) { struct hstate *h; @@ -55,14 +56,21 @@ bool page_is_unmovable(struct zone *zone, struct page *= page, * use folio_hstate() directly. */ h =3D size_to_hstate(folio_size(folio)); - if (h && !hugepage_migration_supported(h)) + if (!h || !hugepage_migration_supported(h)) return true; =20 + nr_pages =3D pages_per_huge_page(h); } else if (!folio_test_lru(folio)) { return true; + } else { + nr_pages =3D folio_nr_pages(folio); } =20 - *step =3D folio_nr_pages(folio) - folio_page_idx(folio, page); + idx =3D folio_page_idx(folio, page); + if (idx >=3D nr_pages) + return true; + + *step =3D nr_pages - idx; return false; } =20 --=20 2.50.1 (Apple Git-155)