From patchwork Mon Dec 14 06:53:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicholas Piggin X-Patchwork-Id: 11971445 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=-13.5 required=3.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED,DKIM_INVALID,DKIM_SIGNED,FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,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 EC366C4361B for ; Mon, 14 Dec 2020 07:01:25 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 6EF5A22583 for ; Mon, 14 Dec 2020 07:01:25 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 6EF5A22583 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id B4C356B005C; Mon, 14 Dec 2020 02:01:24 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id B23CC6B005D; Mon, 14 Dec 2020 02:01:24 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id A13136B0068; Mon, 14 Dec 2020 02:01:24 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0059.hostedemail.com [216.40.44.59]) by kanga.kvack.org (Postfix) with ESMTP id 8349B6B005C for ; Mon, 14 Dec 2020 02:01:24 -0500 (EST) Received: from smtpin12.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay04.hostedemail.com (Postfix) with ESMTP id 47C182C89 for ; Mon, 14 Dec 2020 07:01:24 +0000 (UTC) X-FDA: 77590991688.12.road65_160e4c327418 Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin12.hostedemail.com (Postfix) with ESMTP id 0E7DD18015DBF for ; Mon, 14 Dec 2020 07:01:24 +0000 (UTC) X-HE-Tag: road65_160e4c327418 X-Filterd-Recvd-Size: 9710 Received: from mail-pj1-f68.google.com (mail-pj1-f68.google.com [209.85.216.68]) by imf06.hostedemail.com (Postfix) with ESMTP for ; Mon, 14 Dec 2020 07:01:23 +0000 (UTC) Received: by mail-pj1-f68.google.com with SMTP id b5so6061383pjl.0 for ; Sun, 13 Dec 2020 23:01:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=tTzD/PwVnUryCFsCtBkXOLSBdB20HGAb9puUxId4JVk=; b=IR9n6Xx3XA7TWORm+admowft3H2sA37sBIcd+GaFLOP0qFk15JB6uoOrHhMuzatwsC HQ26+f50MnEXp3JmLnlvTNWfB67/uTwwboaOXijLrWMS6goDqh1RGiVPj6YwHXedhuRY ONdoimeRGscvIVFc1AQRLCydCRLvZxavxCIVqjhlqtBuGaHa2ynhR8Y6wfovleCF/YR/ 8TzsXLnt+Plc6HEfBAzkyeRebiyMGgTwde7hSwzi50i/1jG056NrAeoOuUjU7F6IIrfA Pj80cWPZLza80QoJ00gbstNsZK2bmcjZeoCU3aGM10vTa0vfEgq5iccJ+843aJqUDBJn V/QQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=tTzD/PwVnUryCFsCtBkXOLSBdB20HGAb9puUxId4JVk=; b=cKkQqkPEWzAg2lEBY3iuv8U+Fhi4OFBDkvareIjitmslWE/bfzSAitGv2tdaR9Wtko Y0mktMU8qTuyTTyouRKtDGfIAOru1F7Eo9Ad9bHu9Pwbm51tvb7j8jaLn/XIa/07Ycig jUn9DyKojYQk/O+9kcw0BPENXKiDWB13tRxlkqAeoB3E+2cknYYV4JjYMqDWutewHsrq iFRZ6cRkIH/aAwzt7YG9Iq24NLVBvGEwkS0d7vqA4Q2a3tPjeT7Y22SvKKDVFd+pkIQz Y1wsk7G+8zEsW4YrQ6CQuMcTfJe42nCzbf7fFqZJTGENJ3Lxc5bspdOGtCzFb4GStlTZ 5uGQ== X-Gm-Message-State: AOAM532D8puOSWGhJ1Hp4PN2P++7s3+SF7Tlp51zxtuVhcp0Qs/tZ5Iy 7aORllOkmNmVYyZqyDhdQqM= X-Google-Smtp-Source: ABdhPJwxGbCiA5g+oFBRL0MsR3yqlxPJyXmC3pmGD+mzl4QTJz+fHRqE9o5Gyew/trGb6oI0bDkZuQ== X-Received: by 2002:a17:902:7887:b029:dc:20e:47ff with SMTP id q7-20020a1709027887b02900dc020e47ffmr2078675pll.65.1607929282651; Sun, 13 Dec 2020 23:01:22 -0800 (PST) Received: from bobo.ozlabs.ibm.com ([220.240.228.148]) by smtp.gmail.com with ESMTPSA id 84sm19570018pfy.9.2020.12.13.23.01.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 13 Dec 2020 23:01:22 -0800 (PST) From: Nicholas Piggin To: linux-kernel@vger.kernel.org Cc: Nicholas Piggin , linux-arch@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, linux-mm@kvack.org, Anton Blanchard , Andy Lutomirski Subject: [PATCH v2 2/5] lazy tlb: allow lazy tlb mm switching to be configurable Date: Mon, 14 Dec 2020 16:53:09 +1000 Message-Id: <20201214065312.270062-3-npiggin@gmail.com> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20201214065312.270062-1-npiggin@gmail.com> References: <20201214065312.270062-1-npiggin@gmail.com> MIME-Version: 1.0 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: Add CONFIG_MMU_LAZY_TLB which can be configured out to disable the lazy tlb mechanism entirely, and switches to init_mm when switching to a kernel thread. NOMMU systems could easily go without this and save a bit of code and the refcount atomics, because their mm switch is a no-op. They have not been switched over by default because the arch code needs to be audited and tested for lazy tlb mm refcounting and converted to _lazy_tlb refcounting if necessary. CONFIG_MMU_LAZY_TLB_REFCOUNT is also added, but it must always be enabled if CONFIG_MMU_LAZY_TLB is enabled until the next patch which provides an alternate scheme. Signed-off-by: Nicholas Piggin --- arch/Kconfig | 17 +++++++++ include/linux/sched/mm.h | 13 +++++-- kernel/sched/core.c | 75 ++++++++++++++++++++++++++++++---------- kernel/sched/sched.h | 4 ++- 4 files changed, 87 insertions(+), 22 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index ba4e966484ab..84faaba66364 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -430,6 +430,23 @@ config ARCH_WANT_IRQS_OFF_ACTIVATE_MM irqs disabled over activate_mm. Architectures that do IPI based TLB shootdowns should enable this. +# Should make this depend on MMU, because there is little use for lazy mm switching +# with NOMMU. Must audit NOMMU architecture code for lazy mm refcounting first. +config MMU_LAZY_TLB + def_bool y + help + Enable "lazy TLB" mmu context switching for kernel threads. + If this is disabled then switching to a kernel thread always + switches to init_mm. If mm switches are inexpensive or free + (in the case of NOMMU) then this could be disabled. + +config MMU_LAZY_TLB_REFCOUNT + def_bool y + depends on MMU_LAZY_TLB + help + This must be enabled if MMU_LAZY_TLB is enabled until the next + patch. + config ARCH_HAVE_NMI_SAFE_CMPXCHG bool diff --git a/include/linux/sched/mm.h b/include/linux/sched/mm.h index 94a117160083..5edf8e942c84 100644 --- a/include/linux/sched/mm.h +++ b/include/linux/sched/mm.h @@ -52,12 +52,21 @@ static inline void mmdrop(struct mm_struct *mm) /* Helpers for lazy TLB mm refcounting */ static inline void mmgrab_lazy_tlb(struct mm_struct *mm) { - mmgrab(mm); + if (IS_ENABLED(CONFIG_MMU_LAZY_TLB_REFCOUNT)) + mmgrab(mm); } static inline void mmdrop_lazy_tlb(struct mm_struct *mm) { - mmdrop(mm); + if (IS_ENABLED(CONFIG_MMU_LAZY_TLB_REFCOUNT)) { + mmdrop(mm); + } else { + /* + * mmdrop_lazy_tlb must provide a full memory barrier, see the + * membarrier comment finish_task_switch which relies on this. + */ + smp_mb(); + } } /** diff --git a/kernel/sched/core.c b/kernel/sched/core.c index c2f8ea43d29b..9c1dc9406e4b 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -3579,7 +3579,7 @@ static struct rq *finish_task_switch(struct task_struct *prev) __releases(rq->lock) { struct rq *rq = this_rq(); - struct mm_struct *mm = rq->prev_mm; + struct mm_struct *mm = NULL; long prev_state; /* @@ -3598,7 +3598,10 @@ static struct rq *finish_task_switch(struct task_struct *prev) current->comm, current->pid, preempt_count())) preempt_count_set(FORK_PREEMPT_COUNT); - rq->prev_mm = NULL; +#ifdef CONFIG_MMU_LAZY_TLB_REFCOUNT + mm = rq->prev_lazy_mm; + rq->prev_lazy_mm = NULL; +#endif /* * A task struct has one reference for the use as "current". @@ -3722,22 +3725,10 @@ asmlinkage __visible void schedule_tail(struct task_struct *prev) calculate_sigpending(); } -/* - * context_switch - switch to the new MM and the new thread's register state. - */ -static __always_inline struct rq * -context_switch(struct rq *rq, struct task_struct *prev, - struct task_struct *next, struct rq_flags *rf) +static __always_inline void +context_switch_mm(struct rq *rq, struct task_struct *prev, + struct task_struct *next) { - prepare_task_switch(rq, prev, next); - - /* - * For paravirt, this is coupled with an exit in switch_to to - * combine the page table reload and the switch backend into - * one hypercall. - */ - arch_start_context_switch(prev); - /* * kernel -> kernel lazy + transfer active * user -> kernel lazy + mmgrab_lazy_tlb() active @@ -3766,11 +3757,57 @@ context_switch(struct rq *rq, struct task_struct *prev, switch_mm_irqs_off(prev->active_mm, next->mm, next); if (!prev->mm) { // from kernel - /* will mmdrop_lazy_tlb() in finish_task_switch(). */ - rq->prev_mm = prev->active_mm; +#ifdef CONFIG_MMU_LAZY_TLB_REFCOUNT + /* Will mmdrop_lazy_tlb() in finish_task_switch(). */ + rq->prev_lazy_mm = prev->active_mm; prev->active_mm = NULL; +#else + /* + * Without MMU_LAZY_REFCOUNT there is no lazy + * tracking (because no rq->prev_lazy_mm) in + * finish_task_switch, so no mmdrop_lazy_tlb(), + * so no memory barrier for membarrier (see the + * membarrier comment in finish_task_switch()). + * Do it here. + */ + smp_mb(); +#endif } } +} + +static __always_inline void +context_switch_mm_nolazy(struct rq *rq, struct task_struct *prev, + struct task_struct *next) +{ + if (!next->mm) + next->active_mm = &init_mm; + membarrier_switch_mm(rq, prev->active_mm, next->active_mm); + switch_mm_irqs_off(prev->active_mm, next->active_mm, next); + if (!prev->mm) + prev->active_mm = NULL; +} + +/* + * context_switch - switch to the new MM and the new thread's register state. + */ +static __always_inline struct rq * +context_switch(struct rq *rq, struct task_struct *prev, + struct task_struct *next, struct rq_flags *rf) +{ + prepare_task_switch(rq, prev, next); + + /* + * For paravirt, this is coupled with an exit in switch_to to + * combine the page table reload and the switch backend into + * one hypercall. + */ + arch_start_context_switch(prev); + + if (IS_ENABLED(CONFIG_MMU_LAZY_TLB)) + context_switch_mm(rq, prev, next); + else + context_switch_mm_nolazy(rq, prev, next); rq->clock_update_flags &= ~(RQCF_ACT_SKIP|RQCF_REQ_SKIP); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index df80bfcea92e..3b72aec5a2f2 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -950,7 +950,9 @@ struct rq { struct task_struct *idle; struct task_struct *stop; unsigned long next_balance; - struct mm_struct *prev_mm; +#ifdef CONFIG_MMU_LAZY_TLB_REFCOUNT + struct mm_struct *prev_lazy_mm; +#endif unsigned int clock_update_flags; u64 clock;