From nobody Thu Apr 9 06:36:03 2026 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 830483806C1 for ; Tue, 10 Mar 2026 10:54:31 +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=1773140073; cv=none; b=tujzh0U4Esnmb409NlmFwDYWDA+O9ZvapKAlgaE2kix1s2a6vm4mDQxx2osSDcP5UQWt81X7ys5NaXieE28/s92k8Doj+IpWVCwh4v4V4wOYp5PtU0ZO7ZxoT8PLkIT3HvwOLpJsOctD8kAqf+pIMnxVO+lXIb+zx5GIWUcKWZ0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773140073; c=relaxed/simple; bh=5JxavfVfXXDl54g3IeNjypfindPKGdWLr16q75ItwBs=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=lpf8cKMjV8TlCgOqVuwcqhf0Y6YXFKxye1svxqeiy8Xp44sUPSDKhO1axE5cRFL/ZdAp1ToOOudC/hBcQ7BradpD5d6bdGHOCV7PQL7o4pJjPrVemDzNCnXPAiLmwwK+wGUVvr0uR/8BSNhtjr0A7233rUz1/ALftqzQWGsLIOE= 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=LarhKTNp; 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="LarhKTNp" 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=1773140069; 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=ARuq7ZjC8dzTxJfI/eCppeEwZc/OqS1stLK8KFLZlIU=; b=LarhKTNpjI/TYV/q7TK86qYjr8Lnagqv1M10Zgm8AXO1/FpRqmsARvg+QRMhwz5l3nytTf 22BuOIKQMy+8fuqwHScn+th+0PYhWhpZVo9NK0j52svTZUd8I7KhrUmZVQAihh2NFOJA9z RWrM7Q5bk0SiZgOwI+LJJi8/OwwxM+w= From: Usama Arif To: Andrew Morton , npache@redhat.com, david@kernel.org, ziy@nvidia.com, willy@infradead.org, linux-mm@kvack.org Cc: matthew.brost@intel.com, joshua.hahnjy@gmail.com, hannes@cmpxchg.org, rakie.kim@sk.com, byungchul@sk.com, gourry@gourry.net, ying.huang@linux.alibaba.com, apopple@nvidia.com, linux-kernel@vger.kernel.org, kernel-team@meta.com, Usama Arif Subject: [PATCH v2] mm: migrate: requeue destination folio on deferred split queue Date: Tue, 10 Mar 2026 03:54:19 -0700 Message-ID: <20260310105419.3256755-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: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" During folio migration, __folio_migrate_mapping() removes the source folio from the deferred split queue, but the destination folio is never re-queued. This causes underutilized THPs to escape the shrinker after NUMA migration, since they silently drop off the deferred split list. Fix this by recording whether the source folio was on the deferred split queue and its partially mapped state before move_to_new_folio() unqueues it, and re-queuing the destination folio after a successful migration if it was. By the time migrate_folio_move() runs, partially mapped folios without a pin have already been split by migrate_pages_batch(). So only two cases remain on the deferred list at this point: 1. Partially mapped folios with a pin (split failed). 2. Fully mapped but potentially underused folios. The recorded partially_mapped state is forwarded to deferred_split_folio() so that the destination folio is correctly re-queued in both cases. Reported-by: Johannes Weiner Fixes: dafff3f4c850 ("mm: split underused THPs") Signed-off-by: Usama Arif Acked-by: David Hildenbrand (Arm) Acked-by: Zi Yan --- v1 -> v2: - record whether source folio was on the deferred split queue before move_to_folio() (David) - record partially mapped state and update commit message (Zi) --- mm/migrate.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/mm/migrate.c b/mm/migrate.c index ece77ccb2ec0..61013d258eb4 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -1360,6 +1360,8 @@ static int migrate_folio_move(free_folio_t put_new_fo= lio, unsigned long private, int rc; int old_page_state =3D 0; struct anon_vma *anon_vma =3D NULL; + bool src_deferred_split =3D false; + bool src_partially_mapped =3D false; struct list_head *prev; =20 __migrate_folio_extract(dst, &old_page_state, &anon_vma); @@ -1373,6 +1375,12 @@ static int migrate_folio_move(free_folio_t put_new_f= olio, unsigned long private, goto out_unlock_both; } =20 + if (folio_test_large(src) && folio_test_large_rmappable(src) && + !data_race(list_empty(&src->_deferred_list))) { + src_deferred_split =3D true; + src_partially_mapped =3D folio_test_partially_mapped(src); + } + rc =3D move_to_new_folio(dst, src, mode); if (rc) goto out; @@ -1393,6 +1401,15 @@ static int migrate_folio_move(free_folio_t put_new_f= olio, unsigned long private, if (old_page_state & PAGE_WAS_MAPPED) remove_migration_ptes(src, dst, 0); =20 + /* + * Requeue the destination folio on the deferred split queue if + * the source was on the queue. The source is unqueued in + * __folio_migrate_mapping(), so we recorded the state from + * before move_to_new_folio(). + */ + if (src_deferred_split) + deferred_split_folio(dst, src_partially_mapped); + out_unlock_both: folio_unlock(dst); folio_set_owner_migrate_reason(dst, reason); --=20 2.47.3