From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.5 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CA5ECC4361B for ; Thu, 17 Dec 2020 18:53:05 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 68183238EC for ; Thu, 17 Dec 2020 18:53:05 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 68183238EC Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=soleen.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 5F1836B0073; Thu, 17 Dec 2020 13:53:03 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 575156B0074; Thu, 17 Dec 2020 13:53:03 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 3A20D6B0075; Thu, 17 Dec 2020 13:53:03 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0147.hostedemail.com [216.40.44.147]) by kanga.kvack.org (Postfix) with ESMTP id 1B8206B0073 for ; Thu, 17 Dec 2020 13:53:03 -0500 (EST) Received: from smtpin13.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay04.hostedemail.com (Postfix) with ESMTP id D3EB71E05 for ; Thu, 17 Dec 2020 18:53:02 +0000 (UTC) X-FDA: 77603671404.13.week79_1b0b82827437 Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin13.hostedemail.com (Postfix) with ESMTP id B1B8418140B67 for ; Thu, 17 Dec 2020 18:53:02 +0000 (UTC) X-HE-Tag: week79_1b0b82827437 X-Filterd-Recvd-Size: 10922 Received: from mail-qk1-f181.google.com (mail-qk1-f181.google.com [209.85.222.181]) by imf44.hostedemail.com (Postfix) with ESMTP for ; Thu, 17 Dec 2020 18:53:02 +0000 (UTC) Received: by mail-qk1-f181.google.com with SMTP id b64so23380432qkc.12 for ; Thu, 17 Dec 2020 10:53:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=ddKWF6rz+jusoSW85/8ZXU7qwdgQHa0ysIZMt3vGuRI=; b=Y+S8xlyU6M5Ma07Mnlbu0DPfFn/l4z5e0Vd6UE2ZGYZEAAz2VUjCv85uIPBF+ol81+ x6jfcFfQXXfM7DS+Bi1SZQakCCvVq2axWBhBi5ojyTi/cRQTb6GD/pUVhV/vrnQcNmRa etvfj8gKeVup6AH3odppjx3qV8QIUj0njVsO0LCaHIzs8e4cpZjqpAs7q3EkhxdjKIFU +s2WxTbDpBRPNe2G67zpaxHjz519rXrhaV2TjNjuSBqGlt6oo06S/MB4nD3NLz8njfbS q5pG0fnAWGtmTtakVPZ/oEhADYpxQfD49mZ+SrYC19Vy0j5KIogPu+5mO4pJSH8DdOcd iRYg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ddKWF6rz+jusoSW85/8ZXU7qwdgQHa0ysIZMt3vGuRI=; b=dvhw+YudQqmHIhZjWXenw3I+CmI1l6XPw+Kij+ukzxcUuaxTt06CC/btSqWMAIDVgV v2TBI7H5j6lY7bSUBnWWIy+F4OCUmhp7O4DoxKAHOH7aLaUr6EK84Rmhycbm7hUpeJVm GRFVyrzbvQMKAHpJLhx2Bm5XPpuXmpP7lR8rc4gW1+M07f/8MOEVreTg98S3zIY/lKLg c2fZdqx/ab5JlwwprN7oFbjdWFnuaE4414iNU72mZyzuirU5E86s09U4kOCS560hL56o 7LTG0oGe15MdTaBz8xsCSzM+085hpncPwgTiBC6+V+G7j20d/n+JOU1oxB7R+gaI/CWL wknQ== X-Gm-Message-State: AOAM530m00jmuaMB2g3uQe+cT87PVGs/lQQ+Up1tqos38aiBC4FNOz91 yzl0GKmq363EHRNlZ9Ip9MITvQ== X-Google-Smtp-Source: ABdhPJxGcmSkWGboMlUiUt5OdTP7H/VwwMXdIJqjPcipfMa9wI/JO+uBMKdmiESr7baRF4zUa8CYMQ== X-Received: by 2002:a05:620a:75a:: with SMTP id i26mr730856qki.314.1608231181586; Thu, 17 Dec 2020 10:53:01 -0800 (PST) Received: from localhost.localdomain (c-73-69-118-222.hsd1.nh.comcast.net. [73.69.118.222]) by smtp.gmail.com with ESMTPSA id m8sm4127434qkn.41.2020.12.17.10.52.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 17 Dec 2020 10:53:00 -0800 (PST) From: Pavel Tatashin 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 Message-Id: <20201217185243.3288048-9-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201217185243.3288048-1-pasha.tatashin@soleen.com> References: <20201217185243.3288048-1-pasha.tatashin@soleen.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: check_and_migrate_movable_pages() does not honor isolation errors, and al= so 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 --- 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 */ =20 -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 =3D true; - bool migrate_allow =3D true; +/* + * Verify that there are no unpinnable (movable) pages, if so return tru= e. + * Otherwise an unpinnable pages is found return false, and unpin all pa= ges. + */ +static bool check_and_unpin_pages(unsigned long nr_pages, struct page **= pages, + unsigned int gup_flags) +{ + unsigned long i, step; + + for (i =3D 0; i < nr_pages; i +=3D step) { + struct page *head =3D compound_head(pages[i]); + + step =3D compound_nr(head) - (pages[i] - head); + if (!is_pinnable_page(head)) + break; + } + + if (i >=3D nr_pages) + return true; + + if (gup_flags & FOLL_PIN) { + unpin_user_pages(pages, nr_pages); + } else { + for (i =3D 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 erro= r 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 =3D nr_pages; + long ret =3D 0; + long error_count =3D 0; struct migration_target_control mtc =3D { .nid =3D NUMA_NO_NODE, .gfp_mask =3D GFP_USER | __GFP_NOWARN, }; =20 -check_again: - for (i =3D 0; i < nr_pages;) { - + lru_add_drain_all(); + for (i =3D 0; i < nr_pages; i +=3D step) { struct page *head =3D compound_head(pages[i]); =20 /* @@ -1583,62 +1613,42 @@ static long check_and_migrate_movable_pages(struc= t 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 =3D false; - } - + if (PageHuge(head)) { + if (!isolate_huge_page(head, &movable_page_list)) + error_count +=3D 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 +=3D step; } } } - - i +=3D step; } =20 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 =3D 0; i < nr_pages; i++) - put_page(pages[i]); + ret =3D 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 =3D -EBUSY; + } =20 - 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 =3D false; + if (ret && !list_empty(&movable_page_list)) + putback_movable_pages(&movable_page_list); =20 - 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 =3D __get_user_pages_locked(mm, start, nr_pages, - pages, vmas, NULL, - gup_flags); - - if ((ret > 0) && migrate_allow) { - nr_pages =3D ret; - drain_allow =3D 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 =3D error_count; =20 return ret; } @@ -1654,22 +1664,55 @@ static long __gup_longterm_locked(struct mm_struc= t *mm, struct vm_area_struct **vmas, unsigned int gup_flags) { - unsigned long flags =3D 0; + int migrate_retry =3D 0; + int isolate_retry =3D 0; + unsigned int flags; long rc; =20 - if (gup_flags & FOLL_LONGTERM) - flags =3D memalloc_pin_save(); + if (!(gup_flags & FOLL_LONGTERM)) + return __get_user_pages_locked(mm, start, nr_pages, pages, vmas, + NULL, gup_flags); =20 - rc =3D __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 &=3D FOLL_WRITE; =20 - if (gup_flags & FOLL_LONGTERM) { - if (rc > 0) - rc =3D check_and_migrate_movable_pages(mm, start, rc, - pages, vmas, - gup_flags); - memalloc_pin_restore(flags); + flags =3D 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 =3D __get_user_pages_locked(mm, start, nr_pages, pages, vmas, + NULL, gup_flags); + + /* Return if error or if all pages are pinnable */ + if (rc <=3D 0 || check_and_unpin_pages(rc, pages, gup_flags)) + break; + + /* Some pages are not pinnable, migrate them */ + rc =3D 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++ >=3D PINNABLE_MIGRATE_MAX) { + break; + } else if (rc > 0 && isolate_retry++ >=3D PINNABLE_ISOLATE_MAX) { + rc =3D -EBUSY; + break; + } } + memalloc_pin_restore(flags); + return rc; } =20 --=20 2.25.1