From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out-174.mta1.migadu.com (out-174.mta1.migadu.com [95.215.58.174]) (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 B9A15175A85 for ; Mon, 22 Jun 2026 16:45:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.174 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782146702; cv=none; b=h2svH7fjP4LvXIygHl0ISFCGzZhTQQQ7bd7lu/iKpyoysH+FGC9Z3rSECEiNmKQnh4nLybGUsvp2UQqK43FFyaBXogPuzZ/yBt1HhOMTyayZI1lVwHxLkNdUmNcLndb7AqB23BjFGCSPpmN/BACYsgPEJcpCefYBI61JPRlSmKA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782146702; c=relaxed/simple; bh=JfZZSKs8n3LTUzRmhYITSnZnjOxQkbr89BwmCTE+lqE=; h=Message-ID:Date:MIME-Version:Subject:To:Cc:References:From: In-Reply-To:Content-Type; b=ulAurQR4ftHmmmK5kdkpA27IA2NEK4nUZ/PiKiDQ3v6OW3v2tGrp59eoT4TD1yGmzIlKeH2pX1S1UMTAe/Nbq+95vxvlLgdnxtpXgs7MS4v+gyL/uAEzVmldDvmmr03pyysTlq84+y7RN49fL1cFpYrr+lTjsFqJb3hNu1c+Hx8= 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=CsRdLFfi; arc=none smtp.client-ip=95.215.58.174 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="CsRdLFfi" Message-ID: DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1782146698; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=il/CHFZlvXOVfdz3Uj3nhgSGn8a07SJ8y7KWOpcXefE=; b=CsRdLFfi1aBT3qWPVCEqqLyDD3L/TNWmDmV3XOsg6CfYigqzY0L2K1LliUdygwXFd36HcW THK08vM2MAaIkBLClVP2GgjcDWKqMUsc947KRP5bEW3RNjtW/IKsXQUT9j1HVHBN/e+wUy hdvpKHswllvZh/J8Dc70HmFS6cdYjt4= Date: Mon, 22 Jun 2026 17:44:46 +0100 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Subject: Re: [PATCH v2] mm: migrate: requeue destination folio on deferred split queue To: Wei Yang , "David Hildenbrand (Arm)" Cc: Andrew Morton , npache@redhat.com, ziy@nvidia.com, willy@infradead.org, linux-mm@kvack.org, 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 References: <20260310105419.3256755-1-usama.arif@linux.dev> <20260620072721.x4dfh6gy4wnjqre4@master> <20260622134331.xvbpu6edwml65myp@master> Content-Language: en-US X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. From: Usama Arif In-Reply-To: <20260622134331.xvbpu6edwml65myp@master> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Migadu-Flow: FLOW_OUT On 22/06/2026 14:43, Wei Yang wrote: > On Mon, Jun 22, 2026 at 11:16:39AM +0200, David Hildenbrand (Arm) wrote: >> On 6/20/26 09:27, Wei Yang wrote: >>> On Tue, Mar 10, 2026 at 03:54:19AM -0700, Usama Arif wrote: >>>> 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 >>>> --- >>>> 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_folio, unsigned long private, >>>> int rc; >>>> int old_page_state = 0; >>>> struct anon_vma *anon_vma = NULL; >>>> + bool src_deferred_split = false; >>>> + bool src_partially_mapped = false; >>>> struct list_head *prev; >>>> >>>> __migrate_folio_extract(dst, &old_page_state, &anon_vma); >>>> @@ -1373,6 +1375,12 @@ static int migrate_folio_move(free_folio_t put_new_folio, unsigned long private, >>>> goto out_unlock_both; >>>> } >>>> >>>> + if (folio_test_large(src) && folio_test_large_rmappable(src) && >>>> + !data_race(list_empty(&src->_deferred_list))) { >>>> + src_deferred_split = true; >>>> + src_partially_mapped = folio_test_partially_mapped(src); >>>> + } >>> >>> Hi, Usama >>> >>> I am afraid there maybe a race between migration and defer_split. >>> >>> A B >>> migrate_pages_batch deferred_split_scan >>> migrate_folio_unmap list_del_init(&folio->_deferred_list) >>> folio_lock/folio_trylock >>> >>> migrate_folios_move >>> migrate_folio_move >>> list_empty(&src->_deferred_list) >>> folio_trylock() >>> requeue: >>> >>> In case list_empty() check happens after folio removed from defer_list but >>> before requeued, we will miss this folio. >> >> deferred_split_isolate() would grab a reference through folio_try_get(). >> >> How can we migrate a folio with a raised refcount? >> > > Thanks, I missed expected_refcount check in __migrate_folio(). > Thanks David for pointing it out! I have just started looking at the mailing list for today :) >> -- >> Cheers, >> >> David >