Merge tag 'mm-hotfixes-stable-2023-03-14-16-51' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Pull misc fixes from Andrew Morton:
 "Eleven hotfixes.

  Four of these are cc:stable and the remainder address post-6.2 issues
  or aren't considered suitable for backporting.

  Seven of these fixes are for MM"

* tag 'mm-hotfixes-stable-2023-03-14-16-51' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm:
  mm/damon/paddr: fix folio_nr_pages() after folio_put() in damon_pa_mark_accessed_or_deactivate()
  mm/damon/paddr: fix folio_size() call after folio_put() in damon_pa_young()
  ocfs2: fix data corruption after failed write
  migrate_pages: try migrate in batch asynchronously firstly
  migrate_pages: move split folios processing out of migrate_pages_batch()
  migrate_pages: fix deadlock in batched migration
  .mailmap: add Alexandre Ghiti personal email address
  mailmap: correct Dikshita Agarwal's Qualcomm email address
  mailmap: updates for Jarkko Sakkinen
  mm/userfaultfd: propagate uffd-wp bit when PTE-mapping the huge zeropage
  mm: teach mincore_hugetlb about pte markers
This commit is contained in:
Linus Torvalds
2023-03-14 17:13:58 -07:00
6 changed files with 122 additions and 99 deletions

View File

@@ -28,6 +28,7 @@ Alexander Lobakin <alobakin@pm.me> <bloodyreaper@yandex.ru>
Alexander Mikhalitsyn <alexander@mihalicyn.com> <alexander.mikhalitsyn@virtuozzo.com> Alexander Mikhalitsyn <alexander@mihalicyn.com> <alexander.mikhalitsyn@virtuozzo.com>
Alexander Mikhalitsyn <alexander@mihalicyn.com> <aleksandr.mikhalitsyn@canonical.com> Alexander Mikhalitsyn <alexander@mihalicyn.com> <aleksandr.mikhalitsyn@canonical.com>
Alexandre Belloni <alexandre.belloni@bootlin.com> <alexandre.belloni@free-electrons.com> Alexandre Belloni <alexandre.belloni@bootlin.com> <alexandre.belloni@free-electrons.com>
Alexandre Ghiti <alex@ghiti.fr> <alexandre.ghiti@canonical.com>
Alexei Starovoitov <ast@kernel.org> <alexei.starovoitov@gmail.com> Alexei Starovoitov <ast@kernel.org> <alexei.starovoitov@gmail.com>
Alexei Starovoitov <ast@kernel.org> <ast@fb.com> Alexei Starovoitov <ast@kernel.org> <ast@fb.com>
Alexei Starovoitov <ast@kernel.org> <ast@plumgrid.com> Alexei Starovoitov <ast@kernel.org> <ast@plumgrid.com>
@@ -121,7 +122,7 @@ Dengcheng Zhu <dzhu@wavecomp.com> <dengcheng.zhu@gmail.com>
Dengcheng Zhu <dzhu@wavecomp.com> <dengcheng.zhu@imgtec.com> Dengcheng Zhu <dzhu@wavecomp.com> <dengcheng.zhu@imgtec.com>
Dengcheng Zhu <dzhu@wavecomp.com> <dengcheng.zhu@mips.com> Dengcheng Zhu <dzhu@wavecomp.com> <dengcheng.zhu@mips.com>
<dev.kurt@vandijck-laurijssen.be> <kurt.van.dijck@eia.be> <dev.kurt@vandijck-laurijssen.be> <kurt.van.dijck@eia.be>
Dikshita Agarwal <dikshita@qti.qualcomm.com> <dikshita@codeaurora.org> Dikshita Agarwal <quic_dikshita@quicinc.com> <dikshita@codeaurora.org>
Dmitry Baryshkov <dbaryshkov@gmail.com> Dmitry Baryshkov <dbaryshkov@gmail.com>
Dmitry Baryshkov <dbaryshkov@gmail.com> <[dbaryshkov@gmail.com]> Dmitry Baryshkov <dbaryshkov@gmail.com> <[dbaryshkov@gmail.com]>
Dmitry Baryshkov <dbaryshkov@gmail.com> <dmitry_baryshkov@mentor.com> Dmitry Baryshkov <dbaryshkov@gmail.com> <dmitry_baryshkov@mentor.com>
@@ -194,6 +195,7 @@ Jan Glauber <jan.glauber@gmail.com> <jang@linux.vnet.ibm.com>
Jan Glauber <jan.glauber@gmail.com> <jglauber@cavium.com> Jan Glauber <jan.glauber@gmail.com> <jglauber@cavium.com>
Jarkko Sakkinen <jarkko@kernel.org> <jarkko.sakkinen@linux.intel.com> Jarkko Sakkinen <jarkko@kernel.org> <jarkko.sakkinen@linux.intel.com>
Jarkko Sakkinen <jarkko@kernel.org> <jarkko@profian.com> Jarkko Sakkinen <jarkko@kernel.org> <jarkko@profian.com>
Jarkko Sakkinen <jarkko@kernel.org> <jarkko.sakkinen@tuni.fi>
Jason Gunthorpe <jgg@ziepe.ca> <jgg@mellanox.com> Jason Gunthorpe <jgg@ziepe.ca> <jgg@mellanox.com>
Jason Gunthorpe <jgg@ziepe.ca> <jgg@nvidia.com> Jason Gunthorpe <jgg@ziepe.ca> <jgg@nvidia.com>
Jason Gunthorpe <jgg@ziepe.ca> <jgunthorpe@obsidianresearch.com> Jason Gunthorpe <jgg@ziepe.ca> <jgunthorpe@obsidianresearch.com>

