Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753174AbdFVLOA (ORCPT ); Thu, 22 Jun 2017 07:14:00 -0400 Received: from terminus.zytor.com ([65.50.211.136]:60527 "EHLO terminus.zytor.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752918AbdFVLN6 (ORCPT ); Thu, 22 Jun 2017 07:13:58 -0400 Date: Thu, 22 Jun 2017 04:08:11 -0700 From: tip-bot for Andy Lutomirski Message-ID: Cc: riel@redhat.com, akpm@linux-foundation.org, bp@alien8.de, linux-kernel@vger.kernel.org, nadav.amit@gmail.com, mgorman@suse.de, hpa@zytor.com, dvlasenk@redhat.com, luto@kernel.org, tglx@linutronix.de, jpoimboe@redhat.com, dave.hansen@intel.com, peterz@infradead.org, mingo@kernel.org, brgerst@gmail.com, torvalds@linux-foundation.org, arjan@linux.intel.com, bp@suse.de Reply-To: dvlasenk@redhat.com, hpa@zytor.com, mgorman@suse.de, nadav.amit@gmail.com, linux-kernel@vger.kernel.org, riel@redhat.com, akpm@linux-foundation.org, bp@alien8.de, bp@suse.de, arjan@linux.intel.com, torvalds@linux-foundation.org, brgerst@gmail.com, mingo@kernel.org, peterz@infradead.org, dave.hansen@intel.com, tglx@linutronix.de, jpoimboe@redhat.com, luto@kernel.org In-Reply-To: <2a859ac01245f9594c58f9d0a8b2ed8a7cd2507e.1498022414.git.luto@kernel.org> References: <2a859ac01245f9594c58f9d0a8b2ed8a7cd2507e.1498022414.git.luto@kernel.org> To: linux-tip-commits@vger.kernel.org Subject: [tip:x86/mm] x86/ldt: Simplify the LDT switching logic Git-Commit-ID: 7353425881b170a24990b4d3bdcd14b1156fa8bd X-Mailer: tip-git-log-daemon Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=UTF-8 Content-Disposition: inline Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 4832 Lines: 131 Commit-ID: 7353425881b170a24990b4d3bdcd14b1156fa8bd Gitweb: http://git.kernel.org/tip/7353425881b170a24990b4d3bdcd14b1156fa8bd Author: Andy Lutomirski AuthorDate: Tue, 20 Jun 2017 22:22:08 -0700 Committer: Ingo Molnar CommitDate: Thu, 22 Jun 2017 10:57:50 +0200 x86/ldt: Simplify the LDT switching logic Originally, Linux reloaded the LDT whenever the prev mm or the next mm had an LDT. It was changed in 2002 in: 0bbed3beb4f2 ("[PATCH] Thread-Local Storage (TLS) support") (commit from the historical tree), like this: - /* load_LDT, if either the previous or next thread - * has a non-default LDT. + /* + * load the LDT, if the LDT is different: */ - if (next->context.size+prev->context.size) + if (unlikely(prev->context.ldt != next->context.ldt)) load_LDT(&next->context); The current code is unlikely to avoid any LDT reloads, since different mms won't share an LDT. When we redo lazy mode to stop flush IPIs without switching to init_mm, though, the current logic would become incorrect: it will be possible to have real_prev == next but nonetheless have a stale LDT descriptor. Simplify the code to update LDTR if either the previous or the next mm has an LDT, i.e. effectively restore the historical logic.. While we're at it, clean up the code by moving all the ifdeffery to a header where it belongs. Signed-off-by: Andy Lutomirski Reviewed-by: Thomas Gleixner Reviewed-by: Borislav Petkov Acked-by: Rik van Riel Cc: Andrew Morton Cc: Arjan van de Ven Cc: Borislav Petkov Cc: Brian Gerst Cc: Dave Hansen Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Mel Gorman Cc: Nadav Amit Cc: Peter Zijlstra Cc: linux-mm@kvack.org Link: http://lkml.kernel.org/r/2a859ac01245f9594c58f9d0a8b2ed8a7cd2507e.1498022414.git.luto@kernel.org Signed-off-by: Ingo Molnar --- arch/x86/include/asm/mmu_context.h | 26 ++++++++++++++++++++++++++ arch/x86/mm/tlb.c | 20 ++------------------ 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h index 1458f53..ecfcb66 100644 --- a/arch/x86/include/asm/mmu_context.h +++ b/arch/x86/include/asm/mmu_context.h @@ -93,6 +93,32 @@ static inline void load_mm_ldt(struct mm_struct *mm) #else clear_LDT(); #endif +} + +static inline void switch_ldt(struct mm_struct *prev, struct mm_struct *next) +{ +#ifdef CONFIG_MODIFY_LDT_SYSCALL + /* + * Load the LDT if either the old or new mm had an LDT. + * + * An mm will never go from having an LDT to not having an LDT. Two + * mms never share an LDT, so we don't gain anything by checking to + * see whether the LDT changed. There's also no guarantee that + * prev->context.ldt actually matches LDTR, but, if LDTR is non-NULL, + * then prev->context.ldt will also be non-NULL. + * + * If we really cared, we could optimize the case where prev == next + * and we're exiting lazy mode. Most of the time, if this happens, + * we don't actually need to reload LDTR, but modify_ldt() is mostly + * used by legacy code and emulators where we don't need this level of + * performance. + * + * This uses | instead of || because it generates better code. + */ + if (unlikely((unsigned long)prev->context.ldt | + (unsigned long)next->context.ldt)) + load_mm_ldt(next); +#endif DEBUG_LOCKS_WARN_ON(preemptible()); } diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 2a5e851..b2485d6 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -148,25 +148,9 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, real_prev != &init_mm); cpumask_clear_cpu(cpu, mm_cpumask(real_prev)); - /* Load per-mm CR4 state */ + /* Load per-mm CR4 and LDTR state */ load_mm_cr4(next); - -#ifdef CONFIG_MODIFY_LDT_SYSCALL - /* - * Load the LDT, if the LDT is different. - * - * It's possible that prev->context.ldt doesn't match - * the LDT register. This can happen if leave_mm(prev) - * was called and then modify_ldt changed - * prev->context.ldt but suppressed an IPI to this CPU. - * In this case, prev->context.ldt != NULL, because we - * never set context.ldt to NULL while the mm still - * exists. That means that next->context.ldt != - * prev->context.ldt, because mms never share an LDT. - */ - if (unlikely(real_prev->context.ldt != next->context.ldt)) - load_mm_ldt(next); -#endif + switch_ldt(real_prev, next); } /*