mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Andi Kleen <ak@suse.de>
To: patches@x86-64.org, linux-kernel@vger.kernel.org
Subject: [PATCH] [13/50] x86: Fix and reenable CLFLUSH support in change_page_attr()
Date: Sat, 22 Sep 2007 00:32:11 +0200 (CEST)	[thread overview]
Message-ID: <20070921223211.BB50413DCD@wotan.suse.de> (raw)
In-Reply-To: <200709221231.836138000@suse.de>


Reenable CLFLUSH support in change_page_attr()

Mark pages that need to be cache flushed with a special bit
before putting them into the deferred list.
(PG_owner_priv_1).  Then only cache flush these pages
and don't free them.

Takes especial care to handle cases where the page's LRU
or owner_priv_1 bit is already used. Fall back to full cache
flushes then.

They probably do not happen right now, but this makes
it more future proof. 

TBD port to i386

Signed-off-by: Andi Kleen <ak@suse.de>

---
 arch/i386/mm/pageattr.c      |   69 +++++++++++++++++++++++++++++++++--------
 arch/x86_64/mm/pageattr.c    |   72 +++++++++++++++++++++++++++++++++----------
 include/asm-i386/pgtable.h   |    2 +
 include/asm-x86_64/pgtable.h |    1 
 4 files changed, 115 insertions(+), 29 deletions(-)

Index: linux/arch/x86_64/mm/pageattr.c
===================================================================
--- linux.orig/arch/x86_64/mm/pageattr.c
+++ linux/arch/x86_64/mm/pageattr.c
@@ -13,6 +13,10 @@
 #include <asm/tlbflush.h>
 #include <asm/io.h>
 