View File

@@ -1977,11 +1977,26 @@ int ocfs2_write_end_nolock(struct address_space *mapping,
} }
if (unlikely(copied < len) && wc->w_target_page) { if (unlikely(copied < len) && wc->w_target_page) {
loff_t new_isize;
if (!PageUptodate(wc->w_target_page)) if (!PageUptodate(wc->w_target_page))
copied = 0; copied = 0;
ocfs2_zero_new_buffers(wc->w_target_page, start+copied, new_isize = max_t(loff_t, i_size_read(inode), pos + copied);
start+len); if (new_isize > page_offset(wc->w_target_page))
ocfs2_zero_new_buffers(wc->w_target_page, start+copied,
start+len);
else {
/*
* When page is fully beyond new isize (data copy
* failed), do not bother zeroing the page. Invalidate
* it instead so that writeback does not get confused
* put page & buffer dirty bits into inconsistent
* state.
*/
block_invalidate_folio(page_folio(wc->w_target_page),
0, PAGE_SIZE);
}
} }
if (wc->w_target_page) if (wc->w_target_page)
flush_dcache_page(wc->w_target_page); flush_dcache_page(wc->w_target_page);

View File

@@ -130,7 +130,6 @@ static bool damon_pa_young(unsigned long paddr, unsigned long *folio_sz)
accessed = false; accessed = false;
else else
accessed = true; accessed = true;
folio_put(folio);
goto out; goto out;
} }
@@ -144,10 +143,10 @@ static bool damon_pa_young(unsigned long paddr, unsigned long *folio_sz)
if (need_lock) if (need_lock)
folio_unlock(folio); folio_unlock(folio);
folio_put(folio);
out: out:
*folio_sz = folio_size(folio); *folio_sz = folio_size(folio);
folio_put(folio);
return accessed; return accessed;
} }
@@ -281,8 +280,8 @@ static inline unsigned long damon_pa_mark_accessed_or_deactivate(
folio_mark_accessed(folio); folio_mark_accessed(folio);
else else
folio_deactivate(folio); folio_deactivate(folio);
folio_put(folio);
applied += folio_nr_pages(folio); applied += folio_nr_pages(folio);
folio_put(folio);
} }
return applied * PAGE_SIZE; return applied * PAGE_SIZE;
} }

View File

