Re: [PATCH 13/18] asm-generic/tlb: Introduce HAVE_MMU_GATHER_NO_GATHER

2018-12-10 Thread Aneesh Kumar K.V
Peter Zijlstra  writes:

> From: Martin Schwidefsky 
>
> Add the Kconfig option HAVE_MMU_GATHER_NO_GATHER to the generic
> mmu_gather code. If the option is set the mmu_gather will not
> track individual pages for delayed page free anymore. A platform
> that enables the option needs to provide its own implementation
> of the __tlb_remove_page_size function to free pages.

Can we rename this to HAVE_NO_BATCH_MMU_GATHER? 

>
> Cc: npig...@gmail.com
> Cc: heiko.carst...@de.ibm.com
> Cc: will.dea...@arm.com
> Cc: aneesh.ku...@linux.vnet.ibm.com
> Cc: a...@linux-foundation.org
> Cc: Linus Torvalds 
> Cc: li...@armlinux.org.uk
> Signed-off-by: Martin Schwidefsky 
> Signed-off-by: Peter Zijlstra (Intel) 
> Link: http://lkml.kernel.org/r/20180918125151.31744-2-schwidef...@de.ibm.com

-aneesh



[PATCH 13/18] asm-generic/tlb: Introduce HAVE_MMU_GATHER_NO_GATHER

2018-09-26 Thread Peter Zijlstra
From: Martin Schwidefsky 

Add the Kconfig option HAVE_MMU_GATHER_NO_GATHER to the generic
mmu_gather code. If the option is set the mmu_gather will not
track individual pages for delayed page free anymore. A platform
that enables the option needs to provide its own implementation
of the __tlb_remove_page_size function to free pages.

Cc: npig...@gmail.com
Cc: heiko.carst...@de.ibm.com
Cc: will.dea...@arm.com
Cc: aneesh.ku...@linux.vnet.ibm.com
Cc: a...@linux-foundation.org
Cc: Linus Torvalds 
Cc: li...@armlinux.org.uk
Signed-off-by: Martin Schwidefsky 
Signed-off-by: Peter Zijlstra (Intel) 
Link: http://lkml.kernel.org/r/20180918125151.31744-2-schwidef...@de.ibm.com
---
 arch/Kconfig  |3 +
 include/asm-generic/tlb.h |9 +++
 mm/mmu_gather.c   |  107 +-
 3 files changed, 70 insertions(+), 49 deletions(-)

--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -368,6 +368,9 @@ config HAVE_RCU_TABLE_NO_INVALIDATE
 config HAVE_MMU_GATHER_PAGE_SIZE
bool
 
+config HAVE_MMU_GATHER_NO_GATHER
+   bool
+
 config ARCH_HAVE_NMI_SAFE_CMPXCHG
bool
 
