From patchwork Thu Apr 1 18:21:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suren Baghdasaryan X-Patchwork-Id: 12179161 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=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT,USER_IN_DEF_DKIM_WL 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 C3385C43461 for ; Thu, 1 Apr 2021 18:21:32 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 722DD60240 for ; Thu, 1 Apr 2021 18:21:32 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 722DD60240 Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 103886B0075; Thu, 1 Apr 2021 14:21:32 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 0DB606B0078; Thu, 1 Apr 2021 14:21:32 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id EE4506B007D; Thu, 1 Apr 2021 14:21:31 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0041.hostedemail.com [216.40.44.41]) by kanga.kvack.org (Postfix) with ESMTP id D3B5F6B0075 for ; Thu, 1 Apr 2021 14:21:31 -0400 (EDT) Received: from smtpin11.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay04.hostedemail.com (Postfix) with ESMTP id 8C927BF10 for ; Thu, 1 Apr 2021 18:21:31 +0000 (UTC) X-FDA: 77984615982.11.9CA1840 Received: from mail-qt1-f201.google.com (mail-qt1-f201.google.com [209.85.160.201]) by imf11.hostedemail.com (Postfix) with ESMTP id 972BB200025C for ; Thu, 1 Apr 2021 18:21:29 +0000 (UTC) Received: by mail-qt1-f201.google.com with SMTP id b18so3588315qte.21 for ; Thu, 01 Apr 2021 11:21:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=5HT0qAWVFEwmOUtF6La54IUlPIkCZq6cCaZb+QDq3o0=; b=FCS4HYb6J3nfpKWojigWdeLm322x4N3yal1ui3yFWmzroHvdmhbKuSF3DpbqsIBKqU 3C1CdQ+JY3kcg+YFAsmQ5yLfUbgENDF0IPDrSY+6PjWU94p8tWRFMKPwcAiU0sniPxDq 1TF2+8+Ip8kSSHIhLIvSRZcY7gCVna0ZgXGr5eYamiInLGVJQh+k680kXCav7A/idNVP 8SfPeqsoxzgrtq++O0zdmEqmBXYA68o6+WEbD7dN4ckj4+wBapc6cclze2NFWqKPe5am FpGwFjYcZzq2q5aJNUuKnYZmVnteJrzOrphPlZE2ju6i7MwUENmkr/13kR4/M7hOfJdu j0WQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=5HT0qAWVFEwmOUtF6La54IUlPIkCZq6cCaZb+QDq3o0=; b=a2jQu+Od4WVc9LOu1PsjTvT7XpzpwEEu4dVtZhSEbIXIVYLQ946QaNOlqEOQxTZAxl mIEBFFKRyO0l6cC/ssBJregZhyJ9hcykFC4s5Ehv2d4z7enO6fHzjqH9engkrA+F+ciP oB9cSK1Ykn/oo4GSPSM5DpHLKzjPtVeH4pt5z9ekZL2iv/k5Q3gfinmqfnY0Thou9xZp evCHG1Mp+bD4kGlmkqB5qM7PQeOEQMSYrTcS2S9y+bwan35wIhMjOV5epjjjXE68FyXR 3JyZGLI340t8jNH0Fx5WBvD6nMr0VvSOY9nuGsTFmL+HEAidQTMTQvbhd8ugQH6lFeFE bFtQ== X-Gm-Message-State: AOAM5308Y7m5kW1tY4rkgsiX92/4bPlfElc3kJUl3QRBaeDhaEi1MXeF LGxM/PGTnrwXkTbpeUmOk35yy64IjV4= X-Google-Smtp-Source: ABdhPJx3CSbez+mHmIMP16uoTLOqGzUQCpgEy4t7meclV6GV32vzVuEQJjrjKkgnWp0r1JVEINQ+id1CxYw= X-Received: from surenb1.mtv.corp.google.com ([2620:15c:211:200:899:1066:21fc:b3c5]) (user=surenb job=sendgmr) by 2002:ad4:58cf:: with SMTP id dh15mr9296862qvb.26.1617301290422; Thu, 01 Apr 2021 11:21:30 -0700 (PDT) Date: Thu, 1 Apr 2021 11:21:21 -0700 In-Reply-To: <20210401182125.171484-1-surenb@google.com> Message-Id: <20210401182125.171484-2-surenb@google.com> Mime-Version: 1.0 References: <20210401182125.171484-1-surenb@google.com> X-Mailer: git-send-email 2.31.0.291.g576ba9dcdaf-goog Subject: [PATCH 1/5] mm: reuse only-pte-mapped KSM page in do_wp_page() From: Suren Baghdasaryan To: stable@vger.kernel.org Cc: gregkh@linuxfoundation.org, jannh@google.com, ktkhai@virtuozzo.com, torvalds@linux-foundation.org, shli@fb.com, namit@vmware.com, linux-mm@kvack.org, linux-kernel@vger.kernel.org, kernel-team@android.com, surenb@google.com, Yang Shi , "Kirill A. Shutemov" , Hugh Dickins , Andrea Arcangeli , Christian Koenig , Claudio Imbrenda , Rik van Riel , Huang Ying , Minchan Kim , Andrew Morton X-Rspamd-Server: rspam01 X-Rspamd-Queue-Id: 972BB200025C X-Stat-Signature: mek3baygajxo798pox13z66era5pesig Received-SPF: none (flex--surenb.bounces.google.com>: No applicable sender policy available) receiver=imf11; identity=mailfrom; envelope-from="<3Kg9mYAYKCOkdfcPYMRZZRWP.NZXWTYfi-XXVgLNV.ZcR@flex--surenb.bounces.google.com>"; helo=mail-qt1-f201.google.com; client-ip=209.85.160.201 X-HE-DKIM-Result: pass/pass X-HE-Tag: 1617301289-949295 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: From: Kirill Tkhai Add an optimization for KSM pages almost in the same way that we have for ordinary anonymous pages. If there is a write fault in a page, which is mapped to an only pte, and it is not related to swap cache; the page may be reused without copying its content. [ Note that we do not consider PageSwapCache() pages at least for now, since we don't want to complicate __get_ksm_page(), which has nice optimization based on this (for the migration case). Currenly it is spinning on PageSwapCache() pages, waiting for when they have unfreezed counters (i.e., for the migration finish). But we don't want to make it also spinning on swap cache pages, which we try to reuse, since there is not a very high probability to reuse them. So, for now we do not consider PageSwapCache() pages at all. ] So in reuse_ksm_page() we check for 1) PageSwapCache() and 2) page_stable_node(), to skip a page, which KSM is currently trying to link to stable tree. Then we do page_ref_freeze() to prohibit KSM to merge one more page into the page, we are reusing. After that, nobody can refer to the reusing page: KSM skips !PageSwapCache() pages with zero refcount; and the protection against of all other participants is the same as for reused ordinary anon pages pte lock, page lock and mmap_sem. [akpm@linux-foundation.org: replace BUG_ON()s with WARN_ON()s] Link: http://lkml.kernel.org/r/154471491016.31352.1168978849911555609.stgit@localhost.localdomain Signed-off-by: Kirill Tkhai Reviewed-by: Yang Shi Cc: "Kirill A. Shutemov" Cc: Hugh Dickins Cc: Andrea Arcangeli Cc: Christian Koenig Cc: Claudio Imbrenda Cc: Rik van Riel Cc: Huang Ying Cc: Minchan Kim Cc: Kirill Tkhai Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/ksm.h | 7 +++++++ mm/ksm.c | 30 ++++++++++++++++++++++++++++-- mm/memory.c | 16 ++++++++++++++-- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/include/linux/ksm.h b/include/linux/ksm.h index 161e8164abcf..e48b1e453ff5 100644 --- a/include/linux/ksm.h +++ b/include/linux/ksm.h @@ -53,6 +53,8 @@ struct page *ksm_might_need_to_copy(struct page *page, void rmap_walk_ksm(struct page *page, struct rmap_walk_control *rwc); void ksm_migrate_page(struct page *newpage, struct page *oldpage); +bool reuse_ksm_page(struct page *page, + struct vm_area_struct *vma, unsigned long address); #else /* !CONFIG_KSM */ @@ -86,6 +88,11 @@ static inline void rmap_walk_ksm(struct page *page, static inline void ksm_migrate_page(struct page *newpage, struct page *oldpage) { } +static inline bool reuse_ksm_page(struct page *page, + struct vm_area_struct *vma, unsigned long address) +{ + return false; +} #endif /* CONFIG_MMU */ #endif /* !CONFIG_KSM */ diff --git a/mm/ksm.c b/mm/ksm.c index d021bcf94c41..c4e95ca65d62 100644 --- a/mm/ksm.c +++ b/mm/ksm.c @@ -705,8 +705,9 @@ static struct page *get_ksm_page(struct stable_node *stable_node, bool lock_it) * case this node is no longer referenced, and should be freed; * however, it might mean that the page is under page_ref_freeze(). * The __remove_mapping() case is easy, again the node is now stale; - * but if page is swapcache in migrate_page_move_mapping(), it might - * still be our page, in which case it's essential to keep the node. + * the same is in reuse_ksm_page() case; but if page is swapcache + * in migrate_page_move_mapping(), it might still be our page, + * in which case it's essential to keep the node. */ while (!get_page_unless_zero(page)) { /* @@ -2648,6 +2649,31 @@ void rmap_walk_ksm(struct page *page, struct rmap_walk_control *rwc) goto again; } +bool reuse_ksm_page(struct page *page, + struct vm_area_struct *vma, + unsigned long address) +{ +#ifdef CONFIG_DEBUG_VM + if (WARN_ON(is_zero_pfn(page_to_pfn(page))) || + WARN_ON(!page_mapped(page)) || + WARN_ON(!PageLocked(page))) { + dump_page(page, "reuse_ksm_page"); + return false; + } +#endif + + if (PageSwapCache(page) || !page_stable_node(page)) + return false; + /* Prohibit parallel get_ksm_page() */ + if (!page_ref_freeze(page, 1)) + return false; + + page_move_anon_rmap(page, vma); + page->index = linear_page_index(vma, address); + page_ref_unfreeze(page, 1); + + return true; +} #ifdef CONFIG_MIGRATION void ksm_migrate_page(struct page *newpage, struct page *oldpage) { diff --git a/mm/memory.c b/mm/memory.c index c1a05c2484b0..3874acce1472 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2846,8 +2846,11 @@ static vm_fault_t do_wp_page(struct vm_fault *vmf) * Take out anonymous pages first, anonymous shared vmas are * not dirty accountable. */ - if (PageAnon(vmf->page) && !PageKsm(vmf->page)) { + if (PageAnon(vmf->page)) { int total_map_swapcount; + if (PageKsm(vmf->page) && (PageSwapCache(vmf->page) || + page_count(vmf->page) != 1)) + goto copy; if (!trylock_page(vmf->page)) { get_page(vmf->page); pte_unmap_unlock(vmf->pte, vmf->ptl); @@ -2862,6 +2865,15 @@ static vm_fault_t do_wp_page(struct vm_fault *vmf) } put_page(vmf->page); } + if (PageKsm(vmf->page)) { + bool reused = reuse_ksm_page(vmf->page, vmf->vma, + vmf->address); + unlock_page(vmf->page); + if (!reused) + goto copy; + wp_page_reuse(vmf); + return VM_FAULT_WRITE; + } if (reuse_swap_page(vmf->page, &total_map_swapcount)) { if (total_map_swapcount == 1) { /* @@ -2882,7 +2894,7 @@ static vm_fault_t do_wp_page(struct vm_fault *vmf) (VM_WRITE|VM_SHARED))) { return wp_page_shared(vmf); } - +copy: /* * Ok, we need to copy. Oh, well.. */