6.17-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Hildenbrand david@redhat.com
[ Upstream commit 95c2908f1a4fd608b1cdbb5acef3572e5d769e1c ]
migrate_folio_unmap() is the only user of MIGRATEPAGE_UNMAP. We want to remove MIGRATEPAGE_* completely.
It's rather weird to have a generic MIGRATEPAGE_UNMAP, documented to be returned from address-space callbacks, when it's only used for an internal helper.
Let's start by having only a single "success" return value for migrate_folio_unmap() -- 0 -- by moving the "folio was already freed" check into the single caller.
There is a remaining comment for PG_isolated, which we renamed to PG_movable_ops_isolated recently and forgot to update.
While we might still run into that case with zsmalloc, it's something we want to get rid of soon. So let's just focus that optimization on real folios only for now by excluding movable_ops pages. Note that concurrent freeing can happen at any time and this "already freed" check is not relevant for correctness.
[david@redhat.com: no need to pass "reason" to migrate_folio_unmap(), per Lance] Link: https://lkml.kernel.org/r/3bb725f8-28d7-4aa2-b75f-af40d5cab280@redhat.com Link: https://lkml.kernel.org/r/20250811143949.1117439-2-david@redhat.com Signed-off-by: David Hildenbrand david@redhat.com Reviewed-by: Zi Yan ziy@nvidia.com Reviewed-by: Lance Yang lance.yang@linux.dev Cc: Alistair Popple apopple@nvidia.com Cc: Al Viro viro@zeniv.linux.org.uk Cc: Arnd Bergmann arnd@arndb.de Cc: Benjamin LaHaise bcrl@kvack.org Cc: Byungchul Park byungchul@sk.com Cc: Chris Mason clm@fb.com Cc: Christian Brauner brauner@kernel.org Cc: Christophe Leroy christophe.leroy@csgroup.eu Cc: Dave Kleikamp shaggy@kernel.org Cc: David Sterba dsterba@suse.com Cc: Eugenio Pé rez eperezma@redhat.com Cc: Greg Kroah-Hartman gregkh@linuxfoundation.org Cc: Gregory Price gourry@gourry.net Cc: "Huang, Ying" ying.huang@linux.alibaba.com Cc: Jan Kara jack@suse.cz Cc: Jason Wang jasowang@redhat.com Cc: Jerrin Shaji George jerrin.shaji-george@broadcom.com Cc: Josef Bacik josef@toxicpanda.com Cc: Joshua Hahn joshua.hahnjy@gmail.com Cc: Madhavan Srinivasan maddy@linux.ibm.com Cc: Mathew Brost matthew.brost@intel.com Cc: Michael Ellerman mpe@ellerman.id.au Cc: "Michael S. Tsirkin" mst@redhat.com Cc: Minchan Kim minchan@kernel.org Cc: Muchun Song muchun.song@linux.dev Cc: Nicholas Piggin npiggin@gmail.com Cc: Oscar Salvador osalvador@suse.de Cc: Rakie Kim rakie.kim@sk.com Cc: Sergey Senozhatsky senozhatsky@chromium.org Cc: Xuan Zhuo xuanzhuo@linux.alibaba.com Cc: Dave Kleikamp dave.kleikamp@oracle.com Signed-off-by: Andrew Morton akpm@linux-foundation.org Stable-dep-of: 4ba5a8a7faa6 ("vmw_balloon: indicate success when effectively deflating during migration") Signed-off-by: Sasha Levin sashal@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org --- include/linux/migrate.h | 1 - mm/migrate.c | 45 ++++++++++++++++++++++----------------------- 2 files changed, 22 insertions(+), 24 deletions(-)
--- a/include/linux/migrate.h +++ b/include/linux/migrate.h @@ -18,7 +18,6 @@ struct migration_target_control; * - zero on page migration success; */ #define MIGRATEPAGE_SUCCESS 0 -#define MIGRATEPAGE_UNMAP 1
/** * struct movable_operations - Driver page migration --- a/mm/migrate.c +++ b/mm/migrate.c @@ -1189,7 +1189,7 @@ static void migrate_folio_done(struct fo static int migrate_folio_unmap(new_folio_t get_new_folio, free_folio_t put_new_folio, unsigned long private, struct folio *src, struct folio **dstp, enum migrate_mode mode, - enum migrate_reason reason, struct list_head *ret) + struct list_head *ret) { struct folio *dst; int rc = -EAGAIN; @@ -1198,16 +1198,6 @@ static int migrate_folio_unmap(new_folio bool locked = false; bool dst_locked = false;
- if (folio_ref_count(src) == 1) { - /* Folio was freed from under us. So we are done. */ - folio_clear_active(src); - folio_clear_unevictable(src); - /* free_pages_prepare() will clear PG_isolated. */ - list_del(&src->lru); - migrate_folio_done(src, reason); - return MIGRATEPAGE_SUCCESS; - } - dst = get_new_folio(src, private); if (!dst) return -ENOMEM; @@ -1297,7 +1287,7 @@ static int migrate_folio_unmap(new_folio
if (unlikely(page_has_movable_ops(&src->page))) { __migrate_folio_record(dst, old_page_state, anon_vma); - return MIGRATEPAGE_UNMAP; + return 0; }
/* @@ -1327,7 +1317,7 @@ static int migrate_folio_unmap(new_folio
if (!folio_mapped(src)) { __migrate_folio_record(dst, old_page_state, anon_vma); - return MIGRATEPAGE_UNMAP; + return 0; }
out: @@ -1870,14 +1860,27 @@ static int migrate_pages_batch(struct li continue; }
+ /* + * If we are holding the last folio reference, the folio + * was freed from under us, so just drop our reference. + */ + if (likely(!page_has_movable_ops(&folio->page)) && + folio_ref_count(folio) == 1) { + folio_clear_active(folio); + folio_clear_unevictable(folio); + list_del(&folio->lru); + migrate_folio_done(folio, reason); + stats->nr_succeeded += nr_pages; + stats->nr_thp_succeeded += is_thp; + continue; + } + rc = migrate_folio_unmap(get_new_folio, put_new_folio, - private, folio, &dst, mode, reason, - ret_folios); + private, folio, &dst, mode, ret_folios); /* * The rules are: - * Success: folio will be freed - * Unmap: folio will be put on unmap_folios list, - * dst folio put on dst_folios list + * 0: folio will be put on unmap_folios list, + * dst folio put on dst_folios list * -EAGAIN: stay on the from list * -ENOMEM: stay on the from list * Other errno: put on ret_folios list @@ -1927,11 +1930,7 @@ static int migrate_pages_batch(struct li thp_retry += is_thp; nr_retry_pages += nr_pages; break; - case MIGRATEPAGE_SUCCESS: - stats->nr_succeeded += nr_pages; - stats->nr_thp_succeeded += is_thp; - break; - case MIGRATEPAGE_UNMAP: + case 0: list_move_tail(&folio->lru, &unmap_folios); list_add_tail(&dst->lru, &dst_folios); break;