From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934226AbbIVTq1 (ORCPT ); Tue, 22 Sep 2015 15:46:27 -0400 Received: from terminus.zytor.com ([198.137.202.10]:54678 "EHLO terminus.zytor.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1759470AbbIVTqW (ORCPT ); Tue, 22 Sep 2015 15:46:22 -0400 Date: Tue, 22 Sep 2015 12:45:38 -0700 From: tip-bot for Toshi Kani Message-ID: Cc: hpa@zytor.com, mingo@kernel.org, linux-kernel@vger.kernel.org, tglx@linutronix.de, elliott@hpe.com, toshi.kani@hpe.com, konrad.wilk@oracle.com, mingo@redhat.com, akpm@linux-foundation.org, bp@alien8.de, jgross@suse.com Reply-To: akpm@linux-foundation.org, jgross@suse.com, bp@alien8.de, mingo@redhat.com, toshi.kani@hpe.com, konrad.wilk@oracle.com, elliott@hpe.com, tglx@linutronix.de, linux-kernel@vger.kernel.org, hpa@zytor.com, mingo@kernel.org In-Reply-To: <1442514264-12475-11-git-send-email-toshi.kani@hpe.com> References: <1442514264-12475-11-git-send-email-toshi.kani@hpe.com> To: linux-tip-commits@vger.kernel.org Subject: [tip:x86/mm] x86/mm: Fix __split_large_page() to handle large PAT bit Git-Commit-ID: d551aaa2f7e1387fa66093ce9914c2e91f283a50 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 Commit-ID: d551aaa2f7e1387fa66093ce9914c2e91f283a50 Gitweb: http://git.kernel.org/tip/d551aaa2f7e1387fa66093ce9914c2e91f283a50 Author: Toshi Kani AuthorDate: Thu, 17 Sep 2015 12:24:23 -0600 Committer: Thomas Gleixner CommitDate: Tue, 22 Sep 2015 21:27:33 +0200 x86/mm: Fix __split_large_page() to handle large PAT bit __split_large_page() is called from __change_page_attr() to change the mapping attribute by splitting a given large page into smaller pages. This function uses pte_pfn() and pte_pgprot() for PUD/PMD, which do not handle the large PAT bit properly. Fix __split_large_page() by using the corresponding pud/pmd pfn/ pgprot interfaces. Also remove '#ifdef CONFIG_X86_64', which is not necessary. Signed-off-by: Toshi Kani Cc: Andrew Morton Cc: Juergen Gross Cc: H. Peter Anvin Cc: Ingo Molnar Cc: Borislav Petkov Cc: Konrad Wilk Cc: Robert Elliot Cc: linux-mm@kvack.org Link: http://lkml.kernel.org/r/1442514264-12475-11-git-send-email-toshi.kani@hpe.com Signed-off-by: Thomas Gleixner --- arch/x86/mm/pageattr.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 3f61271..ab9465b 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -605,7 +605,7 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address, struct page *base) { pte_t *pbase = (pte_t *)page_address(base); - unsigned long pfn, pfninc = 1; + unsigned long ref_pfn, pfn, pfninc = 1; unsigned int i, level; pte_t *tmp; pgprot_t ref_prot; @@ -622,26 +622,33 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address, } paravirt_alloc_pte(&init_mm, page_to_pfn(base)); - ref_prot = pte_pgprot(pte_clrhuge(*kpte)); - /* promote PAT bit to correct position */ - if (level == PG_LEVEL_2M) + switch (level) { + case PG_LEVEL_2M: + ref_prot = pmd_pgprot(*(pmd_t *)kpte); + /* clear PSE and promote PAT bit to correct position */ ref_prot = pgprot_large_2_4k(ref_prot); + ref_pfn = pmd_pfn(*(pmd_t *)kpte); + break; -#ifdef CONFIG_X86_64 - if (level == PG_LEVEL_1G) { + case PG_LEVEL_1G: + ref_prot = pud_pgprot(*(pud_t *)kpte); + ref_pfn = pud_pfn(*(pud_t *)kpte); pfninc = PMD_PAGE_SIZE >> PAGE_SHIFT; + /* - * Set the PSE flags only if the PRESENT flag is set + * Clear the PSE flags if the PRESENT flag is not set * otherwise pmd_present/pmd_huge will return true * even on a non present pmd. */ - if (pgprot_val(ref_prot) & _PAGE_PRESENT) - pgprot_val(ref_prot) |= _PAGE_PSE; - else + if (!(pgprot_val(ref_prot) & _PAGE_PRESENT)) pgprot_val(ref_prot) &= ~_PAGE_PSE; + break; + + default: + spin_unlock(&pgd_lock); + return 1; } -#endif /* * Set the GLOBAL flags only if the PRESENT flag is set @@ -657,7 +664,7 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address, /* * Get the target pfn from the original entry: */ - pfn = pte_pfn(*kpte); + pfn = ref_pfn; for (i = 0; i < PTRS_PER_PTE; i++, pfn += pfninc) set_pte(&pbase[i], pfn_pte(pfn, canon_pgprot(ref_prot)));