diff options
-rw-r--r-- | include/asm-generic/tlb.h | 9 | ||||
-rw-r--r-- | mm/memory.c | 5 |
2 files changed, 14 insertions, 0 deletions
diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h index ed6642ad03e0..25f01d0bc149 100644 --- a/include/asm-generic/tlb.h +++ b/include/asm-generic/tlb.h | |||
@@ -78,6 +78,14 @@ struct mmu_gather_batch { | |||
78 | #define MAX_GATHER_BATCH \ | 78 | #define MAX_GATHER_BATCH \ |
79 | ((PAGE_SIZE - sizeof(struct mmu_gather_batch)) / sizeof(void *)) | 79 | ((PAGE_SIZE - sizeof(struct mmu_gather_batch)) / sizeof(void *)) |
80 | 80 | ||
81 | /* | ||
82 | * Limit the maximum number of mmu_gather batches to reduce a risk of soft | ||
83 | * lockups for non-preemptible kernels on huge machines when a lot of memory | ||
84 | * is zapped during unmapping. | ||
85 | * 10K pages freed at once should be safe even without a preemption point. | ||
86 | */ | ||
87 | #define MAX_GATHER_BATCH_COUNT (10000UL/MAX_GATHER_BATCH) | ||
88 | |||
81 | /* struct mmu_gather is an opaque type used by the mm code for passing around | 89 | /* struct mmu_gather is an opaque type used by the mm code for passing around |
82 | * any data needed by arch specific code for tlb_remove_page. | 90 | * any data needed by arch specific code for tlb_remove_page. |
83 | */ | 91 | */ |
@@ -96,6 +104,7 @@ struct mmu_gather { | |||
96 | struct mmu_gather_batch *active; | 104 | struct mmu_gather_batch *active; |
97 | struct mmu_gather_batch local; | 105 | struct mmu_gather_batch local; |
98 | struct page *__pages[MMU_GATHER_BUNDLE]; | 106 | struct page *__pages[MMU_GATHER_BUNDLE]; |
107 | unsigned int batch_count; | ||
99 | }; | 108 | }; |
100 | 109 | ||
101 | #define HAVE_GENERIC_MMU_GATHER | 110 | #define HAVE_GENERIC_MMU_GATHER |
diff --git a/mm/memory.c b/mm/memory.c index e0a9b0ce4f10..49fb1cf08611 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -184,10 +184,14 @@ static int tlb_next_batch(struct mmu_gather *tlb) | |||
184 | return 1; | 184 | return 1; |
185 | } | 185 | } |
186 | 186 | ||
187 | if (tlb->batch_count == MAX_GATHER_BATCH_COUNT) | ||
188 | return 0; | ||
189 | |||
187 | batch = (void *)__get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0); | 190 | batch = (void *)__get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0); |
188 | if (!batch) | 191 | if (!batch) |
189 | return 0; | 192 | return 0; |
190 | 193 | ||
194 | tlb->batch_count++; | ||
191 | batch->next = NULL; | 195 | batch->next = NULL; |
192 | batch->nr = 0; | 196 | batch->nr = 0; |
193 | batch->max = MAX_GATHER_BATCH; | 197 | batch->max = MAX_GATHER_BATCH; |
@@ -216,6 +220,7 @@ void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, bool fullmm) | |||
216 | tlb->local.nr = 0; | 220 | tlb->local.nr = 0; |
217 | tlb->local.max = ARRAY_SIZE(tlb->__pages); | 221 | tlb->local.max = ARRAY_SIZE(tlb->__pages); |
218 | tlb->active = &tlb->local; | 222 | tlb->active = &tlb->local; |
223 | tlb->batch_count = 0; | ||
219 | 224 | ||
220 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE | 225 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE |
221 | tlb->batch = NULL; | 226 | tlb->batch = NULL; |