From: "Garg, Shivank" <shivankg@amd.com>
To: "David Hildenbrand (Arm)" <david@kernel.org>, akpm@linux-foundation.org
Cc: kinseyho@google.com, weixugc@google.com, ljs@kernel.org,
Liam.Howlett@oracle.com, vbabka@kernel.org, willy@infradead.org,
rppt@kernel.org, surenb@google.com, mhocko@suse.com,
ziy@nvidia.com, matthew.brost@intel.com, joshua.hahnjy@gmail.com,
rakie.kim@sk.com, byungchul@sk.com, gourry@gourry.net,
ying.huang@linux.alibaba.com, apopple@nvidia.com,
dave@stgolabs.net, rkodsara@amd.com, vkoul@kernel.org,
bharata@amd.com, sj@kernel.org, rientjes@google.com,
xuezhengchu@huawei.com, yiannis@zptcorp.com,
dave.hansen@intel.com, hannes@cmpxchg.org, jhubbard@nvidia.com,
peterx@redhat.com, riel@surriel.com, shakeel.butt@linux.dev,
stalexan@redhat.com, tj@kernel.org, nifan.cxl@gmail.com,
jic23@kernel.org, aneesh.kumar@kernel.org, nathan.lynch@amd.com,
Frank.li@nxp.com, djbw@kernel.org, linux-kernel@vger.kernel.org,
linux-mm@kvack.org
Subject: Re: [PATCH 3/7] mm/migrate: skip data copy for already-copied folios
Date: Mon, 8 Jun 2026 16:56:57 +0530 [thread overview]
Message-ID: <7e6a7626-5a1b-4672-91bd-85b0f4ee2ecb@amd.com> (raw)
In-Reply-To: <a36348d0-73f5-4599-8d06-c9472d0b8d72@amd.com>
On 5/20/2026 8:51 PM, Garg, Shivank wrote:
>
>
> On 5/11/2026 9:05 PM, David Hildenbrand (Arm) wrote:
>> On 4/28/26 17:50, Shivank Garg wrote:
>>> Add a FOLIO_ALREADY_COPIED flag to the dst->migrate_info migration
>>> state. When set, __migrate_folio() skips folio_mc_copy() and
>>> performs metadata-only migration. All callers currently pass
>>> already_copied=false. The batch-copy path enables it later in a
>>> subsequent patch.
>>>
>>> Move the dst->migrate_info state enum earlier in the file so
>>> __migrate_folio() and move_to_new_folio() can see FOLIO_ALREADY_COPIED.
>>>
>>> Signed-off-by: Shivank Garg <shivankg@amd.com>
>>> ---
>>> mm/migrate.c | 53 +++++++++++++++++++++++++++++++---------------------
>>> 1 file changed, 32 insertions(+), 21 deletions(-)
>>>
>>> diff --git a/mm/migrate.c b/mm/migrate.c
>>> index 03c2a6f7e5e4..c493e67e359d 100644
>>> --- a/mm/migrate.c
>>> +++ b/mm/migrate.c
>>> @@ -850,6 +850,19 @@ void folio_migrate_flags(struct folio *newfolio, struct folio *folio)
>>> }
>>> EXPORT_SYMBOL(folio_migrate_flags);
>>>
>>> +/*
>>> + * To record some information during migration, we use the migrate_info
>>> + * field of struct folio of the newly allocated destination folio.
>>> + * This is safe because nobody is using it except us.
>>> + */
>>> +enum {
>>> + FOLIO_WAS_MAPPED = BIT(0),
>>> + FOLIO_WAS_MLOCKED = BIT(1),
>>> + FOLIO_ALREADY_COPIED = BIT(2),
>>
>> I wonder whether we want to talk about "folio content copied", to not confuse it
>> with folio flags copied etc.
>>
>> FOLIO_CONTENT_COPIED.
>>
>> Thoughts?
>
> Good point, this is more precise.
>
Sashiko Comment:
Does expanding FOLIO_OLD_STATES to include BIT(2) silently corrupt anon_vma
pointers on 32-bit architectures?
The anon_vma pointer is packed with FOLIO_OLD_STATES inside dst->migrate_info.
To separate them, __migrate_folio_extract() uses info & ~FOLIO_OLD_STATES.
Since anon_vma objects are allocated from a kmem_cache with align=0,
ARCH_SLAB_MINALIGN defaults to 4 bytes on many 32-bit architectures. This
means a valid anon_vma pointer can legitimately end in 0x4 or 0xC (meaning
bit 2 is set).
When __migrate_folio_extract() masks the pointer with ~7, it will silently
clear bit 2 from the anon_vma pointer. Any subsequent call to put_anon_vma()
with this corrupted pointer could cause a use-after-free or a kernel panic.
--
#define ARCH_SLAB_MINALIGN __alignof__(unsigned long long)
I initially assumed this to be always 8, confusing it to be same as size of
unsigned long long.
But the GCC docs note that alignment can be smaller in size:
https://gcc.gnu.org/onlinedocs/gcc/Alignment.html
"For example, if the target machine requires a double value to be aligned on
an 8-byte boundary, then __alignof__ (double) is 8. This is true on many RISC
machines. On more traditional machine designs, __alignof__ (double) is 4 or
even 2."
If my understanding is right, Sashiko concern is valid, and I can't safely
use BIT(2).
I see few option from here. Either I can gate batch copy for CONFIG_64BIT,
or I can force anon_vma_cachep to 8-byte alignment via kmem_cache_create()
align arg. Or I can change the migrate_folio() callback to pass already_copied
info to change to dst->migrate_info enum.
I'm not sure if touching the anon_vma cache would be preferred? Gating the change
to CONFIG_64BIT feels less risky to me.
Thanks,
Shivank
>>> + FOLIO_OLD_STATES = FOLIO_WAS_MAPPED | FOLIO_WAS_MLOCKED |
>>> + FOLIO_ALREADY_COPIED,
>>> +};
>>> +
>>> /************************************************************
>>> * Migration functions
>>> ***********************************************************/
>>> @@ -859,14 +872,20 @@ static int __migrate_folio(struct address_space *mapping, struct folio *dst,
>>> enum migrate_mode mode)
>>> {
>>> int rc, expected_count = folio_expected_ref_count(src) + 1;
>>> + bool already_copied = (dst->migrate_info & FOLIO_ALREADY_COPIED);
>>
>> const, and no need for ().
>
> Will fix.
>
>>> +
>>> + if (already_copied)
>>> + dst->migrate_info = 0;
>>
>> Hm, why is that required? Might deserve a comment.
>>
>> Likely you want to clear the "already copied" marker?
>>
>> dst->migrate_info &= ~FOLIO_ALREADY_COPIED;
>>
>> ?
>
> Yes,
> In current code, migrate_info only carry FOLIO_ALREADY_COPIED.
> So, =0 and &=~ are equivalent and similar for |= case. I mirrored the
> how anon_vma/old_folio_state get handled __migrate_folio_extract().
>
> But with your other suggestion of marking already_copied immediately
> after folio_mc_copy(), then bitwise clear and set will be required.
> I'll do this.
>
>
>
>> But I wonder if this really belongs exactly here.
>>
>
> I did not understand this.
>
>
>>>
>>> /* Check whether src does not have extra refs before we do more work */
>>> if (folio_ref_count(src) != expected_count)
>>> return -EAGAIN;
>>>
>>> - rc = folio_mc_copy(dst, src);
>>> - if (unlikely(rc))
>>> - return rc;
>>> + if (!already_copied) {
>>> + rc = folio_mc_copy(dst, src);
>>> + if (unlikely(rc))
>>> + return rc;
>>> + }
>>>
>>> rc = __folio_migrate_mapping(mapping, dst, src, expected_count);
>>> if (rc)
>>> @@ -1090,7 +1109,7 @@ static int fallback_migrate_folio(struct address_space *mapping,
>>> * 0 - success
>>> */
>>> static int move_to_new_folio(struct folio *dst, struct folio *src,
>>> - enum migrate_mode mode)
>>> + enum migrate_mode mode, bool already_copied)
>>> {
>>> struct address_space *mapping = folio_mapping(src);
>>> int rc = -EAGAIN;
>>> @@ -1098,6 +1117,9 @@ static int move_to_new_folio(struct folio *dst, struct folio *src,
>>> VM_BUG_ON_FOLIO(!folio_test_locked(src), src);
>>> VM_BUG_ON_FOLIO(!folio_test_locked(dst), dst);
>>>
>>> + if (already_copied)
>>> + dst->migrate_info = FOLIO_ALREADY_COPIED;
>>
>> |= ?
>>
>
> Will do.
>
>>> +
>>> if (!mapping)
>>> rc = migrate_folio(mapping, dst, src, mode);
>>> else if (mapping_inaccessible(mapping))
>>> @@ -1129,17 +1151,6 @@ static int move_to_new_folio(struct folio *dst, struct folio *src,
>>> return rc;
>>> }
>>>
>>> -/*
>>> - * To record some information during migration, we use the migrate_info
>>> - * field of struct folio of the newly allocated destination folio.
>>> - * This is safe because nobody is using it except us.
>>> - */
>>> -enum {
>>> - FOLIO_WAS_MAPPED = BIT(0),
>>> - FOLIO_WAS_MLOCKED = BIT(1),
>>> - FOLIO_OLD_STATES = FOLIO_WAS_MAPPED | FOLIO_WAS_MLOCKED,
>>> -};
>>> -
>>> static void __migrate_folio_record(struct folio *dst,
>>> int old_folio_state, struct anon_vma *anon_vma)
>>> {
>>> @@ -1353,7 +1364,7 @@ static int migrate_folio_unmap(new_folio_t get_new_folio,
>>> static int migrate_folio_move(free_folio_t put_new_folio, unsigned long private,
>>> struct folio *src, struct folio *dst,
>>> enum migrate_mode mode, enum migrate_reason reason,
>>> - struct list_head *ret)
>>> + struct list_head *ret, bool already_copied)
>>> {
>>> int rc;
>>> int old_folio_state = 0;
>>> @@ -1379,7 +1390,7 @@ static int migrate_folio_move(free_folio_t put_new_folio, unsigned long private,
>>> src_partially_mapped = folio_test_partially_mapped(src);
>>> }
>>>
>>> - rc = move_to_new_folio(dst, src, mode);
>>> + rc = move_to_new_folio(dst, src, mode, already_copied);
>>> if (rc)
>>> goto out;
>>>
>>> @@ -1536,7 +1547,7 @@ static int unmap_and_move_huge_page(new_folio_t get_new_folio,
>>> }
>>>
>>> if (!folio_mapped(src))
>>> - rc = move_to_new_folio(dst, src, mode);
>>> + rc = move_to_new_folio(dst, src, mode, false);
>>
>> ... mode, /* already_copied = */ false
>>
>
> will fix
>
>>>
>>> if (page_was_mapped)
>>> remove_migration_ptes(src, !rc ? dst : src, ttu);
>>> @@ -1720,7 +1731,7 @@ static void migrate_folios_move(struct list_head *src_folios,
>>> struct list_head *ret_folios,
>>> struct migrate_pages_stats *stats,
>>> int *retry, int *thp_retry, int *nr_failed,
>>> - int *nr_retry_pages)
>>> + int *nr_retry_pages, bool already_copied)
>>> {
>>> struct folio *folio, *folio2, *dst, *dst2;
>>> bool is_thp;
>>> @@ -1737,7 +1748,7 @@ static void migrate_folios_move(struct list_head *src_folios,
>>>
>>> rc = migrate_folio_move(put_new_folio, private,
>>> folio, dst, mode,
>>> - reason, ret_folios);
>>> + reason, ret_folios, already_copied);
>>> /*
>>> * The rules are:
>>> * 0: folio will be freed
>>> @@ -1994,7 +2005,7 @@ static int migrate_pages_batch(struct list_head *from,
>>> migrate_folios_move(&unmap_folios, &dst_folios,
>>> put_new_folio, private, mode, reason,
>>> ret_folios, stats, &retry, &thp_retry,
>>> - &nr_failed, &nr_retry_pages);
>>> + &nr_failed, &nr_retry_pages, false);
>>> }
>>
>> dito.
>>
>
> will fix.
>
> Thanks,
> Shivank
next prev parent reply other threads:[~2026-06-08 11:27 UTC|newest]
Thread overview: 67+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-28 15:50 [PATCH 0/7] Accelerate page migration with batch copying and hardware offload Shivank Garg
2026-04-28 15:50 ` [PATCH 1/7] mm/migrate: rename PAGE_ migration flags to FOLIO_ Shivank Garg
2026-04-30 9:07 ` Huang, Ying
2026-05-18 16:54 ` Jonathan Cameron
2026-05-18 23:51 ` Zi Yan
2026-06-09 5:34 ` Dev Jain
2026-06-09 6:17 ` Garg, Shivank
2026-06-09 6:23 ` Dev Jain
2026-04-28 15:50 ` [PATCH 2/7] mm/migrate: use migrate_info field instead of private Shivank Garg
2026-05-07 9:43 ` Huang, Ying
2026-05-11 15:22 ` David Hildenbrand (Arm)
2026-05-18 16:56 ` Jonathan Cameron
2026-04-28 15:50 ` [PATCH 3/7] mm/migrate: skip data copy for already-copied folios Shivank Garg
2026-05-11 15:35 ` David Hildenbrand (Arm)
2026-05-20 15:21 ` Garg, Shivank
2026-06-08 11:26 ` Garg, Shivank [this message]
2026-06-08 15:18 ` David Hildenbrand (Arm)
2026-06-08 15:41 ` Zi Yan
2026-06-08 15:43 ` David Hildenbrand (Arm)
2026-06-08 19:32 ` Garg, Shivank
2026-06-09 12:55 ` David Hildenbrand (Arm)
2026-06-08 15:09 ` David Hildenbrand (Arm)
2026-04-28 15:50 ` [PATCH 4/7] mm/migrate: add batch-copy path in migrate_pages_batch Shivank Garg
2026-05-11 15:40 ` David Hildenbrand (Arm)
2026-05-20 15:06 ` Garg, Shivank
2026-06-08 15:25 ` David Hildenbrand (Arm)
2026-06-08 15:36 ` Zi Yan
2026-06-08 20:40 ` Garg, Shivank
2026-06-08 21:17 ` Karim Manaouil
2026-05-21 13:20 ` Garg, Shivank
2026-04-28 15:50 ` [PATCH 5/7] mm/migrate: add copy offload registration infrastructure Shivank Garg
2026-05-11 15:46 ` David Hildenbrand (Arm)
2026-05-20 15:24 ` Garg, Shivank
2026-05-11 15:50 ` David Hildenbrand (Arm)
2026-05-20 15:22 ` Garg, Shivank
2026-05-25 2:16 ` David Rientjes
2026-05-25 2:19 ` David Rientjes
2026-06-11 9:55 ` Karim Manaouil
2026-06-11 18:44 ` Zi Yan
2026-04-28 15:50 ` [PATCH 6/7] drivers/migrate_offload: add DMA batch copy driver (dcbm) Shivank Garg
2026-06-09 0:00 ` Karim Manaouil
2026-06-09 7:31 ` Garg, Shivank
2026-06-09 16:17 ` Karim Manaouil
2026-06-10 12:26 ` Shivank Garg
2026-06-19 16:07 ` [PATCH 6/7] drivers/migrate_offload: add DMA batch copy driver (dcbm) Karim Manaouil
2026-06-19 16:32 ` Karim Manaouil
2026-06-22 10:03 ` Garg, Shivank
2026-04-28 15:50 ` [PATCH 7/7] mm/migrate: adjust NR_MAX_BATCHED_MIGRATION for testing Shivank Garg
2026-04-28 17:11 ` [PATCH 0/7] Accelerate page migration with batch copying and hardware offload Garg, Shivank
2026-04-28 19:33 ` David Hildenbrand (Arm)
2026-04-29 5:51 ` Garg, Shivank
2026-04-30 8:47 ` Huang, Ying
2026-05-08 11:04 ` Garg, Shivank
2026-05-08 11:28 ` Huang, Ying
2026-05-08 12:34 ` Garg, Shivank
2026-05-09 7:49 ` Huang, Ying
2026-05-10 15:03 ` Garg, Shivank
2026-05-12 2:15 ` Huang, Ying
2026-05-20 15:23 ` Garg, Shivank
2026-05-07 9:58 ` Huang, Ying
2026-05-11 15:19 ` David Hildenbrand (Arm)
2026-05-12 1:45 ` Huang, Ying
2026-05-11 15:53 ` David Hildenbrand (Arm)
2026-05-12 2:35 ` Huang, Ying
2026-05-12 6:34 ` David Hildenbrand (Arm)
2026-05-14 6:42 ` Huang, Ying
2026-05-20 15:35 ` Garg, Shivank
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=7e6a7626-5a1b-4672-91bd-85b0f4ee2ecb@amd.com \
--to=shivankg@amd.com \
--cc=Frank.li@nxp.com \
--cc=Liam.Howlett@oracle.com \
--cc=akpm@linux-foundation.org \
--cc=aneesh.kumar@kernel.org \
--cc=apopple@nvidia.com \
--cc=bharata@amd.com \
--cc=byungchul@sk.com \
--cc=dave.hansen@intel.com \
--cc=dave@stgolabs.net \
--cc=david@kernel.org \
--cc=djbw@kernel.org \
--cc=gourry@gourry.net \
--cc=hannes@cmpxchg.org \
--cc=jhubbard@nvidia.com \
--cc=jic23@kernel.org \
--cc=joshua.hahnjy@gmail.com \
--cc=kinseyho@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=matthew.brost@intel.com \
--cc=mhocko@suse.com \
--cc=nathan.lynch@amd.com \
--cc=nifan.cxl@gmail.com \
--cc=peterx@redhat.com \
--cc=rakie.kim@sk.com \
--cc=riel@surriel.com \
--cc=rientjes@google.com \
--cc=rkodsara@amd.com \
--cc=rppt@kernel.org \
--cc=shakeel.butt@linux.dev \
--cc=sj@kernel.org \
--cc=stalexan@redhat.com \
--cc=surenb@google.com \
--cc=tj@kernel.org \
--cc=vbabka@kernel.org \
--cc=vkoul@kernel.org \
--cc=weixugc@google.com \
--cc=willy@infradead.org \
--cc=xuezhengchu@huawei.com \
--cc=yiannis@zptcorp.com \
--cc=ying.huang@linux.alibaba.com \
--cc=ziy@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.