+#define PageFlush(p) test_bit(PG_owner_priv_1, &(p)->flags)
+#define SetPageFlush(p) set_bit(PG_owner_priv_1, &(p)->flags)
+#define TestClearPageFlush(p) test_and_clear_bit(PG_owner_priv_1, &(p)->flags)
+
 pte_t *lookup_address(unsigned long address)
 { 
 	pgd_t *pgd = pgd_offset_k(address);
@@ -61,6 +65,11 @@ static struct page *split_large_page(uns
 	return base;
 } 
 
+struct flush_arg {
+	int full_flush;
+	struct list_head l;
+};
+
 static void cache_flush_page(void *adr)
 {
 	int i;
@@ -70,17 +79,16 @@ static void cache_flush_page(void *adr)
 
 static void flush_kernel_map(void *arg)
 {
-	struct list_head *l = (struct list_head *)arg;
+	struct flush_arg *a = (struct flush_arg *)arg;
 	struct page *pg;
 
-	/* When clflush is available always use it because it is
+	/* When clflush is available use it because it is
 	   much cheaper than WBINVD. */
-	/* clflush is still broken. Disable for now. */
-	if (1 || !cpu_has_clflush)
+	if (a->full_flush || !cpu_has_clflush)
 		asm volatile("wbinvd" ::: "memory");
-	else list_for_each_entry(pg, l, lru) {
-		void *adr = page_address(pg);
-		cache_flush_page(adr);
+	else list_for_each_entry(pg, &a->l, lru) {
+		if (PageFlush(pg))
+			cache_flush_page(page_address(pg));
 	}
 	__flush_tlb_all();
 }
@@ -90,11 +98,17 @@ static inline void flush_map(struct list
 	on_each_cpu(flush_kernel_map, l, 1, 1);
 }
 
-static LIST_HEAD(deferred_pages); /* protected by init_mm.mmap_sem */
+/* both protected by init_mm.mmap_sem */
+static int full_flush;
+static LIST_HEAD(deferred_pages);
 
-static inline void save_page(struct page *fpage)
+static inline void save_page(struct page *fpage, int data)
 {
-	if (!test_and_set_bit(PG_arch_1, &fpage->flags))
+	if (data && cpu_has_clflush)
+		SetPageFlush(fpage);
+	if (test_and_set_bit(PG_arch_1, &fpage->flags))
+		return;
+	if (cpu_has_clflush || !data)
 		list_add(&fpage->lru, &deferred_pages);
 }
 
@@ -122,6 +136,17 @@ static void revert_page(unsigned long ad
 	set_pte((pte_t *)pmd, large_pte);
 }      
 
+static struct page *flush_page(unsigned long address)
+{
+	struct page *p;
+	if (!(pfn_valid(__pa(address) >> PAGE_SHIFT)))
+		return NULL;
+	p = virt_to_page(address);
+	if ((PageFlush(p) || PageLRU(p)) && !test_bit(PG_arch_1, &p->flags))
+		return NULL;
+	return p;
+}
+
 static int
 __change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot,
 				   pgprot_t ref_prot)
@@ -133,8 +158,19 @@ __change_page_attr(unsigned long address
 	kpte = lookup_address(address);
 	if (!kpte) return 0;
 	kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK);
-	BUG_ON(PageLRU(kpte_page));
 	BUG_ON(PageCompound(kpte_page));
+	BUG_ON(PageLRU(kpte_page));
+
+	/* Do caching attributes change?
+	   Note: this will need changes if the PAT bit is used (it isn't
+   	   currently) because that one varies between 2MB and 4K pages. */
+	if ((pte_val(*kpte)&_PAGE_CACHE) != (pgprot_val(prot)&_PAGE_CACHE)) {
+		struct page *p = flush_page(address);
+		if (!p)
+			full_flush = 1;
+		else
+			save_page(p, 1);
+	}
 	if (pgprot_val(prot) != pgprot_val(ref_prot)) { 
 		if (!pte_huge(*kpte)) {
 			set_pte(kpte, pfn_pte(pfn, prot));
@@ -162,7 +198,7 @@ __change_page_attr(unsigned long address
 	/* on x86-64 the direct mapping set at boot is not using 4k pages */
  	BUG_ON(PageReserved(kpte_page));
 
-	save_page(kpte_page);
+	save_page(kpte_page, 0);
 	if (page_private(kpte_page) == 0)
 		revert_page(address, ref_prot);
 	return 0;
@@ -227,17 +263,21 @@ int change_page_attr(struct page *page, 
 void global_flush_tlb(void)
 { 
 	struct page *pg, *next;
-	struct list_head l;
+	struct flush_arg arg;
 
 	down_read(&init_mm.mmap_sem);
-	list_replace_init(&deferred_pages, &l);
+	arg.full_flush = full_flush;
+	full_flush = 0;
+	list_replace_init(&deferred_pages, &arg.l);
 	up_read(&init_mm.mmap_sem);
 
-	flush_map(&l);
+	flush_map(&arg);
 
-	list_for_each_entry_safe(pg, next, &l, lru) {
+	list_for_each_entry_safe(pg, next, &arg.l, lru) {
 		list_del(&pg->lru);
 		clear_bit(PG_arch_1, &pg->flags);
+		if (TestClearPageFlush(pg))
+			continue;
 		if (page_private(pg) != 0)
 			continue;
 		ClearPagePrivate(pg);
Index: linux/include/asm-x86_64/pgtable.h
===================================================================
--- linux.orig/include/asm-x86_64/pgtable.h
+++ linux/include/asm-x86_64/pgtable.h
@@ -165,6 +165,7 @@ static inline pte_t ptep_get_and_clear_f
 
 #define _PAGE_PROTNONE	0x080	/* If not present */
 #define _PAGE_NX        (_AC(1,UL)<<_PAGE_BIT_NX)
+#define _PAGE_CACHE	(_PAGE_PCD|_PAGE_PWT)
 
 #define _PAGE_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define _KERNPG_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
Index: linux/arch/i386/mm/pageattr.c
===================================================================
--- linux.orig/arch/i386/mm/pageattr.c
+++ linux/arch/i386/mm/pageattr.c
@@ -14,7 +14,13 @@
 #include <asm/pgalloc.h>
 #include <asm/sections.h>
 
+#define PageFlush(p) test_bit(PG_owner_priv_1, &(p)->flags)
+#define SetPageFlush(p) set_bit(PG_owner_priv_1, &(p)->flags)
+#define TestClearPageFlush(p) test_and_clear_bit(PG_owner_priv_1, &(p)->flags)
+
 static DEFINE_SPINLOCK(cpa_lock);
+/* Both protected by cpa_lock */
+static int full_flush;
 static struct list_head df_list = LIST_HEAD_INIT(df_list);
 
 
@@ -68,6 +74,11 @@ static struct page *split_large_page(uns
 	return base;
 } 
 
+struct flush_arg {
+	int full_flush;
+	struct list_head l;
+};
+
 static void cache_flush_page(struct page *p)
 { 
 	void *adr = page_address(p);
@@ -78,13 +89,14 @@ static void cache_flush_page(struct page
 
 static void flush_kernel_map(void *arg)
 {
-	struct list_head *lh = (struct list_head *)arg;
+	struct flush_arg *a = (struct flush_arg *)arg;
 	struct page *p;
 
-	/* High level code is not ready for clflush yet */
-	if (0 && cpu_has_clflush) {
-		list_for_each_entry (p, lh, lru)
-			cache_flush_page(p);
+	if (!a->full_flush && cpu_has_clflush) {
+		list_for_each_entry (p, &a->l, lru) {
+			if (PageFlush(p))
+				cache_flush_page(p);
+		}
 	} else if (boot_cpu_data.x86_model >= 4)
 		wbinvd();
 
@@ -136,10 +148,25 @@ static inline void revert_page(struct pa
 			    ref_prot));
 }
 
-static inline void save_page(struct page *kpte_page)
+static inline void save_page(struct page *fpage, int data)
+{
+	if (data && cpu_has_clflush)
+		SetPageFlush(fpage);
+	if (test_and_set_bit(PG_arch_1, &fpage->flags))
+		return;
+	if (!data || cpu_has_clflush)
+		list_add(&fpage->lru, &df_list);
+}
+
+static struct page *flush_page(unsigned long address)
 {
-	if (!test_and_set_bit(PG_arch_1, &kpte_page->flags))
-		list_add(&kpte_page->lru, &df_list);
+	struct page *p;
+	if (!(pfn_valid(__pa(address) >> PAGE_SHIFT)))
+		return NULL;
+	p = virt_to_page(address);
+	if ((PageFlush(p) || PageLRU(p)) && !test_bit(PG_arch_1, &p->flags))
+		return NULL;
+	return p;
 }
 
 static int
@@ -158,6 +185,18 @@ __change_page_attr(struct page *page, pg
 	kpte_page = virt_to_page(kpte);
 	BUG_ON(PageLRU(kpte_page));
 	BUG_ON(PageCompound(kpte_page));
+	BUG_ON(PageLRU(kpte_page));
+
+	/* Do caching attributes change?
+	   Note: this will need changes if the PAT bit is used (it isn't
+   	   currently) because that one varies between 2MB and 4K pages. */
+	if ((pte_val(*kpte)&_PAGE_CACHE) != (pgprot_val(prot)&_PAGE_CACHE)) {
+		struct page *p = flush_page(address);
+		if (!p)
+			full_flush = 1;
+		else
+			save_page(p, 1);
+	}
 
 	if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) { 
 		if (!pte_huge(*kpte)) {
@@ -189,7 +228,7 @@ __change_page_attr(struct page *page, pg
 	 * replace it with a largepage.
 	 */
 
-	save_page(kpte_page);
+	save_page(kpte_page, 0);
 	if (!PageReserved(kpte_page)) {
 		if (cpu_has_pse && (page_private(kpte_page) == 0)) {
 			paravirt_release_pt(page_to_pfn(kpte_page));
@@ -235,18 +274,22 @@ int change_page_attr(struct page *page, 
 
 void global_flush_tlb(void)
 {
-	struct list_head l;
+	struct flush_arg arg;
 	struct page *pg, *next;
 
 	BUG_ON(irqs_disabled());
 
 	spin_lock_irq(&cpa_lock);
-	list_replace_init(&df_list, &l);
+	arg.full_flush = full_flush;
+	full_flush = 0;
+	list_replace_init(&df_list, &arg.l);
 	spin_unlock_irq(&cpa_lock);
-	flush_map(&l);
-	list_for_each_entry_safe(pg, next, &l, lru) {
+	flush_map(&arg);
+	list_for_each_entry_safe(pg, next, &arg.l, lru) {
 		list_del(&pg->lru);
 		clear_bit(PG_arch_1, &pg->flags);
+		if (TestClearPageFlush(pg))
+			continue;
 		if (PageReserved(pg) || !cpu_has_pse || page_private(pg) != 0)
 			continue;
 		ClearPagePrivate(pg);
Index: linux/include/asm-i386/pgtable.h
===================================================================
--- linux.orig/include/asm-i386/pgtable.h
+++ linux/include/asm-i386/pgtable.h
@@ -128,6 +128,8 @@ void paging_init(void);
 #else
 #define _PAGE_NX	0
 #endif
+#define _PAGE_CACHE	(_PAGE_PCD|_PAGE_PWT)
+
 
 #define _PAGE_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define _KERNPG_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)

  parent reply	other threads:[~2007-09-21 22:36 UTC|newest]

Thread overview: 105+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-09-21 22:31 [PATCH] [0/50] x86 2.6.24 patches review II Andi Kleen
2007-09-21 22:31 ` [PATCH] [1/50] x86_64: store core id bits in cpuinfo_x8 Andi Kleen
2007-09-21 22:31 ` [PATCH] [2/50] x86_64: use core id bits for apicid_to_node initialization Andi Kleen
2007-09-21 22:32 ` [PATCH] [3/50] x86_64: remove never used apic_mapped Andi Kleen
2007-09-21 22:32 ` [PATCH] [4/50] x86: add cpu codenames for Kconfig.cpu Andi Kleen
2007-09-21 22:45   ` Dave Jones
2007-09-21 23:52     ` Alan Cox
2007-09-22  6:57     ` Sam Ravnborg
2007-09-22  9:46       ` Jan Engelhardt
2007-09-22 14:23       ` Dave Jones
2007-09-22 17:40         ` Randy Dunlap
2007-09-30 10:09     ` Andi Kleen
2007-09-22 17:50   ` Thomas Gleixner
2007-10-01 11:17     ` Andi Kleen
2007-09-21 22:32 ` [PATCH] [5/50] i386: change order in Kconfig.cpu Andi Kleen
2007-09-21 22:32 ` [PATCH] [6/50] i386: clean up oops/bug reports Andi Kleen
2007-09-21 22:41   ` Chuck Ebbert
2007-09-22  9:47     ` Jan Engelhardt
2007-09-22  2:51   ` Killing printk calls for size (Re: [PATCH] [6/50] i386: clean up oops/bug reports) Oleg Verych
2007-09-21 22:32 ` [PATCH] [7/50] x86: expand /proc/interrupts to include missing vectors, v2 Andi Kleen
2007-09-22  3:35   ` possible corrections in the docs (Re: [PATCH] [7/50] x86: expand /proc/interrupts to include missing vectors, v2) Oleg Verych
2007-09-22  3:52     ` Joe Korty
2007-09-21 22:32 ` [PATCH] [8/50] x86_64: remove x86_cpu_to_log_apicid Andi Kleen
2007-09-21 22:32 ` [PATCH] [9/50] i386: validate against ACPI motherboard resources Andi Kleen
2007-09-22  6:49   ` Yinghai Lu
2007-09-22  6:56     ` Yinghai Lu
2007-09-22 16:28     ` Robert Hancock
2007-09-22 18:01       ` Thomas Gleixner
2007-09-22 18:42         ` Robert Hancock
2007-09-22 20:40           ` Yinghai Lu
2007-09-22 20:56             ` H. Peter Anvin
2007-09-22 21:27             ` Robert Hancock
2007-09-23  1:20               ` Yinghai Lu
2007-09-23  1:34               ` Yinghai Lu
2007-09-22 20:47       ` Yinghai Lu
2007-09-21 22:32 ` [PATCH] [10/50] x86_64: install unstripped copies of compat vdso on disk Andi Kleen
2007-09-21 22:32 ` [PATCH] [11/50] x86_64: Install unstripped copy of 64bit vdso to disk Andi Kleen
2007-09-21 22:32 ` [PATCH] [12/50] x86_64: Untable __init references between IO data Andi Kleen
2007-09-22  5:37   ` [patches] " Yinghai Lu
2007-09-21 22:32 ` Andi Kleen [this message]
2007-09-22  5:47   ` [PATCH] [13/50] x86: Fix and reenable CLFLUSH support in change_page_attr() Oleg Verych
2007-10-01 10:59     ` Andi Kleen
2007-09-24  8:23   ` [patches] [PATCH] [13/50] x86: Fix and reenable CLFLUSH support inchange_page_attr() Jan Beulich
2007-10-01 10:38     ` Andi Kleen
2007-09-21 22:32 ` [PATCH] [14/50] x86: Minor code-style cleanups to change_page_attr Andi Kleen
2007-09-21 22:32 ` [PATCH] [15/50] x86_64: Return EINVAL for unknown address in change_page_attr Andi Kleen
2007-09-24  8:32   ` [patches] [PATCH] [15/50] x86_64: Return EINVAL for unknown addressin change_page_attr Jan Beulich
2007-09-21 22:32 ` [PATCH] [16/50] x86: Use macros to modify the PG_arch_1 page flags in change_page_attr Andi Kleen
2007-09-21 22:32 ` [PATCH] [17/50] x86_64: remove STR() macros Andi Kleen
2007-09-21 22:32 ` [PATCH] [18/50] x86_64: Save registers in saved_context during suspend and hibernation Andi Kleen
2007-09-21 22:32 ` [PATCH] [19/50] Experimental: detect if SVM is disabled by BIOS Andi Kleen
2007-09-22  6:59   ` Sam Ravnborg
2007-09-22  9:17   ` Joerg Roedel
2007-10-01 16:47     ` Andi Kleen
2007-10-01 20:12       ` Joerg Roedel
2007-10-01 21:45         ` [patches] " Andi Kleen
2007-10-01 22:13           ` Joerg Roedel
2007-09-22 19:05   ` Thomas Gleixner
2007-09-21 22:32 ` [PATCH] [20/50] x86_64: Fix some broken white space in arch/x86_64/mm/init.c Andi Kleen
2007-09-22 19:17   ` Thomas Gleixner
2007-09-23  1:47     ` Oleg Verych
2007-09-21 22:32 ` [PATCH] [21/50] i386: Misc cpuinit annotations Andi Kleen
2007-09-21 22:32 ` [PATCH] [22/50] " Andi Kleen
2007-09-21 22:32 ` [PATCH] [23/50] x86_64: Implement missing x86_64 function smp_call_function_mask() Andi Kleen
2007-09-21 22:32 ` [PATCH] [24/50] x86_64: Eliminate result signage problem in asm-x86_64/bitops.h Andi Kleen
2007-09-21 22:32 ` [PATCH] [25/50] x86_64: Add parenthesis to IRQ vector macros Andi Kleen
2007-09-21 22:32 ` [PATCH] [26/50] i386: export i386 smp_call_function_mask() to modules Andi Kleen
2007-09-21 22:32 ` [PATCH] [27/50] x86_64: Remove duplicated vsyscall nsec update Andi Kleen
2007-09-21 22:32 ` [PATCH] [28/50] i386: remove stub early_printk.c Andi Kleen
2007-09-21 22:32 ` [PATCH] [29/50] x86: honor _PAGE_PSE bit on page walks Andi Kleen
2007-09-21 22:32 ` [PATCH] [30/50] x86_64: remove some dead code Andi Kleen
2007-09-21 22:32 ` [PATCH] [31/50] x86_64: honor notify_die() returning NOTIFY_STOP Andi Kleen
2007-09-22 19:23   ` Thomas Gleixner
2007-09-21 22:32 ` [PATCH] [32/50] x86: Show last exception from/to register contents Andi Kleen
2007-09-21 22:32 ` [PATCH] [33/50] x86: rename .i assembler includes to .h Andi Kleen
2007-09-21 22:32 ` [PATCH] [34/50] i386: Fix argument signedness warnings Andi Kleen
2007-09-22  5:06   ` Satyam Sharma
2007-09-22 10:01     ` Jan Engelhardt
2007-09-22 17:42       ` Randy Dunlap
2007-09-21 22:32 ` [PATCH] [35/50] i386: Do cpuid_device_create() in CPU_UP_PREPARE instead of CPU_ONLINE Andi Kleen
2007-09-22 19:33   ` Thomas Gleixner
2007-09-23  1:52     ` Akinobu Mita
2007-09-23  7:52       ` Thomas Gleixner
2007-09-21 22:32 ` [PATCH] [36/50] x86: Use raw locks during oopses Andi Kleen
2007-09-21 22:32 ` [PATCH] [37/50] x86_64: Clean up mce= argument parsing slightly Andi Kleen
2007-09-21 22:32 ` [PATCH] [38/50] x86_64: fix off-by-one in find_next_zero_string Andi Kleen
2007-09-21 22:32 ` [PATCH] [39/50] i386: fix 4 bit apicid assumption of mach-default Andi Kleen
2007-09-21 22:32 ` [PATCH] [40/50] i386: Fix section mismatch Andi Kleen
2007-09-21 22:32 ` [PATCH] [41/50] i386: fix section mismatch warning in intel.c Andi Kleen
2007-09-21 22:32 ` [PATCH] [42/50] i386: constify wd_ops Andi Kleen
2007-09-21 22:32 ` [PATCH] [43/50] x86: multi-byte single instruction NOPs Andi Kleen
2007-09-21 22:32 ` [PATCH] [44/50] i386: Introduce "used_vectors" bitmap which can be used to reserve vectors Andi Kleen
2007-09-21 22:32 ` [PATCH] [45/50] x86_64: configure HPET_EMULATE_RTC automatically Andi Kleen
2007-09-21 22:32 ` [PATCH] [46/50] x86: also show non-zero IRQ counts for vectors that currently don't have a handler Andi Kleen
2007-09-21 22:32 ` [PATCH] [47/50] i386: avoid temporarily inconsistent pte-s Andi Kleen
2007-09-21 22:32 ` [PATCH] [48/50] x86_64: return correct error code from child_rip in x86_64 entry.S Andi Kleen
2007-09-21 22:32 ` [PATCH] [49/50] x86_64: Initialize 64bit registers for a.out executables Andi Kleen
2007-09-21 22:32 ` [PATCH] [50/50] x86_64: Remove fpu io port resource Andi Kleen
2007-09-21 23:00   ` Jeff Garzik
2007-10-01 10:40     ` Andi Kleen
2007-10-01 11:30       ` Jeff Garzik
2007-10-01 11:48         ` Andi Kleen
2007-10-01 13:33           ` Jeff Garzik
2007-10-01 14:16             ` Mark Lord
2007-10-02 14:37         ` Alan Cox

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070921223211.BB50413DCD@wotan.suse.de \
    --to=ak@suse.de \
    --cc=linux-kernel@vger.kernel.org \
    --cc=patches@x86-64.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®