@@ -2037,7 +2037,7 @@ static void __split_huge_zero_page_pmd(struct vm_area_struct *vma,
{ {
struct mm_struct *mm = vma->vm_mm; struct mm_struct *mm = vma->vm_mm;
pgtable_t pgtable; pgtable_t pgtable;
pmd_t _pmd; pmd_t _pmd, old_pmd;
int i; int i;
/* /*
@@ -2048,7 +2048,7 @@ static void __split_huge_zero_page_pmd(struct vm_area_struct *vma,
* *
* See Documentation/mm/mmu_notifier.rst * See Documentation/mm/mmu_notifier.rst
*/ */
pmdp_huge_clear_flush(vma, haddr, pmd); old_pmd = pmdp_huge_clear_flush(vma, haddr, pmd);
pgtable = pgtable_trans_huge_withdraw(mm, pmd); pgtable = pgtable_trans_huge_withdraw(mm, pmd);
pmd_populate(mm, &_pmd, pgtable); pmd_populate(mm, &_pmd, pgtable);
@@ -2057,6 +2057,8 @@ static void __split_huge_zero_page_pmd(struct vm_area_struct *vma,
pte_t *pte, entry; pte_t *pte, entry;
entry = pfn_pte(my_zero_pfn(haddr), vma->vm_page_prot); entry = pfn_pte(my_zero_pfn(haddr), vma->vm_page_prot);
entry = pte_mkspecial(entry); entry = pte_mkspecial(entry);
if (pmd_uffd_wp(old_pmd))
entry = pte_mkuffd_wp(entry);
pte = pte_offset_map(&_pmd, haddr); pte = pte_offset_map(&_pmd, haddr);
VM_BUG_ON(!pte_none(*pte)); VM_BUG_ON(!pte_none(*pte));
set_pte_at(mm, haddr, pte, entry); set_pte_at(mm, haddr, pte, entry);

View File

@@ -1112,9 +1112,8 @@ static void migrate_folio_done(struct folio *src,
/* Obtain the lock on page, remove all ptes. */ /* Obtain the lock on page, remove all ptes. */
static int migrate_folio_unmap(new_page_t get_new_page, free_page_t put_new_page, static int migrate_folio_unmap(new_page_t get_new_page, free_page_t put_new_page,
unsigned long private, struct folio *src, unsigned long private, struct folio *src,
struct folio **dstp, int force, bool avoid_force_lock, struct folio **dstp, enum migrate_mode mode,
enum migrate_mode mode, enum migrate_reason reason, enum migrate_reason reason, struct list_head *ret)
struct list_head *ret)
{ {
struct folio *dst; struct folio *dst;
int rc = -EAGAIN; int rc = -EAGAIN;
@@ -1144,7 +1143,7 @@ static int migrate_folio_unmap(new_page_t get_new_page, free_page_t put_new_page
dst->private = NULL; dst->private = NULL;
if (!folio_trylock(src)) { if (!folio_trylock(src)) {
if (!force || mode == MIGRATE_ASYNC) if (mode == MIGRATE_ASYNC)
goto out; goto out;
/* /*
@@ -1163,17 +1162,6 @@ static int migrate_folio_unmap(new_page_t get_new_page, free_page_t put_new_page
if (current->flags & PF_MEMALLOC) if (current->flags & PF_MEMALLOC)
goto out; goto out;
/*
* We have locked some folios and are going to wait to lock
* this folio. To avoid a potential deadlock, let's bail
* out and not do that. The locked folios will be moved and
* unlocked, then we can wait to lock this folio.
*/
if (avoid_force_lock) {
rc = -EDEADLOCK;
goto out;
}
folio_lock(src); folio_lock(src);
} }
locked = true; locked = true;
@@ -1193,8 +1181,6 @@ static int migrate_folio_unmap(new_page_t get_new_page, free_page_t put_new_page
rc = -EBUSY; rc = -EBUSY;
goto out; goto out;
} }
if (!force)
goto out;
folio_wait_writeback(src); folio_wait_writeback(src);
} }
@@ -1253,7 +1239,7 @@ static int migrate_folio_unmap(new_page_t get_new_page, free_page_t put_new_page
/* Establish migration ptes */ /* Establish migration ptes */
VM_BUG_ON_FOLIO(folio_test_anon(src) && VM_BUG_ON_FOLIO(folio_test_anon(src) &&
!folio_test_ksm(src) && !anon_vma, src); !folio_test_ksm(src) && !anon_vma, src);
try_to_migrate(src, TTU_BATCH_FLUSH); try_to_migrate(src, mode == MIGRATE_ASYNC ? TTU_BATCH_FLUSH : 0);
page_was_mapped = 1; page_was_mapped = 1;
} }
@@ -1267,7 +1253,7 @@ out:
* A folio that has not been unmapped will be restored to * A folio that has not been unmapped will be restored to
* right list unless we want to retry. * right list unless we want to retry.
*/ */
if (rc == -EAGAIN || rc == -EDEADLOCK) if (rc == -EAGAIN)
ret = NULL; ret = NULL;
migrate_folio_undo_src(src, page_was_mapped, anon_vma, locked, ret); migrate_folio_undo_src(src, page_was_mapped, anon_vma, locked, ret);
@@ -1508,6 +1494,9 @@ static inline int try_split_folio(struct folio *folio, struct list_head *split_f
#define NR_MAX_BATCHED_MIGRATION 512 #define NR_MAX_BATCHED_MIGRATION 512
#endif #endif
#define NR_MAX_MIGRATE_PAGES_RETRY 10 #define NR_MAX_MIGRATE_PAGES_RETRY 10
#define NR_MAX_MIGRATE_ASYNC_RETRY 3
#define NR_MAX_MIGRATE_SYNC_RETRY \
(NR_MAX_MIGRATE_PAGES_RETRY - NR_MAX_MIGRATE_ASYNC_RETRY)
struct migrate_pages_stats { struct migrate_pages_stats {
int nr_succeeded; /* Normal and large folios migrated successfully, in int nr_succeeded; /* Normal and large folios migrated successfully, in
@@ -1618,13 +1607,19 @@ static int migrate_hugetlbs(struct list_head *from, new_page_t get_new_page,
/* /*
* migrate_pages_batch() first unmaps folios in the from list as many as * migrate_pages_batch() first unmaps folios in the from list as many as
* possible, then move the unmapped folios. * possible, then move the unmapped folios.
*
* We only batch migration if mode == MIGRATE_ASYNC to avoid to wait a
* lock or bit when we have locked more than one folio. Which may cause
* deadlock (e.g., for loop device). So, if mode != MIGRATE_ASYNC, the
* length of the from list must be <= 1.
*/ */
static int migrate_pages_batch(struct list_head *from, new_page_t get_new_page, static int migrate_pages_batch(struct list_head *from, new_page_t get_new_page,
free_page_t put_new_page, unsigned long private, free_page_t put_new_page, unsigned long private,
enum migrate_mode mode, int reason, struct list_head *ret_folios, enum migrate_mode mode, int reason, struct list_head *ret_folios,
struct migrate_pages_stats *stats) struct list_head *split_folios, struct migrate_pages_stats *stats,
int nr_pass)
{ {
int retry; int retry = 1;
int large_retry = 1; int large_retry = 1;
int thp_retry = 1; int thp_retry = 1;
int nr_failed = 0; int nr_failed = 0;
@@ -1634,21 +1629,15 @@ static int migrate_pages_batch(struct list_head *from, new_page_t get_new_page,
bool is_large = false; bool is_large = false;
bool is_thp = false; bool is_thp = false;
struct folio *folio, *folio2, *dst = NULL, *dst2; struct folio *folio, *folio2, *dst = NULL, *dst2;
int rc, rc_saved, nr_pages; int rc, rc_saved = 0, nr_pages;
LIST_HEAD(split_folios);
LIST_HEAD(unmap_folios); LIST_HEAD(unmap_folios);
LIST_HEAD(dst_folios); LIST_HEAD(dst_folios);
bool nosplit = (reason == MR_NUMA_MISPLACED); bool nosplit = (reason == MR_NUMA_MISPLACED);
bool no_split_folio_counting = false;
bool avoid_force_lock;
retry: VM_WARN_ON_ONCE(mode != MIGRATE_ASYNC &&
rc_saved = 0; !list_empty(from) && !list_is_singular(from));
avoid_force_lock = false;
retry = 1; for (pass = 0; pass < nr_pass && (retry || large_retry); pass++) {
for (pass = 0;
pass < NR_MAX_MIGRATE_PAGES_RETRY && (retry || large_retry);
pass++) {
retry = 0; retry = 0;
large_retry = 0; large_retry = 0;
thp_retry = 0; thp_retry = 0;
@@ -1679,7 +1668,7 @@ retry:
if (!thp_migration_supported() && is_thp) { if (!thp_migration_supported() && is_thp) {
nr_large_failed++; nr_large_failed++;
stats->nr_thp_failed++; stats->nr_thp_failed++;
if (!try_split_folio(folio, &split_folios)) { if (!try_split_folio(folio, split_folios)) {
stats->nr_thp_split++; stats->nr_thp_split++;
continue; continue;
} }
@@ -1689,15 +1678,13 @@ retry:
} }
rc = migrate_folio_unmap(get_new_page, put_new_page, private, rc = migrate_folio_unmap(get_new_page, put_new_page, private,
folio, &dst, pass > 2, avoid_force_lock, folio, &dst, mode, reason, ret_folios);
mode, reason, ret_folios);
/* /*
* The rules are: * The rules are:
* Success: folio will be freed * Success: folio will be freed
* Unmap: folio will be put on unmap_folios list, * Unmap: folio will be put on unmap_folios list,
* dst folio put on dst_folios list * dst folio put on dst_folios list
* -EAGAIN: stay on the from list * -EAGAIN: stay on the from list
* -EDEADLOCK: stay on the from list
* -ENOMEM: stay on the from list * -ENOMEM: stay on the from list
* Other errno: put on ret_folios list * Other errno: put on ret_folios list
*/ */
@@ -1712,7 +1699,7 @@ retry:
stats->nr_thp_failed += is_thp; stats->nr_thp_failed += is_thp;
/* Large folio NUMA faulting doesn't split to retry. */ /* Large folio NUMA faulting doesn't split to retry. */
if (!nosplit) { if (!nosplit) {
int ret = try_split_folio(folio, &split_folios); int ret = try_split_folio(folio, split_folios);
if (!ret) { if (!ret) {
stats->nr_thp_split += is_thp; stats->nr_thp_split += is_thp;
@@ -1729,18 +1716,11 @@ retry:
break; break;
} }
} }
} else if (!no_split_folio_counting) { } else {
nr_failed++; nr_failed++;
} }
stats->nr_failed_pages += nr_pages + nr_retry_pages; stats->nr_failed_pages += nr_pages + nr_retry_pages;
/*
* There might be some split folios of fail-to-migrate large
* folios left in split_folios list. Move them to ret_folios
* list so that they could be put back to the right list by
* the caller otherwise the folio refcnt will be leaked.
*/
list_splice_init(&split_folios, ret_folios);
/* nr_failed isn't updated for not used */ /* nr_failed isn't updated for not used */
nr_large_failed += large_retry; nr_large_failed += large_retry;
stats->nr_thp_failed += thp_retry; stats->nr_thp_failed += thp_retry;
@@ -1749,19 +1729,11 @@ retry:
goto out; goto out;
else else
goto move; goto move;
case -EDEADLOCK:
/*
* The folio cannot be locked for potential deadlock.
* Go move (and unlock) all locked folios. Then we can
* try again.
*/
rc_saved = rc;
goto move;
case -EAGAIN: case -EAGAIN:
if (is_large) { if (is_large) {
large_retry++; large_retry++;
thp_retry += is_thp; thp_retry += is_thp;
} else if (!no_split_folio_counting) { } else {
retry++; retry++;
} }
nr_retry_pages += nr_pages; nr_retry_pages += nr_pages;
@@ -1771,11 +1743,6 @@ retry:
stats->nr_thp_succeeded += is_thp; stats->nr_thp_succeeded += is_thp;
break; break;
case MIGRATEPAGE_UNMAP: case MIGRATEPAGE_UNMAP:
/*
* We have locked some folios, don't force lock
* to avoid deadlock.
*/
avoid_force_lock = true;
list_move_tail(&folio->lru, &unmap_folios); list_move_tail(&folio->lru, &unmap_folios);
list_add_tail(&dst->lru, &dst_folios); list_add_tail(&dst->lru, &dst_folios);
break; break;
@@ -1789,7 +1756,7 @@ retry:
if (is_large) { if (is_large) {
nr_large_failed++; nr_large_failed++;
stats->nr_thp_failed += is_thp; stats->nr_thp_failed += is_thp;
} else if (!no_split_folio_counting) { } else {
nr_failed++; nr_failed++;
} }
@@ -1807,9 +1774,7 @@ move:
try_to_unmap_flush(); try_to_unmap_flush();
retry = 1; retry = 1;
for (pass = 0; for (pass = 0; pass < nr_pass && (retry || large_retry); pass++) {
pass < NR_MAX_MIGRATE_PAGES_RETRY && (retry || large_retry);
pass++) {
retry = 0; retry = 0;
large_retry = 0; large_retry = 0;
thp_retry = 0; thp_retry = 0;
@@ -1838,7 +1803,7 @@ move:
if (is_large) { if (is_large) {
large_retry++; large_retry++;
thp_retry += is_thp; thp_retry += is_thp;
} else if (!no_split_folio_counting) { } else {
retry++; retry++;
} }
nr_retry_pages += nr_pages; nr_retry_pages += nr_pages;
@@ -1851,7 +1816,7 @@ move:
if (is_large) { if (is_large) {
nr_large_failed++; nr_large_failed++;
stats->nr_thp_failed += is_thp; stats->nr_thp_failed += is_thp;
} else if (!no_split_folio_counting) { } else {
nr_failed++; nr_failed++;
} }
@@ -1888,30 +1853,52 @@ out:
dst2 = list_next_entry(dst, lru); dst2 = list_next_entry(dst, lru);
} }
return rc;
}
static int migrate_pages_sync(struct list_head *from, new_page_t get_new_page,
free_page_t put_new_page, unsigned long private,
enum migrate_mode mode, int reason, struct list_head *ret_folios,
struct list_head *split_folios, struct migrate_pages_stats *stats)
{
int rc, nr_failed = 0;
LIST_HEAD(folios);
struct migrate_pages_stats astats;
memset(&astats, 0, sizeof(astats));
/* Try to migrate in batch with MIGRATE_ASYNC mode firstly */
rc = migrate_pages_batch(from, get_new_page, put_new_page, private, MIGRATE_ASYNC,
reason, &folios, split_folios, &astats,
NR_MAX_MIGRATE_ASYNC_RETRY);
stats->nr_succeeded += astats.nr_succeeded;
stats->nr_thp_succeeded += astats.nr_thp_succeeded;
stats->nr_thp_split += astats.nr_thp_split;
if (rc < 0) {
stats->nr_failed_pages += astats.nr_failed_pages;
stats->nr_thp_failed += astats.nr_thp_failed;
list_splice_tail(&folios, ret_folios);
return rc;
}
stats->nr_thp_failed += astats.nr_thp_split;
nr_failed += astats.nr_thp_split;
/* /*
* Try to migrate split folios of fail-to-migrate large folios, no * Fall back to migrate all failed folios one by one synchronously. All
* nr_failed counting in this round, since all split folios of a * failed folios except split THPs will be retried, so their failure
* large folio is counted as 1 failure in the first round. * isn't counted
*/ */
if (rc >= 0 && !list_empty(&split_folios)) { list_splice_tail_init(&folios, from);
/* while (!list_empty(from)) {
* Move non-migrated folios (after NR_MAX_MIGRATE_PAGES_RETRY list_move(from->next, &folios);
* retries) to ret_folios to avoid migrating them again. rc = migrate_pages_batch(&folios, get_new_page, put_new_page,
*/ private, mode, reason, ret_folios,
list_splice_init(from, ret_folios); split_folios, stats, NR_MAX_MIGRATE_SYNC_RETRY);
list_splice_init(&split_folios, from); list_splice_tail_init(&folios, ret_folios);
no_split_folio_counting = true; if (rc < 0)
goto retry; return rc;
nr_failed += rc;
} }
/* return nr_failed;
* We have unlocked all locked folios, so we can force lock now, let's
* try again.
*/
if (rc == -EDEADLOCK)
goto retry;
return rc;
} }
/* /*
@@ -1949,6 +1936,7 @@ int migrate_pages(struct list_head *from, new_page_t get_new_page,
struct folio *folio, *folio2; struct folio *folio, *folio2;
LIST_HEAD(folios); LIST_HEAD(folios);
LIST_HEAD(ret_folios); LIST_HEAD(ret_folios);
LIST_HEAD(split_folios);
struct migrate_pages_stats stats; struct migrate_pages_stats stats;
trace_mm_migrate_pages_start(mode, reason); trace_mm_migrate_pages_start(mode, reason);
@@ -1959,6 +1947,7 @@ int migrate_pages(struct list_head *from, new_page_t get_new_page,
mode, reason, &stats, &ret_folios); mode, reason, &stats, &ret_folios);
if (rc_gather < 0) if (rc_gather < 0)
goto out; goto out;
again: again:
nr_pages = 0; nr_pages = 0;
list_for_each_entry_safe(folio, folio2, from, lru) { list_for_each_entry_safe(folio, folio2, from, lru) {
@@ -1969,20 +1958,36 @@ again:
} }
nr_pages += folio_nr_pages(folio); nr_pages += folio_nr_pages(folio);
if (nr_pages > NR_MAX_BATCHED_MIGRATION) if (nr_pages >= NR_MAX_BATCHED_MIGRATION)
break; break;
} }
if (nr_pages > NR_MAX_BATCHED_MIGRATION) if (nr_pages >= NR_MAX_BATCHED_MIGRATION)
list_cut_before(&folios, from, &folio->lru); list_cut_before(&folios, from, &folio2->lru);
else else
list_splice_init(from, &folios); list_splice_init(from, &folios);
rc = migrate_pages_batch(&folios, get_new_page, put_new_page, private, if (mode == MIGRATE_ASYNC)
mode, reason, &ret_folios, &stats); rc = migrate_pages_batch(&folios, get_new_page, put_new_page, private,
mode, reason, &ret_folios, &split_folios, &stats,
NR_MAX_MIGRATE_PAGES_RETRY);
else
rc = migrate_pages_sync(&folios, get_new_page, put_new_page, private,
mode, reason, &ret_folios, &split_folios, &stats);
list_splice_tail_init(&folios, &ret_folios); list_splice_tail_init(&folios, &ret_folios);
if (rc < 0) { if (rc < 0) {
rc_gather = rc; rc_gather = rc;
list_splice_tail(&split_folios, &ret_folios);
goto out; goto out;
} }
if (!list_empty(&split_folios)) {
/*
* Failure isn't counted since all split folios of a large folio
* is counted as 1 failure already. And, we only try to migrate
* with minimal effort, force MIGRATE_ASYNC mode and retry once.
*/
migrate_pages_batch(&split_folios, get_new_page, put_new_page, private,
MIGRATE_ASYNC, reason, &ret_folios, NULL, &stats, 1);
list_splice_tail_init(&split_folios, &ret_folios);
}
rc_gather += rc; rc_gather += rc;
if (!list_empty(from)) if (!list_empty(from))
goto again; goto again;

View File

@@ -33,7 +33,7 @@ static int mincore_hugetlb(pte_t *pte, unsigned long hmask, unsigned long addr,
* Hugepages under user process are always in RAM and never * Hugepages under user process are always in RAM and never
* swapped out, but theoretically it needs to be checked. * swapped out, but theoretically it needs to be checked.
*/ */
present = pte && !huge_pte_none(huge_ptep_get(pte)); present = pte && !huge_pte_none_mostly(huge_ptep_get(pte));
for (; addr != end; vec++, addr += PAGE_SIZE) for (; addr != end; vec++, addr += PAGE_SIZE)
*vec = present; *vec = present;
walk->private = vec; walk->private = vec;