--- a/include/asm-generic/tlb.h
+++ b/include/asm-generic/tlb.h
@@ -184,6 +184,7 @@ extern void tlb_remove_table(struct mmu_
 
 #endif
 
+#ifndef CONFIG_HAVE_MMU_GATHER_NO_GATHER
 /*
  * If we can't allocate a page to make a big batch of page pointers
  * to work on, then just handle a few from the on-stack structure.
@@ -208,6 +209,10 @@ struct mmu_gather_batch {
  */
 #define MAX_GATHER_BATCH_COUNT (1UL/MAX_GATHER_BATCH)
 
+extern bool __tlb_remove_page_size(struct mmu_gather *tlb, struct page *page,
+  int page_size);
+#endif
+
 /*
  * struct mmu_gather is an opaque type used by the mm code for passing around
  * any data needed by arch specific code for tlb_remove_page.
@@ -254,6 +259,7 @@ struct mmu_gather {
 
unsigned intbatch_count;
 
+#ifndef CONFIG_HAVE_MMU_GATHER_NO_GATHER
struct mmu_gather_batch *active;
struct mmu_gather_batch local;
struct page *__pages[MMU_GATHER_BUNDLE];
@@ -261,6 +267,7 @@ struct mmu_gather {
 #ifdef CONFIG_HAVE_MMU_GATHER_PAGE_SIZE
unsigned int page_size;
 #endif
+#endif
 };
 
 void arch_tlb_gather_mmu(struct mmu_gather *tlb,
@@ -269,8 +276,6 @@ void tlb_flush_mmu(struct mmu_gather *tl
 void arch_tlb_finish_mmu(struct mmu_gather *tlb,
 unsigned long start, unsigned long end, bool force);
 void tlb_flush_mmu_free(struct mmu_gather *tlb);
-extern bool __tlb_remove_page_size(struct mmu_gather *tlb, struct page *page,
-  int page_size);
 
 static inline void __tlb_adjust_range(struct mmu_gather *tlb,
  unsigned long address,
--- a/mm/mmu_gather.c
+++ b/mm/mmu_gather.c
@@ -13,6 +13,8 @@
 
 #ifdef HAVE_GENERIC_MMU_GATHER
 
+#ifndef CONFIG_HAVE_MMU_GATHER_NO_GATHER
+
 static bool tlb_next_batch(struct mmu_gather *tlb)
 {
struct mmu_gather_batch *batch;
@@ -41,6 +43,56 @@ static bool tlb_next_batch(struct mmu_ga
return true;
 }
 
+static void tlb_batch_pages_flush(struct mmu_gather *tlb)
+{
+   struct mmu_gather_batch *batch;
+
+   for (batch = >local; batch && batch->nr; batch = batch->next) {
+   free_pages_and_swap_cache(batch->pages, batch->nr);
+   batch->nr = 0;
+   }
+   tlb->active = >local;
+}
+
+static void tlb_batch_list_free(struct mmu_gather *tlb)
+{
+   struct mmu_gather_batch *batch, *next;
+
+   for (batch = tlb->local.next; batch; batch = next) {
+   next = batch->next;
+   free_pages((unsigned long)batch, 0);
+   }
+   tlb->local.next = NULL;
+}
+
+bool __tlb_remove_page_size(struct mmu_gather *tlb, struct page *page, int 
page_size)
+{
+   struct mmu_gather_batch *batch;
+
+   VM_BUG_ON(!tlb->end);
+
+#ifdef CONFIG_HAVE_MMU_GATHER_PAGE_SIZE
+   VM_WARN_ON(tlb->page_size != page_size);
+#endif
+
+   batch = tlb->active;
+   /*
+* Add the page and check if we are full. If so
+* force a flush.
+*/
+   batch->pages[batch->nr++] = page;
+   if (batch->nr == batch->max) {
+   if (!tlb_next_batch(tlb))
+   return true;
+   batch = tlb->active;
+   }
+   VM_BUG_ON_PAGE(batch->nr > batch->max, page);
+
+   return false;
+}
+
+#endif /* HAVE_MMU_GATHER_NO_GATHER */
+
 void arch_tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm,
