From: Pavel Tatashin <pasha.tatashin@soleen.com>
To: pasha.tatashin@soleen.com, linux-kernel@vger.kernel.org,
linux-mm@kvack.org, akpm@linux-foundation.org, vbabka@suse.cz,
mhocko@suse.com, david@redhat.com, osalvador@suse.de,
dan.j.williams@intel.com, sashal@kernel.org,
tyhicks@linux.microsoft.com, iamjoonsoo.kim@lge.com,
mike.kravetz@oracle.com, rostedt@goodmis.org, mingo@redhat.com,
jgg@ziepe.ca, peterz@infradead.org, mgorman@suse.de,
willy@infradead.org, rientjes@google.com, jhubbard@nvidia.com,
linux-doc@vger.kernel.org, ira.weiny@intel.com,
linux-kselftest@vger.kernel.org
Subject: [PATCH v4 08/10] mm/gup: limit number of gup migration failures, honor failures
Date: Thu, 17 Dec 2020 13:52:41 -0500 [thread overview]
Message-ID: <20201217185243.3288048-9-pasha.tatashin@soleen.com> (raw)
In-Reply-To: <20201217185243.3288048-1-pasha.tatashin@soleen.com>
check_and_migrate_movable_pages() does not honor isolation errors, and also
retries migration failures indefinably.
Fix both of the above issues: add a new function that checks and unpins
pages range check_and_unpin_pages().
Move the retry loop from check_and_migrate_movable_pages() to
__gup_longterm_locked().
Rename check_and_migrate_movable_pages() as migrate_movable_pages() and
make this function accept already unpinned pages. Also, track the errors
during isolation, so they can be re-tried with a different maximum limit,
the isolation errors should be ephemeral.
Signed-off-by: Pavel Tatashin <pasha.tatashin@soleen.com>
---
mm/gup.c | 179 ++++++++++++++++++++++++++++++++++---------------------
1 file changed, 111 insertions(+), 68 deletions(-)
diff --git a/mm/gup.c b/mm/gup.c
index 1ebb7cc2fbe4..70cc8b8f67c4 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -1550,27 +1550,57 @@ struct page *get_dump_page(unsigned long addr)
}
#endif /* CONFIG_ELF_CORE */
-static long check_and_migrate_movable_pages(struct mm_struct *mm,
- unsigned long start,
- unsigned long nr_pages,
- struct page **pages,
- struct vm_area_struct **vmas,
- unsigned int gup_flags)
-{
- unsigned long i;
- unsigned long step;
- bool drain_allow = true;
- bool migrate_allow = true;
+/*
+ * Verify that there are no unpinnable (movable) pages, if so return true.
+ * Otherwise an unpinnable pages is found return false, and unpin all pages.
+ */
+static bool check_and_unpin_pages(unsigned long nr_pages, struct page **pages,
+ unsigned int gup_flags)
+{
+ unsigned long i, step;
+
+ for (i = 0; i < nr_pages; i += step) {
+ struct page *head = compound_head(pages[i]);
+
+ step = compound_nr(head) - (pages[i] - head);
+ if (!is_pinnable_page(head))
+ break;
+ }
+
+ if (i >= nr_pages)
+ return true;
+
+ if (gup_flags & FOLL_PIN) {
+ unpin_user_pages(pages, nr_pages);
+ } else {
+ for (i = 0; i < nr_pages; i++)
+ put_page(pages[i]);
+ }
+
+ return false;
+}
+
+#define PINNABLE_MIGRATE_MAX 10
+#define PINNABLE_ISOLATE_MAX 100
+
+/*
+ * Migrate pages that cannot be pinned. Return zero on success and error code
+ * on migration failure. If migration was successful but page isolation had
+ * failures return number of pages that failed to be isolated.
+ */
+static long migrate_movable_pages(unsigned long nr_pages, struct page **pages)
+{
+ unsigned long i, step;
LIST_HEAD(movable_page_list);
- long ret = nr_pages;
+ long ret = 0;
+ long error_count = 0;
struct migration_target_control mtc = {
.nid = NUMA_NO_NODE,
.gfp_mask = GFP_USER | __GFP_NOWARN,
};
-check_again:
- for (i = 0; i < nr_pages;) {
-
+ lru_add_drain_all();
+ for (i = 0; i < nr_pages; i += step) {
struct page *head = compound_head(pages[i]);
/*
@@ -1583,62 +1613,42 @@ static long check_and_migrate_movable_pages(struct mm_struct *mm,
* these entries, try to move them out if possible.
*/
if (!is_pinnable_page(head)) {
- if (PageHuge(head))
- isolate_huge_page(head, &movable_page_list);
- else {
- if (!PageLRU(head) && drain_allow) {
- lru_add_drain_all();
- drain_allow = false;
- }
-
+ if (PageHuge(head)) {
+ if (!isolate_huge_page(head, &movable_page_list))
+ error_count += step;
+ } else {
if (!isolate_lru_page(head)) {
list_add_tail(&head->lru, &movable_page_list);
mod_node_page_state(page_pgdat(head),
NR_ISOLATED_ANON +
page_is_file_lru(head),
thp_nr_pages(head));
+ } else {
+ error_count += step;
}
}
}
-
- i += step;
}
if (!list_empty(&movable_page_list)) {
- /*
- * drop the above get_user_pages reference.
- */
- if (gup_flags & FOLL_PIN)
- unpin_user_pages(pages, nr_pages);
- else
- for (i = 0; i < nr_pages; i++)
- put_page(pages[i]);
+ ret = migrate_pages(&movable_page_list, alloc_migration_target,
+ NULL, (unsigned long)&mtc, MIGRATE_SYNC,
+ MR_LONGTERM_PIN);
+ /* Assume -EBUSY failure if some pages were not migrated */
+ if (ret > 0)
+ ret = -EBUSY;
+ }
- if (migrate_pages(&movable_page_list, alloc_migration_target, NULL,
- (unsigned long)&mtc, MIGRATE_SYNC, MR_LONGTERM_PIN)) {
- /*
- * some of the pages failed migration. Do get_user_pages
- * without migration.
- */
- migrate_allow = false;
+ if (ret && !list_empty(&movable_page_list))
+ putback_movable_pages(&movable_page_list);
- if (!list_empty(&movable_page_list))
- putback_movable_pages(&movable_page_list);
- }
- /*
- * We did migrate all the pages, Try to get the page references
- * again migrating any pages which we failed to isolate earlier.
- */
- ret = __get_user_pages_locked(mm, start, nr_pages,
- pages, vmas, NULL,
- gup_flags);
-
- if ((ret > 0) && migrate_allow) {
- nr_pages = ret;
- drain_allow = true;
- goto check_again;
- }
- }
+ /*
+ * Check if there were isolation errors, if so they should not be
+ * counted toward PINNABLE_MIGRATE_MAX, so separate them, by
+ * returning number of pages failed to isolate.
+ */
+ if (!ret && error_count)
+ ret = error_count;
return ret;
}
@@ -1654,22 +1664,55 @@ static long __gup_longterm_locked(struct mm_struct *mm,
struct vm_area_struct **vmas,
unsigned int gup_flags)
{
- unsigned long flags = 0;
+ int migrate_retry = 0;
+ int isolate_retry = 0;
+ unsigned int flags;
long rc;
- if (gup_flags & FOLL_LONGTERM)
- flags = memalloc_pin_save();
+ if (!(gup_flags & FOLL_LONGTERM))
+ return __get_user_pages_locked(mm, start, nr_pages, pages, vmas,
+ NULL, gup_flags);
- rc = __get_user_pages_locked(mm, start, nr_pages, pages, vmas, NULL,
- gup_flags);
+ /*
+ * Without FOLL_WRITE fault handler may return zero page, which can
+ * be in a movable zone, and also will fail to isolate during migration,
+ * thus the longterm pin will fail.
+ */
+ gup_flags &= FOLL_WRITE;
- if (gup_flags & FOLL_LONGTERM) {
- if (rc > 0)
- rc = check_and_migrate_movable_pages(mm, start, rc,
- pages, vmas,
- gup_flags);
- memalloc_pin_restore(flags);
+ flags = memalloc_pin_save();
+ /*
+ * Migration may fail, we retry before giving up. Also, because after
+ * migration pages[] becomes outdated, we unpin and repin all pages
+ * in the range, so pages array is repopulated with new values.
+ * Also, because of this we cannot retry migration failures in a loop
+ * without pinning/unpinnig pages.
+ */
+ for (; ; ) {
+ rc = __get_user_pages_locked(mm, start, nr_pages, pages, vmas,
+ NULL, gup_flags);
+
+ /* Return if error or if all pages are pinnable */
+ if (rc <= 0 || check_and_unpin_pages(rc, pages, gup_flags))
+ break;
+
+ /* Some pages are not pinnable, migrate them */
+ rc = migrate_movable_pages(rc, pages);
+
+ /*
+ * If there is an error, and we tried maximum number of times
+ * bail out. Notice: we return an error code, and all pages are
+ * unpinned
+ */
+ if (rc < 0 && migrate_retry++ >= PINNABLE_MIGRATE_MAX) {
+ break;
+ } else if (rc > 0 && isolate_retry++ >= PINNABLE_ISOLATE_MAX) {
+ rc = -EBUSY;
+ break;
+ }
}
+ memalloc_pin_restore(flags);
+
return rc;
}
--
2.25.1
next prev parent reply other threads:[~2020-12-17 18:53 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-12-17 18:52 [PATCH v4 00/10] prohibit pinning pages in ZONE_MOVABLE Pavel Tatashin
2020-12-17 18:52 ` [PATCH v4 01/10] mm/gup: don't pin migrated cma pages in movable zone Pavel Tatashin
2020-12-17 18:52 ` [PATCH v4 02/10] mm cma: rename PF_MEMALLOC_NOCMA to PF_MEMALLOC_PIN Pavel Tatashin
2020-12-17 18:52 ` [PATCH v4 03/10] mm: apply per-task gfp constraints in fast path Pavel Tatashin
2020-12-18 9:36 ` Michal Hocko
2020-12-18 12:23 ` Pavel Tatashin
2020-12-17 18:52 ` [PATCH v4 04/10] mm: honor PF_MEMALLOC_PIN for all movable pages Pavel Tatashin
2020-12-17 18:52 ` [PATCH v4 05/10] mm/gup: migrate pinned pages out of movable zone Pavel Tatashin
2020-12-18 9:43 ` Michal Hocko
2020-12-18 12:24 ` Pavel Tatashin
2020-12-18 13:08 ` Michal Hocko
2021-01-13 19:14 ` Pavel Tatashin
2020-12-17 18:52 ` [PATCH v4 06/10] memory-hotplug.rst: add a note about ZONE_MOVABLE and page pinning Pavel Tatashin
2020-12-18 9:44 ` Michal Hocko
2020-12-17 18:52 ` [PATCH v4 07/10] mm/gup: change index type to long as it counts pages Pavel Tatashin
2020-12-18 9:50 ` Michal Hocko
2020-12-18 12:32 ` Pavel Tatashin
2020-12-17 18:52 ` Pavel Tatashin [this message]
2020-12-17 20:50 ` [PATCH v4 08/10] mm/gup: limit number of gup migration failures, honor failures Jason Gunthorpe
2020-12-17 22:02 ` Pavel Tatashin
2020-12-18 14:19 ` Jason Gunthorpe
2021-01-13 19:43 ` Pavel Tatashin
2021-01-13 19:55 ` Jason Gunthorpe
2021-01-13 20:05 ` Pavel Tatashin
2021-01-13 23:40 ` Jason Gunthorpe
2021-01-15 18:10 ` Pavel Tatashin
2021-01-15 18:40 ` Jason Gunthorpe
2020-12-18 10:46 ` Michal Hocko
2020-12-18 12:43 ` Pavel Tatashin
2020-12-18 13:04 ` David Hildenbrand
2020-12-18 13:14 ` Michal Hocko
2021-01-13 19:49 ` Pavel Tatashin
2020-12-17 18:52 ` [PATCH v4 09/10] selftests/vm: test flag is broken Pavel Tatashin
2020-12-18 9:06 ` John Hubbard
2020-12-18 9:11 ` John Hubbard
2020-12-17 18:52 ` [PATCH v4 10/10] selftests/vm: test faulting in kernel, and verify pinnable pages Pavel Tatashin
2020-12-19 5:57 ` John Hubbard
2020-12-19 15:22 ` Pavel Tatashin
2020-12-19 23:51 ` John Hubbard
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=20201217185243.3288048-9-pasha.tatashin@soleen.com \
--to=pasha.tatashin@soleen.com \
--cc=akpm@linux-foundation.org \
--cc=dan.j.williams@intel.com \
--cc=david@redhat.com \
--cc=iamjoonsoo.kim@lge.com \
--cc=ira.weiny@intel.com \
--cc=jgg@ziepe.ca \
--cc=jhubbard@nvidia.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=mgorman@suse.de \
--cc=mhocko@suse.com \
--cc=mike.kravetz@oracle.com \
--cc=mingo@redhat.com \
--cc=osalvador@suse.de \
--cc=peterz@infradead.org \
--cc=rientjes@google.com \
--cc=rostedt@goodmis.org \
--cc=sashal@kernel.org \
--cc=tyhicks@linux.microsoft.com \
--cc=vbabka@suse.cz \
--cc=willy@infradead.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox