From: Peter Zijlstra <hidden> Date: 2010-08-28 14:28:29
This patch-set makes part of the mm a lot more preemptible. It converts
i_mmap_lock and anon_vma->lock to mutexes and makes mmu_gather fully
preemptible.
The main motivation was making mm_take_all_locks() preemptible, since it
appears people are nesting hundreds of spinlocks there.
The side-effects are that can finally make mmu_gather preemptible,
something which lots of people have wanted to do for a long time.
It also gets us anon_vma refcounting, which seems to result in a nice
cleanup of the anon_vma lifetime rules wrt KSM and compaction.
This patch-set it build and boot-tested on x86_64 (a previous version was
also tested on Dave's Niagra2 machines, and I suppose s390 did too when
Martin provided the conversion patch for his arch).
There are no known architectures left unconverted, although some arch code
never did see a compiler (superh and ia64 come to mind, I'll try and
update my toolchains next week).
Yanmin ran the last posting through the comprehensive Intel test farm
and didn't find any regressions.
( Not included in this posting are the 4 Sparc64 patches that implement
gup_fast, those can be applied separately after this series gets
anywhere. )
Full series (including the Sparc64 gup_fast bits) also available in -git
form from (against Linus' tree as of about an hour ago):
git://git.kernel.org/pub/scm/linux/kernel/git/peterz/linux-2.6-mmu_preempt.git mmu_preempt
Do people feel its ready to get added to -next?
From: Peter Zijlstra <hidden> Date: 2010-08-28 14:27:43
In case other architectures require RCU freed page-tables to implement
gup_fast() and software filled hashes and similar things, provide the
means to do so by moving the logic into generic code.
Requested-by: David Miller [off-list ref]
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Peter Zijlstra <redacted>
---
arch/powerpc/include/asm/pgalloc.h | 23 +++++++-
arch/powerpc/include/asm/tlb.h | 10 ---
arch/powerpc/mm/pgtable.c | 98 -------------------------------------
arch/powerpc/mm/tlb_hash32.c | 3 -
arch/powerpc/mm/tlb_hash64.c | 3 -
arch/powerpc/mm/tlb_nohash.c | 3 -
include/asm-generic/tlb.h | 57 +++++++++++++++++++--
mm/memory.c | 77 +++++++++++++++++++++++++++++
8 files changed, 149 insertions(+), 125 deletions(-)
Index: linux-2.6/arch/powerpc/include/asm/pgalloc.h
===================================================================
@@ -33,104 +33,6 @@#include"mmu_decl.h"-#ifdef CONFIG_SMP--/*-*HandlebatchingofpagetablefreeingonSMP.Pagetablesare-*queuedupandsendtobefreedlaterbyRCUinordertoavoid-*freeingapagetablepagethatisbeingwalkedwithoutlocks-*/--staticunsignedlongpte_freelist_forced_free;--structpte_freelist_batch-{-structrcu_headrcu;-unsignedintindex;-unsignedlongtables[0];-};--#define PTE_FREELIST_SIZE \-((PAGE_SIZE-sizeof(structpte_freelist_batch))\-/sizeof(unsignedlong))--staticvoidpte_free_smp_sync(void*arg)-{-/* Do nothing, just ensure we sync with all CPUs */-}--/* This is only called when we are critically out of memory-*(andfailtogetapageinpte_free_tlb).-*/-staticvoidpgtable_free_now(void*table,unsignedshift)-{-pte_freelist_forced_free++;--smp_call_function(pte_free_smp_sync,NULL,1);--pgtable_free(table,shift);-}--staticvoidpte_free_rcu_callback(structrcu_head*head)-{-structpte_freelist_batch*batch=-container_of(head,structpte_freelist_batch,rcu);-unsignedinti;--for(i=0;i<batch->index;i++){-void*table=(void*)(batch->tables[i]&~MAX_PGTABLE_INDEX_SIZE);-unsignedshift=batch->tables[i]&MAX_PGTABLE_INDEX_SIZE;--pgtable_free(table,shift);-}--free_page((unsignedlong)batch);-}--staticvoidpte_free_submit(structpte_freelist_batch*batch)-{-call_rcu_sched(&batch->rcu,pte_free_rcu_callback);-}--voidpgtable_free_tlb(structmmu_gather*tlb,void*table,unsignedshift)-{-structpte_freelist_batch**batchp=&tlb->arch.batch;-unsignedlongpgf;--if(atomic_read(&tlb->mm->mm_users)<2){-pgtable_free(table,shift);-return;-}--if(*batchp==NULL){-*batchp=(structpte_freelist_batch*)__get_free_page(GFP_ATOMIC);-if(*batchp==NULL){-pgtable_free_now(table,shift);-return;-}-(*batchp)->index=0;-}-BUG_ON(shift>MAX_PGTABLE_INDEX_SIZE);-pgf=(unsignedlong)table|shift;-(*batchp)->tables[(*batchp)->index++]=pgf;-if((*batchp)->index==PTE_FREELIST_SIZE){-pte_free_submit(*batchp);-*batchp=NULL;-}-}--voidpte_free_finish(structmmu_gather*tlb)-{-structpte_freelist_batch**batchp=&tlb->arch.batch;--if(*batchp==NULL)-return;-pte_free_submit(*batchp);-*batchp=NULL;-}--#endif /* CONFIG_SMP */-staticinlineintis_exec_fault(void){returncurrent->thread.regs&&TRAP(current->thread.regs)==0x400;
@@ -27,6 +27,49 @@#define tlb_fast_mode(tlb) 1#endif+#ifdef HAVE_ARCH_RCU_TABLE_FREE+/*+*SemiRCUfreeingofthepagedirectories.+*+*Thisisneededbysomearchitecturestoimplementsoftwarepagetablewalkers.+*+*gup_fast()andothersoftwarepagetablewalkersdoalocklesspage-table+*walkandthereforeneedssomesynchronizationwiththefreeingofthepage+*directories.ThechosenmeanstoaccomplishthatisbydisablingIRQsover+*thewalk.+*+*ArchitecturesthatuseIPIstoflushTLBswillthenautomagicallyDTRT,+*sinceweunlinkthepage,flushTLBs,freethepage.Sincethedisablingof+*IRQsdelaysthecopmletionoftheTLBflushwecanneverobserveanalready+*freedpage.+*+*Architecturesthatdonothavethis(PPC)needtodelaythefreeingbysome+*othermeans,thisisthatmeans.+*+*Whatwedoisbatchthefreeddirectorypages(tables)andRCUfreethem.+*WeusetheschedRCUvariant,asthatguaranteesthatIRQ/preemptdisabling+*holdsoffgraceperiods.+*+*However,inordertobatchthesepagesweneedtoallocatestorage,this+*allocationisdeepinsidetheMMcodeandcanthuseasilyfailonmemory+*pressure.Toguaranteeprogresswefallbacktosingletablefreeing,see+*theimplementationoftlb_remove_table_one().+*+*/+structmmu_table_batch{+structrcu_headrcu;+unsignedintnr;+void*tables[0];+};++#define MAX_TABLE_BATCH \+((PAGE_SIZE-sizeof(structmmu_table_batch))/sizeof(void*))++externvoidtlb_table_flush(structmmu_gather*tlb);+externvoidtlb_remove_table(structmmu_gather*tlb,void*table);++#endif+/* struct mmu_gather is an opaque type used by the mm code for passing around*anydataneededbyarchspecificcodefortlb_remove_page.*/
@@ -36,11 +79,12 @@ struct mmu_gather {unsignedintmax;/* nr < max */unsignedintneed_flush;/* Really unmapped some ptes? */unsignedintfullmm;/* non-zero means full mm flush */-#ifdef HAVE_ARCH_MMU_GATHER-structarch_mmu_gatherarch;-#endifstructpage**pages;structpage*local[8];++#ifdef HAVE_ARCH_RCU_TABLE_FREE+structmmu_table_batch*batch;+#endif};staticinlinevoid__tlb_alloc_pages(structmmu_gather*tlb)
@@ -683,7 +683,7 @@ rcu_unlock:/* Drop an anon_vma reference if we took one */if(anon_vma)-drop_anon_vma(anon_vma);+put_anon_vma(anon_vma);if(rcu_locked)rcu_read_unlock();
@@ -274,7 +274,7 @@ static void anon_vma_unlink(struct anon_if(empty){/* We no longer need the root anon_vma */if(anon_vma->root!=anon_vma)-drop_anon_vma(anon_vma->root);+put_anon_vma(anon_vma->root);anon_vma_free(anon_vma);}}
@@ -1448,7 +1448,7 @@ int try_to_munlock(struct page *page)*weknowwearethelastuser,nobodyelsecangetareferenceandwe*candothefreeingwithoutthelock.*/-voiddrop_anon_vma(structanon_vma*anon_vma)+voidput_anon_vma(structanon_vma*anon_vma){BUG_ON(atomic_read(&anon_vma->external_refcount)<=0);if(atomic_dec_and_lock(&anon_vma->external_refcount,&anon_vma->root->lock)){
From: Peter Zijlstra <hidden> Date: 2010-08-28 14:28:08
PowerPC relies on IRQ-disable to guard against RCU quiecent states,
use the appropriate RCU call version.
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Nick Piggin <redacted>
Cc: Paul E. McKenney <redacted>
Signed-off-by: Peter Zijlstra <redacted>
---
arch/powerpc/mm/pgtable.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Index: linux-2.6/arch/powerpc/mm/pgtable.c
===================================================================
From: Peter Zijlstra <hidden> Date: 2010-08-28 14:28:10
Fix up the um mmu_gather code to conform to the new API.
Cc: Jeff Dike <redacted>
Signed-off-by: Peter Zijlstra <redacted>
---
arch/um/include/asm/tlb.h | 16 ++--------------
1 file changed, 2 insertions(+), 14 deletions(-)
Index: linux-2.6/arch/um/include/asm/tlb.h
===================================================================
@@ -22,9 +22,6 @@ struct mmu_gather {unsignedintfullmm;/* non-zero means full mm flush */};-/* Users of the generic TLB shootdown code must declare this storage space. */-DECLARE_PER_CPU(structmmu_gather,mmu_gathers);-staticinlinevoid__tlb_remove_tlb_entry(structmmu_gather*tlb,pte_t*ptep,unsignedlongaddress){
From: Peter Zijlstra <hidden> Date: 2010-08-28 14:28:12
Fix up powerpc to the new mmu_gather stuffs.
PPC has an extra batching queue to RCU free the actual pagetable
allocations, use the ARCH extentions for that for now.
For the ppc64_tlb_batch, which tracks the vaddrs to unhash from the
hardware hash-table, keep using per-cpu arrays but flush on context
switch and use a TLF bit to track the laxy_mmu state.
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Peter Zijlstra <redacted>
---
arch/powerpc/include/asm/pgalloc.h | 4 ++--
arch/powerpc/include/asm/thread_info.h | 2 ++
arch/powerpc/include/asm/tlb.h | 10 ++++++++++
arch/powerpc/kernel/process.c | 19 +++++++++++++++++++
arch/powerpc/mm/pgtable.c | 14 ++++----------
arch/powerpc/mm/tlb_hash32.c | 2 +-
arch/powerpc/mm/tlb_hash64.c | 12 +++++++-----
arch/powerpc/mm/tlb_nohash.c | 2 +-
8 files changed, 46 insertions(+), 19 deletions(-)
Index: linux-2.6/arch/powerpc/include/asm/tlb.h
===================================================================
@@ -97,12 +94,10 @@ static void pte_free_submit(struct pte_fvoidpgtable_free_tlb(structmmu_gather*tlb,void*table,unsignedshift){-/* This is safe since tlb_gather_mmu has disabled preemption */-structpte_freelist_batch**batchp=&__get_cpu_var(pte_freelist_cur);+structpte_freelist_batch**batchp=&tlb->arch.batch;unsignedlongpgf;-if(atomic_read(&tlb->mm->mm_users)<2||-cpumask_equal(mm_cpumask(tlb->mm),cpumask_of(smp_processor_id()))){+if(atomic_read(&tlb->mm->mm_users)<2){pgtable_free(table,shift);return;}
@@ -124,10 +119,9 @@ void pgtable_free_tlb(struct mmu_gather }}-voidpte_free_finish(void)+voidpte_free_finish(structmmu_gather*tlb){-/* This is safe since tlb_gather_mmu has disabled preemption */-structpte_freelist_batch**batchp=&__get_cpu_var(pte_freelist_cur);+structpte_freelist_batch**batchp=&tlb->arch.batch;if(*batchp==NULL)return;
@@ -155,7 +155,7 @@ void __flush_tlb_pending(struct ppc64_tlvoidtlb_flush(structmmu_gather*tlb){-structppc64_tlb_batch*tlbbatch=&__get_cpu_var(ppc64_tlb_batch);+structppc64_tlb_batch*tlbbatch=&get_cpu_var(ppc64_tlb_batch);/* If there's a TLB batch pending, then we must flush it because the*pagesaregoingtobefreedandwereallydon'twanttohaveaCPU
@@ -164,8 +164,10 @@ void tlb_flush(struct mmu_gather *tlb)if(tlbbatch->index)__flush_tlb_pending(tlbbatch);+put_cpu_var(ppc64_tlb_batch);+/* Push out batch of freed page tables */-pte_free_finish();+pte_free_finish(tlb);}/**
@@ -28,44 +28,50 @@#include<asm/smp.h>#include<asm/tlbflush.h>-#ifndef CONFIG_SMP-#define TLB_NR_PTRS 1-#else-#define TLB_NR_PTRS 508-#endif-structmmu_gather{structmm_struct*mm;unsignedintfullmm;unsignedintnr_ptes;unsignedintnr_pxds;-void*array[TLB_NR_PTRS];+unsignedintmax;+void**array;+void*local[8];};-DECLARE_PER_CPU(structmmu_gather,mmu_gathers);--staticinlinestructmmu_gather*tlb_gather_mmu(structmm_struct*mm,-unsignedintfull_mm_flush)+staticinlinevoid__tlb_alloc_pages(structmmu_gather*tlb){-structmmu_gather*tlb=&get_cpu_var(mmu_gathers);+unsignedlongaddr=__get_free_pages(GFP_ATOMIC,0);++if(addr){+tlb->array=(void*)addr;+tlb->max=PAGE_SIZE/sizeof(void*);+}+}+staticinlinevoidtlb_gather_mmu(structmmu_gather*tlb,+structmm_struct*mm,+unsignedintfull_mm_flush)+{tlb->mm=mm;+tlb->max=ARRAY_SIZE(tlb->local);+tlb->array=tlb->local;tlb->fullmm=full_mm_flush;-tlb->nr_ptes=0;-tlb->nr_pxds=TLB_NR_PTRS;if(tlb->fullmm)__tlb_flush_mm(mm);-returntlb;+else+__tlb_alloc_pages(tlb);+tlb->nr_ptes=0;+tlb->nr_pxds=tlb->max;}staticinlinevoidtlb_flush_mmu(structmmu_gather*tlb,unsignedlongstart,unsignedlongend){-if(!tlb->fullmm&&(tlb->nr_ptes>0||tlb->nr_pxds<TLB_NR_PTRS))+if(!tlb->fullmm&&(tlb->nr_ptes>0||tlb->nr_pxds<tlb->max))__tlb_flush_mm(tlb->mm);while(tlb->nr_ptes>0)pte_free(tlb->mm,tlb->array[--tlb->nr_ptes]);-while(tlb->nr_pxds<TLB_NR_PTRS)+while(tlb->nr_pxds<tlb->max)/* pgd_free frees the pointer as region or segment table */pgd_free(tlb->mm,tlb->array[tlb->nr_pxds++]);}
@@ -78,7 +84,8 @@ static inline void tlb_finish_mmu(struct/* keep the page table cache within bounds */check_pgt_cache();-put_cpu_var(mmu_gathers);+if(tlb->array!=tlb->local)+free_pages((unsignedlong)tlb->array,0);}/*
From: Peter Zijlstra <hidden> Date: 2010-08-28 14:28:16
Fix up the ia64 mmu_gather code to conform to the new API.
Cc: Tony Luck <tony.luck@intel.com>
Signed-off-by: Peter Zijlstra <redacted>
---
arch/ia64/include/asm/tlb.h | 38 +++++++++++++++++++++++++-------------
1 file changed, 25 insertions(+), 13 deletions(-)
Index: linux-2.6/arch/ia64/include/asm/tlb.h
===================================================================
From: Peter Zijlstra <hidden> Date: 2010-08-28 14:28:18
Optimize the page_lock_anon_vma() fast path to be one LOCKed op,
instead of two.
Signed-off-by: Peter Zijlstra <redacted>
---
mm/rmap.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 61 insertions(+), 4 deletions(-)
Index: linux-2.6/mm/rmap.c
===================================================================
@@ -353,20 +353,69 @@ out:returnanon_vma;}+/*+*Similartopage_get_anon_vma()exceptitlockstheanon_vma.+*+*Itsalittlemorecomplexasittriestokeepthefastpathtoasingle+*atomicop--thetrylock.Ifwefailthetrylock,wefallbacktogettinga+*referencelikewithpage_get_anon_vma()andthenblockonthemutex.+*/structanon_vma*page_lock_anon_vma(structpage*page){-structanon_vma*anon_vma=page_get_anon_vma(page);+structanon_vma*anon_vma=NULL;+unsignedlonganon_mapping;++rcu_read_lock();+anon_mapping=(unsignedlong)ACCESS_ONCE(page->mapping);+if((anon_mapping&PAGE_MAPPING_FLAGS)!=PAGE_MAPPING_ANON)+gotoout;+if(!page_mapped(page))+gotoout;++anon_vma=(structanon_vma*)(anon_mapping-PAGE_MAPPING_ANON);+if(mutex_trylock(&anon_vma->root->lock)){+/*+*Ifweobservea!0refcount,thenholdingthelockensures+*theanon_vmawillnotgoaway,see__put_anon_vma().+*/+if(!atomic_read(&anon_vma->refcount)){+anon_vma_unlock(anon_vma);+anon_vma=NULL;+}+gotoout;+}++/* trylock failed, we got to sleep */+if(!atomic_inc_not_zero(&anon_vma->refcount)){+anon_vma=NULL;+gotoout;+}++/* we pinned the anon_vma, its safe to sleep */+rcu_read_unlock();+anon_vma_lock(anon_vma);++if(atomic_dec_and_test(&anon_vma->refcount)){+/*+*Oops,weheldthelastrefcount,releasethelock+*andbail--can'tsimplyuseput_anon_vma()because+*we'lldeadlockontheanon_vma_lock()recursion.+*/+anon_vma_unlock(anon_vma);+__put_anon_vma(anon_vma);+anon_vma=NULL;+}-if(anon_vma)-anon_vma_lock(anon_vma);+returnanon_vma;+out:+rcu_read_unlock();returnanon_vma;}voidpage_unlock_anon_vma(structanon_vma*anon_vma){anon_vma_unlock(anon_vma);-put_anon_vma(anon_vma);}/*
@@ -1458,6 +1507,14 @@ int try_to_munlock(struct page *page)void__put_anon_vma(structanon_vma*anon_vma){+/*+*Synchronizeagainstpage_lock_anon_vma()suchthat+*wecansafelyholdthelockwithouttheanon_vmagetting+*freed.+*/+anon_vma_lock(anon_vma);+anon_vma_unlock(anon_vma);+if(anon_vma->root!=anon_vma)put_anon_vma(anon_vma->root);anon_vma_free(anon_vma);
From: Peter Zijlstra <hidden> Date: 2010-08-28 14:28:19
A slightly more verbose comment to go along with the trickery in
page_lock_anon_vma().
Reviewed-by: KOSAKI Motohiro <redacted>
Signed-off-by: Peter Zijlstra <redacted>
Acked-by: Mel Gorman <redacted>
LKML-Reference: <1271158226.4807.1107.camel@twins>
---
mm/rmap.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
Index: linux-2.6/mm/rmap.c
===================================================================
From: Peter Zijlstra <hidden> Date: 2010-08-28 14:28:21
Make mmu_gather preemptible by using a small on stack list and use
an option allocation to speed things up.
Preemptible mmu_gather is desired in general and usable once
i_mmap_lock becomes a mutex. Doing it before the mutex conversion
saves us from having to rework the code by moving the mmu_gather
bits inside the i_mmap_lock.
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: David Miller <davem@davemloft.net>
Cc: Martin Schwidefsky <redacted>
Cc: Russell King <redacted>
Cc: Paul Mundt <redacted>
Cc: Jeff Dike <redacted>
Cc: Tony Luck <tony.luck@intel.com>
Signed-off-by: Peter Zijlstra <redacted>
---
fs/exec.c | 10 ++++-----
include/asm-generic/tlb.h | 51 +++++++++++++++++++++++++++++-----------------
include/linux/mm.h | 2 -
mm/memory.c | 27 +++++-------------------
mm/mmap.c | 16 +++++++-------
5 files changed, 53 insertions(+), 53 deletions(-)
Index: linux-2.6/fs/exec.c
===================================================================
@@ -39,30 +33,48 @@structmmu_gather{structmm_struct*mm;unsignedintnr;/* set to ~0U means fast mode */+unsignedintmax;/* nr < max */unsignedintneed_flush;/* Really unmapped some ptes? */unsignedintfullmm;/* non-zero means full mm flush */-structpage*pages[FREE_PTE_NR];+#ifdef HAVE_ARCH_MMU_GATHER+structarch_mmu_gatherarch;+#endif+structpage**pages;+structpage*local[8];};-/* Users of the generic TLB shootdown code must declare this storage space. */-DECLARE_PER_CPU(structmmu_gather,mmu_gathers);+staticinlinevoid__tlb_alloc_pages(structmmu_gather*tlb)+{+unsignedlongaddr=__get_free_pages(GFP_ATOMIC,0);++if(addr){+tlb->pages=(void*)addr;+tlb->max=PAGE_SIZE/sizeof(structpage*);+}+}/* tlb_gather_mmu*Returnapointertoaninitializedstructmmu_gather.*/-staticinlinestructmmu_gather*-tlb_gather_mmu(structmm_struct*mm,unsignedintfull_mm_flush)+staticinlinevoid+tlb_gather_mmu(structmmu_gather*tlb,structmm_struct*mm,unsignedintfull_mm_flush){-structmmu_gather*tlb=&get_cpu_var(mmu_gathers);-tlb->mm=mm;-/* Use fast mode if only one CPU is online */-tlb->nr=num_online_cpus()>1?0U:~0U;+tlb->max=ARRAY_SIZE(tlb->local);+tlb->pages=tlb->local;++if(num_online_cpus()>1){+tlb->nr=0;+__tlb_alloc_pages(tlb);+}else/* Use fast mode if only one CPU is online */+tlb->nr=~0U;tlb->fullmm=full_mm_flush;-returntlb;+#ifdef HAVE_ARCH_MMU_GATHER+tlb->arch=ARCH_MMU_GATHER_INIT;+#endif}staticinlinevoid
@@ -2247,7 +2247,7 @@ EXPORT_SYMBOL(do_brk);/* Release all mmaps. */voidexit_mmap(structmm_struct*mm){-structmmu_gather*tlb;+structmmu_gathertlb;structvm_area_struct*vma;unsignedlongnr_accounted=0;unsignedlongend;
@@ -2272,14 +2272,14 @@ void exit_mmap(struct mm_struct *mm)lru_add_drain();flush_cache_mm(mm);-tlb=tlb_gather_mmu(mm,1);+tlb_gather_mmu(&tlb,mm,1);/* update_hiwater_rss(mm) here? but nobody should be looking *//* Use -1 here to ensure all VMAs in the mm are unmapped */end=unmap_vmas(&tlb,vma,0,-1,&nr_accounted,NULL);vm_unacct_memory(nr_accounted);-free_pgtables(tlb,vma,FIRST_USER_ADDRESS,0);-tlb_finish_mmu(tlb,0,end);+free_pgtables(&tlb,vma,FIRST_USER_ADDRESS,0);+tlb_finish_mmu(&tlb,0,end);/**Walkthelistagain,actuallyclosingandfreeingit,
From: Peter Zijlstra <hidden> Date: 2010-08-28 14:28:22
Instead of using a single batch (the small on-stack, or an allocated
page), try and extend the batch every time it runs out and only flush
once either the extend fails or we're done.
Requested-by: Nick Piggin [off-list ref]
Signed-off-by: Peter Zijlstra <redacted>
---
include/asm-generic/tlb.h | 122 ++++++++++++++++++++++++++++++----------------
1 file changed, 82 insertions(+), 40 deletions(-)
Index: linux-2.6/include/asm-generic/tlb.h
===================================================================
@@ -70,31 +60,66 @@ extern void tlb_remove_table(struct mmu_#endif+structmmu_gather_batch{+structmmu_gather_batch*next;+unsignedintnr;+unsignedintmax;+structpage*pages[0];+};++#define MAX_GATHER_BATCH \+((PAGE_SIZE-sizeof(structmmu_gather_batch))/sizeof(void*))+/* struct mmu_gather is an opaque type used by the mm code for passing around*anydataneededbyarchspecificcodefortlb_remove_page.*/structmmu_gather{structmm_struct*mm;-unsignedintnr;/* set to ~0U means fast mode */-unsignedintmax;/* nr < max */-unsignedintneed_flush;/* Really unmapped some ptes? */-unsignedintfullmm;/* non-zero means full mm flush */-structpage**pages;-structpage*local[8];+unsignedintneed_flush:1,/* Did free PTEs */+fast_mode:1;/* No batching */+unsignedintfullmm;/* Flush full mm */++structmmu_gather_batch*active;+structmmu_gather_batchlocal;+structpage*__pages[8];#ifdef HAVE_ARCH_RCU_TABLE_FREEstructmmu_table_batch*batch;#endif};-staticinlinevoid__tlb_alloc_pages(structmmu_gather*tlb)+/*+*ForUPwedon'tneedtoworryaboutTLBflush+*andpagefreeordersomuch..+*/+#ifdef CONFIG_SMP+#define tlb_fast_mode(tlb) (tlb->fast_mode)+#else+#define tlb_fast_mode(tlb) 1+#endif++staticinlineinttlb_next_batch(structmmu_gather*tlb){-unsignedlongaddr=__get_free_pages(GFP_ATOMIC,0);+structmmu_gather_batch*batch;-if(addr){-tlb->pages=(void*)addr;-tlb->max=PAGE_SIZE/sizeof(structpage*);+batch=tlb->active;+if(batch->next){+tlb->active=batch->next;+return1;}++batch=(void*)__get_free_pages(GFP_ATOMIC,0);+if(!batch)+return0;++batch->next=NULL;+batch->nr=0;+batch->max=MAX_GATHER_BATCH;++tlb->active->next=batch;+tlb->active=batch;++return1;}/* tlb_gather_mmu
@@ -105,17 +130,16 @@ tlb_gather_mmu(struct mmu_gather *tlb, s{tlb->mm=mm;-tlb->max=ARRAY_SIZE(tlb->local);-tlb->pages=tlb->local;--if(num_online_cpus()>1){-tlb->nr=0;-__tlb_alloc_pages(tlb);-}else/* Use fast mode if only one CPU is online */-tlb->nr=~0U;-+tlb->need_flush=0;+if(num_online_cpus()==1)+tlb->fast_mode=1;tlb->fullmm=full_mm_flush;+tlb->local.next=NULL;+tlb->local.nr=0;+tlb->local.max=ARRAY_SIZE(tlb->__pages);+tlb->active=&tlb->local;+#ifdef HAVE_ARCH_RCU_TABLE_FREEtlb->batch=NULL;#endif
From: Peter Zijlstra <hidden> Date: 2010-08-28 14:28:23
Rework the sparc mmu_gather usage to conform to the new world order :-)
Sparc mmu_gather does two things:
- tracks vaddrs to unhash
- tracks pages to free
Split these two things like powerpc has done and keep the vaddrs
in per-cpu data structures and flush them on context switch.
The remaining bits can then use the generic mmu_gather.
Cc: David Miller <davem@davemloft.net>
Signed-off-by: Peter Zijlstra <redacted>
---
arch/sparc/include/asm/pgalloc_64.h | 3 +
arch/sparc/include/asm/tlb_64.h | 91 ++---------------------------------
arch/sparc/include/asm/tlbflush_64.h | 12 +++-
arch/sparc/mm/tlb.c | 42 +++++++++-------
arch/sparc/mm/tsb.c | 15 +++--
5 files changed, 51 insertions(+), 112 deletions(-)
Index: linux-2.6/arch/sparc/include/asm/pgalloc_64.h
===================================================================
@@ -27,18 +27,15 @@structanon_vma{spinlock_tlock;/* Serialize access to vma list */structanon_vma*root;/* Root of this anon_vma tree */-#if defined(CONFIG_KSM) || defined(CONFIG_MIGRATION)-/*-*Theexternal_refcountistakenbyeitherKSMorpagemigration-*totakeareferencetoananon_vmawhenthereisno+*Therefcountistakenonananon_vmawhenthereisno*guaranteethatthevmaofpagetableswillexistfor*thedurationoftheoperation.Acallerthattakes*thereferenceisresponsibleforclearingupthe*anon_vmaiftheyarethelastuseronrelease*/-atomic_texternal_refcount;-#endif+atomic_trefcount;+/**NOTE:theLSBofthehead.nextissetby*mm_take_all_locks()_after_takingtheabovelock.Sothe
@@ -268,7 +268,7 @@ static void anon_vma_unlink(struct anon_list_del(&anon_vma_chain->same_anon_vma);/* We must garbage collect the anon_vma if it's empty */-empty=list_empty(&anon_vma->head)&&!anonvma_external_refcount(anon_vma);+empty=list_empty(&anon_vma->head)&&!atomic_read(&anon_vma->refcount);anon_vma_unlock(anon_vma);if(empty){
From: Peter Zijlstra <hidden> Date: 2010-08-28 14:28:30
This patch changes the anon_vma refcount to be 0 when the object is
free. It does this by adding 1 ref to being in use in the anon_vma
structure (iow. the anon_vma->head list is not empty).
This allows a simpler release scheme without having to check both the
refcount and the list as well as avoids taking a ref for each entry
on the list.
Signed-off-by: Peter Zijlstra <redacted>
---
include/linux/rmap.h | 11 +++++--
mm/ksm.c | 4 --
mm/rmap.c | 79 ++++++++++++++++++---------------------------------
3 files changed, 38 insertions(+), 56 deletions(-)
Index: linux-2.6/include/linux/rmap.h
===================================================================
@@ -133,11 +146,6 @@ int anon_vma_prepare(struct vm_area_struif(unlikely(!anon_vma))gotoout_enomem_free_avc;allocated=anon_vma;-/*-*ThisVMAhadnoanon_vmayet.Thisanon_vmais-*therootofanyanon_vmatreethatmightform.-*/-anon_vma->root=anon_vma;}anon_vma_lock(anon_vma);
@@ -156,7 +164,7 @@ int anon_vma_prepare(struct vm_area_struanon_vma_unlock(anon_vma);if(unlikely(allocated))-anon_vma_free(allocated);+put_anon_vma(allocated);if(unlikely(avc))anon_vma_chain_free(avc);}
@@ -237,9 +245,9 @@ int anon_vma_fork(struct vm_area_struct */anon_vma->root=pvma->anon_vma->root;/*-*WithKSMrefcounts,ananon_vmacanstayaroundlongerthanthe-*processitbelongsto.Therootanon_vmaneedstobepinned-*untilthisanon_vmaisfreed,becausethelocklivesintheroot.+*Withrefcounts,ananon_vmacanstayaroundlongerthanthe+*processitbelongsto.Therootanon_vmaneedstobepinneduntil+*thisanon_vmaisfreed,becausethelocklivesintheroot.*/get_anon_vma(anon_vma->root);/* Mark this anon_vma as the one where our new (COWed) pages go. */
@@ -249,7 +257,7 @@ int anon_vma_fork(struct vm_area_struct return0;out_error_free_anon_vma:-anon_vma_free(anon_vma);+put_anon_vma(anon_vma);out_error:unlink_anon_vmas(vma);return-ENOMEM;
@@ -268,15 +276,11 @@ static void anon_vma_unlink(struct anon_list_del(&anon_vma_chain->same_anon_vma);/* We must garbage collect the anon_vma if it's empty */-empty=list_empty(&anon_vma->head)&&!atomic_read(&anon_vma->refcount);+empty=list_empty(&anon_vma->head);anon_vma_unlock(anon_vma);-if(empty){-/* We no longer need the root anon_vma */-if(anon_vma->root!=anon_vma)-put_anon_vma(anon_vma->root);-anon_vma_free(anon_vma);-}+if(empty)+put_anon_vma(anon_vma);}voidunlink_anon_vmas(structvm_area_struct*vma)
@@ -1441,38 +1445,11 @@ int try_to_munlock(struct page *page)returntry_to_unmap_file(page,TTU_MUNLOCK);}-/*-*Dropananon_vmarefcount,freeingtheanon_vmaandanon_vma->root-*ifnecessary.Becarefultodoallthetestsunderthelock.Once-*weknowwearethelastuser,nobodyelsecangetareferenceandwe-*candothefreeingwithoutthelock.-*/-voidput_anon_vma(structanon_vma*anon_vma)-{-BUG_ON(atomic_read(&anon_vma->refcount)<=0);-if(atomic_dec_and_lock(&anon_vma->refcount,&anon_vma->root->lock)){-structanon_vma*root=anon_vma->root;-intempty=list_empty(&anon_vma->head);-intlast_root_user=0;-introot_empty=0;--/*-*Therefcountonanon-rootanon_vmagotdropped.Drop-*therefcountontherootandcheckifweneedtofreeit.-*/-if(empty&&anon_vma!=root){-BUG_ON(atomic_read(&root->refcount)<=0);-last_root_user=atomic_dec_and_test(&root->refcount);-root_empty=list_empty(&root->head);-}-anon_vma_unlock(anon_vma);--if(empty){-anon_vma_free(anon_vma);-if(root_empty&&last_root_user)-anon_vma_free(root);-}-}+void__put_anon_vma(structanon_vma*anon_vma)+{+if(anon_vma->root!=anon_vma)+put_anon_vma(anon_vma->root);+anon_vma_free(anon_vma);}#ifdef CONFIG_MIGRATION
From: Peter Zijlstra <hidden> Date: 2010-08-28 14:28:31
Convert page_lock_anon_vma() over to use refcounts. This is
done for each of convertion of anon_vma from spinlock to mutex.
Signed-off-by: Peter Zijlstra <redacted>
---
mm/rmap.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
Index: linux-2.6/mm/rmap.c
===================================================================
From: Peter Zijlstra <hidden> Date: 2010-08-28 14:28:33
Fix up the sh mmu_gahter code to conform to the new API.
Cc: Paul Mundt <redacted>
Signed-off-by: Peter Zijlstra <redacted>
---
arch/sh/include/asm/tlb.h | 12 ++----------
1 file changed, 2 insertions(+), 10 deletions(-)
Index: linux-2.6/arch/sh/include/asm/tlb.h
===================================================================
From: Peter Zijlstra <hidden> Date: 2010-08-28 14:28:35
Fix up the arm mmu_gahter code to conform to the new API.
Cc: Russell King <redacted>
Signed-off-by: Peter Zijlstra <redacted>
---
arch/arm/include/asm/tlb.h | 12 ++----------
1 file changed, 2 insertions(+), 10 deletions(-)
Index: linux-2.6/arch/arm/include/asm/tlb.h
===================================================================
@@ -626,7 +626,7 @@ struct address_space {unsignedinti_mmap_writable;/* count VM_SHARED mappings */structprio_tree_rooti_mmap;/* tree of private and shared mappings */structlist_headi_mmap_nonlinear;/*list VM_NONLINEAR mappings */-spinlock_ti_mmap_lock;/* protect tree, count, list */+structmutexi_mmap_lock;/* protect tree, count, list */unsignedinttruncate_count;/* Cover race condition with truncate */unsignedlongnrpages;/* number of total pages */pgoff_twriteback_index;/* writeback starts here */
@@ -25,7 +25,7 @@*pointingtothisanon_vmaonceitsvmalistisempty.*/structanon_vma{-spinlock_tlock;/* Serialize access to vma list */+structmutexlock;/* Serialize access to vma list */structanon_vma*root;/* Root of this anon_vma tree *//**Therefcountistakenonananon_vmawhenthereisno
@@ -369,7 +369,7 @@ static int dup_mmap(struct mm_struct *mmget_file(file);if(tmp->vm_flags&VM_DENYWRITE)atomic_dec(&inode->i_writecount);-spin_lock(&mapping->i_mmap_lock);+mutex_lock(&mapping->i_mmap_lock);if(tmp->vm_flags&VM_SHARED)mapping->i_mmap_writable++;tmp->vm_truncate_count=mpnt->vm_truncate_count;
@@ -377,7 +377,7 @@ static int dup_mmap(struct mm_struct *mm/* insert tmp into the share list, just after mpnt */vma_prio_tree_add(tmp,mpnt);flush_dcache_mmap_unlock(mapping);-spin_unlock(&mapping->i_mmap_lock);+mutex_unlock(&mapping->i_mmap_lock);}/*
@@ -2282,7 +2282,7 @@ static int unmap_ref_private(struct mm_s*thismappingshouldbesharedbetweenalltheVMAs,*__unmap_hugepage_range()iscalledasthelockisalreadyheld*/-spin_lock(&mapping->i_mmap_lock);+mutex_lock(&mapping->i_mmap_lock);vma_prio_tree_foreach(iter_vma,&iter,&mapping->i_mmap,pgoff,pgoff){/* Do not unmap the current VMA */if(iter_vma==vma)
@@ -2300,7 +2300,7 @@ static int unmap_ref_private(struct mm_saddress,address+huge_page_size(h),page);}-spin_unlock(&mapping->i_mmap_lock);+mutex_unlock(&mapping->i_mmap_lock);return1;}
@@ -1177,7 +1177,7 @@ unsigned long unmap_vmas(struct mmu_gath{longzap_work=ZAP_BLOCK_SIZE;unsignedlongstart=start_addr;-spinlock_t*i_mmap_lock=details?details->i_mmap_lock:NULL;+structmutex*i_mmap_lock=details?details->i_mmap_lock:NULL;structmm_struct*mm=vma->vm_mm;mmu_notifier_invalidate_range_start(mm,start_addr,end_addr);
@@ -1227,7 +1227,7 @@ unsigned long unmap_vmas(struct mmu_gath}if(need_resched()||-(i_mmap_lock&&spin_needbreak(i_mmap_lock))){+(i_mmap_lock&&mutex_is_contended(i_mmap_lock))){if(i_mmap_lock)gotoout;cond_resched();
@@ -2520,7 +2520,7 @@ again:restart_addr=zap_page_range(vma,start_addr,end_addr-start_addr,details);-need_break=need_resched()||spin_needbreak(details->i_mmap_lock);+need_break=need_resched()||mutex_is_contended(details->i_mmap_lock);if(restart_addr>=end_addr){/* We have now completed this vma: mark it so */
From: Peter Zijlstra <peterz@infradead.org> Date: 2010-08-28 14:32:38
Sorry folks, got Nick's old email in there (changed for this reply).
On Sat, 2010-08-28 at 16:16 +0200, Peter Zijlstra wrote:
This patch-set makes part of the mm a lot more preemptible. It converts
i_mmap_lock and anon_vma->lock to mutexes and makes mmu_gather fully
preemptible.
The main motivation was making mm_take_all_locks() preemptible, since it
appears people are nesting hundreds of spinlocks there.
The side-effects are that can finally make mmu_gather preemptible,
something which lots of people have wanted to do for a long time.
It also gets us anon_vma refcounting, which seems to result in a nice
cleanup of the anon_vma lifetime rules wrt KSM and compaction.
This patch-set it build and boot-tested on x86_64 (a previous version was
also tested on Dave's Niagra2 machines, and I suppose s390 did too when
Martin provided the conversion patch for his arch).
There are no known architectures left unconverted, although some arch code
never did see a compiler (superh and ia64 come to mind, I'll try and
update my toolchains next week).
Yanmin ran the last posting through the comprehensive Intel test farm
and didn't find any regressions.
( Not included in this posting are the 4 Sparc64 patches that implement
gup_fast, those can be applied separately after this series gets
anywhere. )
Full series (including the Sparc64 gup_fast bits) also available in -git
form from (against Linus' tree as of about an hour ago):
git://git.kernel.org/pub/scm/linux/kernel/git/peterz/linux-2.6-mmu_preempt.git mmu_preempt
Do people feel its ready to get added to -next?
From: Piotr Hosowicz <hidden> Date: 2010-08-28 14:58:30
On 28.08.2010 16:16, Peter Zijlstra wrote:
Full series (including the Sparc64 gup_fast bits) also available in -git
form from (against Linus' tree as of about an hour ago):
How come? I tried this:
aapi205:/usr/src/linus/tmp# git pull
Already up-to-date.
... and don't see an update. Maybe I don't do something right. If there is newer code I should receive it, am I correct? I use this link:
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
--
Janusz Korwin-Mikke:
"Generalnie rzecz biorąc, ja jestem w jednej dziedzinie za
równouprawnieniem, a mianowicie: żeby w małżeństwie było
50% mężczyzn i 50% kobiet."
NP: Peter Green Splinter Group - Turn Your Love Away
NB: 2.6.36-rc2-next-20100827
From: Peter Zijlstra <peterz@infradead.org> Date: 2010-08-28 15:10:56
On Sat, 2010-08-28 at 16:56 +0200, Piotr Hosowicz wrote:
On 28.08.2010 16:16, Peter Zijlstra wrote:
quoted
Full series (including the Sparc64 gup_fast bits) also available in -git
form from (against Linus' tree as of about an hour ago):
How come? I tried this:
aapi205:/usr/src/linus/tmp# git pull
Already up-to-date.
... and don't see an update. Maybe I don't do something right. If there
is newer code I should receive it, am I correct? I use this link:
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
That's Linus' tree, the patches aren't in there quite yet, try:
git remote add mmu_preempt git://git.kernel.org/pub/scm/linux/kernel/git/peterz/linux-2.6-mmu_preempt.git
git remote update
git checkout mmu_preempt/mmu_preempt
or
git checkout -b mmu_preempt origin/master
git pull git://git.kernel.org/pub/scm/linux/kernel/git/peterz/linux-2.6-mmu_preempt.git mmu_preempt
From: Pekka Enberg <penberg@kernel.org> Date: 2010-08-28 15:13:28
On Sat, Aug 28, 2010 at 5:16 PM, Peter Zijlstra [off-list ref] wrote:
This patch changes the anon_vma refcount to be 0 when the object is
free. It does this by adding 1 ref to being in use in the anon_vma
structure (iow. the anon_vma->head list is not empty).
This allows a simpler release scheme without having to check both the
refcount and the list as well as avoids taking a ref for each entry
on the list.
Signed-off-by: Peter Zijlstra <redacted>
From: Piotr Hosowicz <hidden> Date: 2010-08-28 15:18:56
On 28.08.2010 17:10, Peter Zijlstra wrote:
On Sat, 2010-08-28 at 16:56 +0200, Piotr Hosowicz wrote:
quoted
On 28.08.2010 16:16, Peter Zijlstra wrote:
quoted
Full series (including the Sparc64 gup_fast bits) also available in -git
form from (against Linus' tree as of about an hour ago):
How come? I tried this:
aapi205:/usr/src/linus/tmp# git pull
Already up-to-date.
... and don't see an update. Maybe I don't do something right. If there
is newer code I should receive it, am I correct? I use this link:
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
That's Linus' tree, the patches aren't in there quite yet, try:
git remote add mmu_preempt git://git.kernel.org/pub/scm/linux/kernel/git/peterz/linux-2.6-mmu_preempt.git
git remote update
git checkout mmu_preempt/mmu_preempt
or
git checkout -b mmu_preempt origin/master
git pull git://git.kernel.org/pub/scm/linux/kernel/git/peterz/linux-2.6-mmu_preempt.git mmu_preempt
Which is better? Thanks, I'll try.
Regards,
Piotr Hosowicz
--
Wzór Einsteina-Pitagorasa: E = mc2 = m(a2 + b2)
NP: Peter Green Splinter Group - Big Change Is Gonna Come
NB: 2.6.36-rc2-next-20100827
Fully depends on how you manage your git tree, the first will keep
giving you the same tree while the second will try and merge my changes
into whatever you got from Linus' tree, which keeps moving fwd and might
thus start failing (at which point I'll have to either rebase or
backmerge Linus' changes).
From: Peter Zijlstra <peterz@infradead.org> Date: 2010-08-28 15:28:07
On Sat, 2010-08-28 at 18:19 +0300, Pekka Enberg wrote:
Hi Peter,
On Sat, Aug 28, 2010 at 5:16 PM, Peter Zijlstra [off-list ref] wrote:
quoted
Yanmin ran the last posting through the comprehensive Intel test farm
and didn't find any regressions.
Is there data somewhere that shows where this helps and how much?
Yanmin didn't publish any data, but the main point of the series is to
not take hundreds of nested spinlocks. Not regressing is a fine state.
In theory the preemptible mmu could end up doing less TLB invalidates
for large unmaps and thus gain some performance there.
Fully depends on how you manage your git tree, the first will keep
giving you the same tree while the second will try and merge my changes
into whatever you got from Linus' tree, which keeps moving fwd and might
thus start failing (at which point I'll have to either rebase or
backmerge Linus' changes).
I'll risk the second way. I almost do not manage the tree, I just copy my local copy to tmp dir, then git pull from Linus, if there are changes I build the kernel.
Regards,
Piotr Hosowicz
--
Z cyklu "Uroki demokracji", czyli pytania i odpowiedzi w teledurniejach:
- W którym kraju znajduje się Mount Everest?
- Hm, to nie Szkocja, prawda?
NP: Peter Green Splinter Group - I Can't Help Myself
NB: 2.6.36-rc2-next-20100827
From: Peter Zijlstra <peterz@infradead.org> Date: 2010-08-28 22:42:09
On Sat, 2010-08-28 at 15:28 -0700, David Miller wrote:
I get 'as' segfaults during a "make -j128" of the kernel on sparc64
with these changes.
I'll try to track it down.
Hrm, I let it run:
while :; do
make O=foo/ clean;
make O=foo/ randconfig;
make O=foo/ -j48;
done
on my 24 cpu machine with this for like an hour, I'll let it run more
tomorrow to see if I can reproduce this.
Thanks for looking at this.
Fully depends on how you manage your git tree, the first will keep
giving you the same tree while the second will try and merge my changes
into whatever you got from Linus' tree, which keeps moving fwd and might
thus start failing (at which point I'll have to either rebase or
backmerge Linus' changes).
I chose the second path, kernel built OK, but then I had to build NVidia module and I started Xorg. I logged in and then the screen froze for a while, then Kde background went black and I had to hard reset the PC, bezcause couldn't switch to VT. I attach my Xorg log.
--
- E.T. phone home. - powiedział E.T.
- Dzwoni do centrali po wskazówki - domyślił się Stirlitz.
NP: Patrick O'Hearn - Chance
NB: 2.6.36-rc2-git5
From: Piotr Hosowicz <hidden> Date: 2010-08-29 13:45:17
On 29.08.2010 15:37, Peter Zijlstra wrote:
On Sun, 2010-08-29 at 14:46 +0200, Piotr Hosowicz wrote:
quoted
build NVidia module
Sorry, you're on your own.
OK.
Regards,
Piotr Hosowicz
--
"Pirotechnicy zdetonowali na warszawskim Okęciu podejrzane ładunki,
znalezione przy porzuconym motocyklu. Wszystko wskazuje na to, że
był to fałszywy alarm". Z polskiego na nasze: "rozp* komuś motor".
NP: Patrick O'Hearn - Night Becomes Her
NB: 2.6.36-rc2-git5
From: Peter Zijlstra <peterz@infradead.org> Date: 2010-08-30 15:45:44
Got a fancy ia64 compiler now, which informed me I fouled up, fixed up
patch below.
Will update the git tree shortly.
---
Subject: ia64: Preemptible mmu_gather
From: Peter Zijlstra <redacted>
Date: Wed Jun 02 13:26:02 CEST 2010
Fix up the ia64 mmu_gather code to conform to the new API.
Cc: Tony Luck <tony.luck@intel.com>
Signed-off-by: Peter Zijlstra <redacted>
LKML-Reference: <new-submission>
---
arch/ia64/include/asm/tlb.h | 39 ++++++++++++++++++++++++---------------
1 file changed, 24 insertions(+), 15 deletions(-)
Index: linux-2.6/arch/ia64/include/asm/tlb.h
===================================================================
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2010-08-31 06:12:08
On Sat, 2010-08-28 at 16:16 +0200, Peter Zijlstra wrote:
plain text document attachment (powerpc-pgtable-call_rcu_sched.patch)
PowerPC relies on IRQ-disable to guard against RCU quiecent states,
use the appropriate RCU call version.
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Nick Piggin <redacted>
Cc: Paul E. McKenney <redacted>
Signed-off-by: Peter Zijlstra <redacted>
So as per discussions with Paul Mck, that should be correct,
thus
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2010-08-31 06:28:11
On Sat, 2010-08-28 at 16:16 +0200, Peter Zijlstra wrote:
Fix up powerpc to the new mmu_gather stuffs.
Unfortunately, I think this is broken...
First there's an actual bug here:
quoted hunk
last = _switch(old_thread, new_thread);+#ifdef CONFIG_PPC64+ if (task_thread_info(new)->local_flags & _TLF_LAZY_MMU) {+ task_thread_info(new)->local_flags &= ~_TLF_LAZY_MMU;+ batch = &__get_cpu_var(ppc64_tlb_batch);+ batch->active = 1;+ }+#endif+
Here, you are coming out of _switch() which will have swapped the
stack and non-volatile registers to the state they were in when the
new task was originally switched-out. Thus "new" which is a local variable
(either on stack or in a non-volatile register) will now refer to whatever
was the next task back then.
I suppose that's what's causing the similar patch you have in -rt to
fail btw. This could be fixed easily by using "current" instead.
However, there I have another concern.
PPC has an extra batching queue to RCU free the actual pagetable
allocations, use the ARCH extentions for that for now.
Right, so far that looks fine (at least after a quick look).
For the ppc64_tlb_batch, which tracks the vaddrs to unhash from the
hardware hash-table, keep using per-cpu arrays but flush on context
switch and use a TLF bit to track the laxy_mmu state.
However, that doesn't seem necessary at all, at least not for !-rt, or
unless you broke something that I would need to look at very closely
then :-)
IE. Enable/disable the batch only within "lazy_mmu_mode" sections. We do
that in large part because we do not want non-flushed pages to exist
outside of the pte spinlock.
The reason is that if we let that happen, a small possibility exist for
our MMU hash page handling to try to insert a duplicate entry for a
given PTE into the hash table, which is basically fatal.
Thus, we only exist during that lazy period, which means with a lock
held. Hence we can't schedule and the changes you do regarding
get/put_cpu_var are unnecessary.
Another "trick" here btw is that fork() is currently not using a batch,
but with our technique, we do get batching there too.
So unless something else is broken that makes the above not true
anymore, which would be a concern, most of the changes you did to the
flush batch are unnecessary for your preemptible mmu_gather on non-rt
kernels.
Of course, with -rt and the pte lock becoming a mutex, all of your
changes do become necessary (and I suppose that's where they come from).
Now, those changes won't technically hurt on a non-rt kernel, tho they
will add a tiny bit of overhead. I'll see if I can measure it.
Cheers,
Ben.
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2010-08-31 06:32:30
On Tue, 2010-08-31 at 16:26 +1000, Benjamin Herrenschmidt wrote:
On Sat, 2010-08-28 at 16:16 +0200, Peter Zijlstra wrote:
quoted
Fix up powerpc to the new mmu_gather stuffs.
Unfortunately, I think this is broken...
First there's an actual bug here:
quoted
last = _switch(old_thread, new_thread);+#ifdef CONFIG_PPC64+ if (task_thread_info(new)->local_flags & _TLF_LAZY_MMU) {+ task_thread_info(new)->local_flags &= ~_TLF_LAZY_MMU;+ batch = &__get_cpu_var(ppc64_tlb_batch);+ batch->active = 1;+ }+#endif+
Here, you are coming out of _switch() which will have swapped the
stack and non-volatile registers to the state they were in when the
new task was originally switched-out. Thus "new" which is a local variable
(either on stack or in a non-volatile register) will now refer to whatever
was the next task back then.
I suppose that's what's causing the similar patch you have in -rt to
fail btw. This could be fixed easily by using "current" instead.
And here's a fix. Using current_thread_info() everywhere is better
anyways, you are not supposed to touch the local_flags within anything
but "current" so we may as well make it explicit.
Feel free to fold that into your -rt patch and this one if you decide
not to drop that whole part.
From: Peter Zijlstra <peterz@infradead.org> Date: 2010-08-31 09:16:04
On Tue, 2010-08-31 at 16:31 +1000, Benjamin Herrenschmidt wrote:
Of course, with -rt and the pte lock becoming a mutex, all of your
changes do become necessary (and I suppose that's where they come from).
Now, those changes won't technically hurt on a non-rt kernel, tho they
will add a tiny bit of overhead. I'll see if I can measure it.
Indeed, those parts are only strictly needed for -rt, I was hoping the
tiny bit of overhead wouldn't be too bad and we could keep it.
If not I guess we should put those two bits in __switch_to() under
CONFIG_PREEMPT_RT and carry them there for a little while longer.
quoted
I suppose that's what's causing the similar patch you have in -rt to
fail btw. This could be fixed easily by using "current" instead.
And here's a fix. Using current_thread_info() everywhere is better
anyways, you are not supposed to touch the local_flags within anything
but "current" so we may as well make it explicit.
Feel free to fold that into your -rt patch and this one if you decide
not to drop that whole part.
Thanks! And yeah I'd prefer to keep it to reduce Thomas' burden if
possible.
Fully depends on how you manage your git tree, the first will keep
giving you the same tree while the second will try and merge my changes
into whatever you got from Linus' tree, which keeps moving fwd and might
thus start failing (at which point I'll have to either rebase or
backmerge Linus' changes).
I chose the second path, kernel built OK, but then I had to build NVidia
module and I started Xorg. I logged in and then the screen froze for a
while, then Kde background went black and I had to hard reset the PC,
bezcause couldn't switch to VT. I attach my Xorg log.
Now I had done it the second way you described and everything seems to be working ok.
aapi205:~# uname -r
2.6.36-rc3-20100831-1507-pz+
If there will be any problems I'll write here.
Regards,
Piotr Hosowicz
--
Z cyklu "Uroki demokracji", czyli pytania i odpowiedzi w teledurniejach:
- Który aktor amerykański jest mężem Nicole Kidman?
- Forrest Gump.
NP: Peter Green Splinter Group - You'll Be Sorry Someday
NB: 2.6.36-rc3-20100831-1507-pz+
Fully depends on how you manage your git tree, the first will keep
giving you the same tree while the second will try and merge my changes
into whatever you got from Linus' tree, which keeps moving fwd and might
thus start failing (at which point I'll have to either rebase or
backmerge Linus' changes).
I chose the second path, kernel built OK, but then I had to build NVidia
module and I started Xorg. I logged in and then the screen froze for a
while, then Kde background went black and I had to hard reset the PC,
bezcause couldn't switch to VT. I attach my Xorg log.
Now I had done it the second way you described and everything seems to
be working ok.
Sorry, I made a mistake - I had built it the first way.
Regards and sorry for the noise,
Piotr Hosowicz
--
Janusz Korwin-Mikke:
"Idiota z dyplomem to taki sam idiota,
jak przedtem - tylko z pretensjami."
NP: Peter Green Splinter Group - Tribal Dance
NB: 2.6.36-rc3-20100831-1507-pz+
Fully depends on how you manage your git tree, the first will keep
giving you the same tree while the second will try and merge my changes
into whatever you got from Linus' tree, which keeps moving fwd and might
thus start failing (at which point I'll have to either rebase or
backmerge Linus' changes).
I chose the second path, kernel built OK, but then I had to build NVidia
module and I started Xorg. I logged in and then the screen froze for a
while, then Kde background went black and I had to hard reset the PC,
bezcause couldn't switch to VT. I attach my Xorg log.
Now I had done it the second way you described and everything seems to
be working ok.
Still works OK and I perceive that it is better, Peter.
Do you know when Linus will be back from Brazil?
Regards,
Piotr Hosowicz
--
Z cyklu "Uroki demokracji", czyli pytania i odpowiedzi w teledurniejach:
- Ile kół ma trójkołowiec?
- Dwa.
NP: Peter Green Splinter Group - Indians
NB: 2.6.36-rc3-20100831-1507-pz+