unsigned long start, unsigned long end)
 {
@@ -48,12 +100,15 @@ void arch_tlb_gather_mmu(struct mmu_gath
 
/* Is it from 0 to ~0? */
tlb->fullmm = !(start | (end+1));
+
+#ifndef CONFIG_HAVE_MMU_GATHER_NO_GATHER
tlb->need_flush_all = 0;
tlb->local.next = NULL;
tlb->local.nr   = 0;
tlb->local.max  = ARRAY_SIZE(tlb->__pages);
tlb->active = >local;
   

[PATCH 13/18] asm-generic/tlb: Introduce HAVE_MMU_GATHER_NO_GATHER

2018-09-26 Thread Peter Zijlstra
From: Martin Schwidefsky 

Add the Kconfig option HAVE_MMU_GATHER_NO_GATHER to the generic
mmu_gather code. If the option is set the mmu_gather will not
track individual pages for delayed page free anymore. A platform
that enables the option needs to provide its own implementation
of the __tlb_remove_page_size function to free pages.

Cc: npig...@gmail.com
Cc: heiko.carst...@de.ibm.com
Cc: will.dea...@arm.com
Cc: aneesh.ku...@linux.vnet.ibm.com
Cc: a...@linux-foundation.org
Cc: Linus Torvalds 
Cc: li...@armlinux.org.uk
Signed-off-by: Martin Schwidefsky 
Signed-off-by: Peter Zijlstra (Intel) 
Link: http://lkml.kernel.org/r/20180918125151.31744-2-schwidef...@de.ibm.com
---
 arch/Kconfig  |3 +
 include/asm-generic/tlb.h |9 +++
 mm/mmu_gather.c   |  107 +-
 3 files changed, 70 insertions(+), 49 deletions(-)

--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -368,6 +368,9 @@ config HAVE_RCU_TABLE_NO_INVALIDATE
 config HAVE_MMU_GATHER_PAGE_SIZE
bool
 
+config HAVE_MMU_GATHER_NO_GATHER
+   bool
+
 config ARCH_HAVE_NMI_SAFE_CMPXCHG
bool
 
--- a/include/asm-generic/tlb.h
+++ b/include/asm-generic/tlb.h
@@ -184,6 +184,7 @@ extern void tlb_remove_table(struct mmu_
 
 #endif
 
+#ifndef CONFIG_HAVE_MMU_GATHER_NO_GATHER
 /*
  * If we can't allocate a page to make a big batch of page pointers
  * to work on, then just handle a few from the on-stack structure.
@@ -208,6 +209,10 @@ struct mmu_gather_batch {
  */
 #define MAX_GATHER_BATCH_COUNT (1UL/MAX_GATHER_BATCH)
 
+extern bool __tlb_remove_page_size(struct mmu_gather *tlb, struct page *page,
+  int page_size);
+#endif
+
 /*
  * struct mmu_gather is an opaque type used by the mm code for passing around
  * any data needed by arch specific code for tlb_remove_page.
@@ -254,6 +259,7 @@ struct mmu_gather {
 
unsigned intbatch_count;
 
+#ifndef CONFIG_HAVE_MMU_GATHER_NO_GATHER
struct mmu_gather_batch *active;
struct mmu_gather_batch local;
struct page *__pages[MMU_GATHER_BUNDLE];
@@ -261,6 +267,7 @@ struct mmu_gather {
 #ifdef CONFIG_HAVE_MMU_GATHER_PAGE_SIZE
unsigned int page_size;
 #endif
+#endif
 };
 
 void arch_tlb_gather_mmu(struct mmu_gather *tlb,
@@ -269,8 +276,6 @@ void tlb_flush_mmu(struct mmu_gather *tl
 void arch_tlb_finish_mmu(struct mmu_gather *tlb,
 unsigned long start, unsigned long end, bool force);
 void tlb_flush_mmu_free(struct mmu_gather *tlb);
-extern bool __tlb_remove_page_size(struct mmu_gather *tlb, struct page *page,
-  int page_size);
 
 static inline void __tlb_adjust_range(struct mmu_gather *tlb,
  unsigned long address,
--- a/mm/mmu_gather.c
+++ b/mm/mmu_gather.c
@@ -13,6 +13,8 @@
 
 #ifdef HAVE_GENERIC_MMU_GATHER
 
+#ifndef CONFIG_HAVE_MMU_GATHER_NO_GATHER
+
 static bool tlb_next_batch(struct mmu_gather *tlb)
 {
struct mmu_gather_batch *batch;
@@ -41,6 +43,56 @@ static bool tlb_next_batch(struct mmu_ga
return true;
 }
 
+static void tlb_batch_pages_flush(struct mmu_gather *tlb)
+{
+   struct mmu_gather_batch *batch;
+
+   for (batch = >local; batch && batch->nr; batch = batch->next) {
+   free_pages_and_swap_cache(batch->pages, batch->nr);
+   batch->nr = 0;
+   }
+   tlb->active = >local;
+}
+
+static void tlb_batch_list_free(struct mmu_gather *tlb)
+{
+   struct mmu_gather_batch *batch, *next;
+
+   for (batch = tlb->local.next; batch; batch = next) {
+   next = batch->next;
+   free_pages((unsigned long)batch, 0);
+   }
+   tlb->local.next = NULL;
+}
+
+bool __tlb_remove_page_size(struct mmu_gather *tlb, struct page *page, int 
page_size)
+{
+   struct mmu_gather_batch *batch;
+
+   VM_BUG_ON(!tlb->end);
+
+#ifdef CONFIG_HAVE_MMU_GATHER_PAGE_SIZE
+   VM_WARN_ON(tlb->page_size != page_size);
+#endif
+
+   batch = tlb->active;
+   /*
+* Add the page and check if we are full. If so
+* force a flush.
+*/
+   batch->pages[batch->nr++] = page;
+   if (batch->nr == batch->max) {
+   if (!tlb_next_batch(tlb))
+   return true;
+   batch = tlb->active;
+   }
+   VM_BUG_ON_PAGE(batch->nr > batch->max, page);
+
+   return false;
+}
+
+#endif /* HAVE_MMU_GATHER_NO_GATHER */
+
 void arch_tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm,
unsigned long start, unsigned long end)
 {
@@ -48,12 +100,15 @@ void arch_tlb_gather_mmu(struct mmu_gath
 
/* Is it from 0 to ~0? */
tlb->fullmm = !(start | (end+1));
+
+#ifndef CONFIG_HAVE_MMU_GATHER_NO_GATHER
tlb->need_flush_all = 0;
tlb->local.next = NULL;
tlb->local.nr   = 0;
tlb->local.max  = ARRAY_SIZE(tlb->__pages);
tlb->active = >local;