VMA lookup with RCU
Subsystems (22)
cover VMA lookup with RCU
This is forward port of Peter Zijlstra's RCU based VMA lookup patch set to kernel version 2.6.23.1
Reference:
http://programming.kicks-ass.net/kernel-patches/vma_lookup/
The patch set still needs some cleanup. I am sending this out for anybody to review and try more experiments.
I have been posting results based on this patch set at linux-mm
http://marc.info/?l=linux-mm&m=119186241210311&w=2
--Vaidy
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 1/9 Data structure changes
* Replace vm_next with list_head in mm_struct
* Change all instance of mm->vm_next and mm->mmap
* TBD: Not all architectures covered
--- arch/alpha/kernel/osf_sys.c | 2 arch/arm/mm/mmap.c | 2 arch/frv/mm/elf-fdpic.c | 4 - arch/i386/mm/hugetlbpage.c | 2 arch/ia64/kernel/sys_ia64.c | 2 arch/ia64/mm/hugetlbpage.c | 2 arch/mips/kernel/irixelf.c | 19 +++--- arch/mips/kernel/syscall.c | 2 arch/parisc/kernel/sys_parisc.c | 4 - arch/powerpc/mm/tlb_32.c | 2 arch/ppc/mm/tlb.c | 2 arch/x86_64/ia32/ia32_aout.c | 2 arch/x86_64/kernel/sys_x86_64.c | 2 drivers/char/mem.c | 2 drivers/oprofile/buffer_sync.c | 4 - fs/binfmt_aout.c | 2 fs/binfmt_elf.c | 4 - fs/binfmt_elf_fdpic.c | 5 + fs/exec.c | 4 - fs/hugetlbfs/inode.c | 2 fs/proc/task_mmu.c | 18 +++--- include/linux/init_task.h | 1 include/linux/mm.h | 44 ++++++++++++++- include/linux/sched.h | 2 ipc/shm.c | 4 - kernel/acct.c | 5 - kernel/auditsc.c | 4 - kernel/fork.c | 11 +-- mm/madvise.c | 2 mm/memory.c | 21 +++---- mm/mempolicy.c | 10 +-- mm/migrate.c | 2 mm/mlock.c | 5 + mm/mmap.c | 114 +++++++++++++++++++--------------------- mm/mprotect.c | 2 mm/mremap.c | 7 +- mm/msync.c | 2 mm/swapfile.c | 2 38 files changed, 180 insertions(+), 146 deletions(-)
arch/alpha/kernel/osf_sys.c +1 -1
@@ -1255,7 +1255,7 @@ arch_get_unmapped_area_1(unsigned long aif (!vma || addr + len <= vma->vm_start)return addr; addr = vma->vm_end; - vma = vma->vm_next; + vma =vma_next (vma); } }
arch/arm/mm/mmap.c +1 -1
@@ -84,7 +84,7 @@ full_search:else addr =PAGE_ALIGN (addr); -for (vma =find_vma (mm, addr); ; vma = vma->vm_next) { +for (vma =find_vma (mm, addr); ; vma =vma_next (vma)) {/* At this point: (!vma || addr < vma->vm_end). */ if (TASK_SIZE - len < addr) {/*
arch/frv/mm/elf-fdpic.c +2 -2
@@ -86,7 +86,7 @@ unsigned long arch_get_unmapped_area(strif (addr <= limit) { vma =find_vma (current->mm,PAGE_SIZE ); -for (; vma; vma = vma->vm_next) { +for (; vma; vma =vma_next (vma)) {if (addr > limit)break ;if (addr + len <= vma->vm_start)
@@ -101,7 +101,7 @@ unsigned long arch_get_unmapped_area(str limit =TASK_SIZE - len;if (addr <= limit) { vma =find_vma (current->mm, addr); -for (; vma; vma = vma->vm_next) { +for (; vma; vma =vma_next (vma)) {if (addr > limit)break ;if (addr + len <= vma->vm_start)
arch/i386/mm/hugetlbpage.c +1 -1
@@ -241,7 +241,7 @@ static unsigned long hugetlb_get_unmappe full_search: addr =ALIGN (start_addr,HPAGE_SIZE ); -for (vma =find_vma (mm, addr); ; vma = vma->vm_next) { +for (vma =find_vma (mm, addr); ; vma =vma_next (vma)) {/* At this point: (!vma || addr < vma->vm_end). */ if (TASK_SIZE - len < addr) {/*
arch/ia64/kernel/sys_ia64.c +1 -1
@@ -58,7 +58,7 @@ arch_get_unmapped_area (struct file *fil full_search: start_addr = addr = (addr + align_mask) & ~align_mask; -for (vma =find_vma (mm, addr); ; vma = vma->vm_next) { +for (vma =find_vma (mm, addr); ; vma =vma_next (vma)) {/* At this point: (!vma || addr < vma->vm_end). */ if (TASK_SIZE - len < addr ||RGN_MAP_LIMIT - len <REGION_OFFSET (addr)) {if (start_addr !=TASK_UNMAPPED_BASE ) {
arch/ia64/mm/hugetlbpage.c +1 -1
@@ -159,7 +159,7 @@ unsigned long hugetlb_get_unmapped_area( addr =HPAGE_REGION_BASE ; else addr =ALIGN (addr,HPAGE_SIZE ); -for (vmm =find_vma (current->mm, addr); ; vmm = vmm->vm_next) { +for (vmm =find_vma (current->mm, addr); ; vmm =vmm_next (vma)) {/* At this point: (!vmm || addr < vmm->vm_end). */ if (REGION_OFFSET (addr) + len >RGN_MAP_LIMIT )return -ENOMEM ;
arch/mips/kernel/irixelf.c +10 -9
@@ -718,7 +718,7 @@ static int load_irix_binary(struct linux/* OK, This is the point of no return */ current->mm->end_data =0 ; current->mm->end_code =0 ; - current->mm->mmap =NULL ; +INIT_LIST_HEAD (¤t->mm->mm_vmas); current->flags &= ~PF_FORKNOEXEC ; elf_entry = (unsigned int ) elf_ex.e_entry;
@@ -1108,7 +1108,7 @@ static int irix_core_dump(long signr, st/* Count what's needed to dump, up to the limit of coredump size. */ segs =0 ; size =0 ; -for (vma = current->mm->mmap; vma !=NULL ; vma = vma->vm_next) { +for (vma = current->mm->mmap; vma !=NULL ; vma =vma_next (vma)) {if (maydump (vma)) {int sz = vma->vm_end-vma->vm_start;
@@ -1267,12 +1267,13 @@ static int irix_core_dump(long signr, st dataoff = offset =roundup (offset,PAGE_SIZE );/* Write program headers for segments dump. */ -for (vma = current->mm->mmap, i =0 ; - i < segs && vma !=NULL ; vma = vma->vm_next) { + i = 0 +list_for_each_entry (vma, ¤t->mm->mm_vmas, vm_list) {struct elf_phdr phdr;size_t sz; - i++; +if (i++ == seg) +break ; sz = vma->vm_end - vma->vm_start;
@@ -1301,15 +1302,15 @@ static int irix_core_dump(long signr, stDUMP_SEEK (dataoff); -for (i =0 , vma = current->mm->mmap; - i < segs && vma !=NULL ; - vma = vma->vm_next) { + i = 0 +list_for_each_entry (vma, ¤t->mm->mm_vmas, vm_list) {unsigned long addr = vma->vm_start;unsigned long len = vma->vm_end - vma->vm_start;if (!maydump (vma))continue ; - i++; +if (i++ == seg) +break ;pr_debug ("elf_core_dump: writing %08lx %lx\n" , addr, len);DUMP_WRITE ((void __user *)addr, len); }
arch/mips/kernel/syscall.c +1 -1
@@ -104,7 +104,7 @@ unsigned long arch_get_unmapped_area(strelse addr =PAGE_ALIGN (addr); -for (vmm =find_vma (current->mm, addr); ; vmm = vmm->vm_next) { +for (vmm =find_vma (current->mm, addr); ; vmm =vmm_next (vmm)) {/* At this point: (!vmm || addr < vmm->vm_end). */ if (task_size - len < addr)return -ENOMEM ;
arch/parisc/kernel/sys_parisc.c +2 -2
@@ -52,7 +52,7 @@ static unsigned long get_unshared_area(u addr =PAGE_ALIGN (addr); -for (vma =find_vma (current->mm, addr); ; vma = vma->vm_next) { +for (vma =find_vma (current->mm, addr); ; vma =vma_next (vma)) {/* At this point: (!vma || addr < vma->vm_end). */ if (TASK_SIZE - len < addr)return -ENOMEM ;
@@ -88,7 +88,7 @@ static unsigned long get_shared_area(str addr =DCACHE_ALIGN (addr - offset) + offset; -for (vma =find_vma (current->mm, addr); ; vma = vma->vm_next) { +for (vma =find_vma (current->mm, addr); ; vma =vma_next (vma)) {/* At this point: (!vma || addr < vma->vm_end). */ if (TASK_SIZE - len < addr)return -ENOMEM ;
arch/powerpc/mm/tlb_32.c +1 -1
@@ -155,7 +155,7 @@ void flush_tlb_mm(struct mm_struct *mm)* unmap_region or exit_mmap, but not from vmtruncate on SMP - * but it seems dup_mmap is the only SMP case which gets here. */ -for (mp = mm->mmap; mp !=NULL ; mp = mp->vm_next) +list_for_each_entry (mp, &mm->mm_vmas, vm_list)flush_range (mp->vm_mm, mp->vm_start, mp->vm_end);FINISH_FLUSH ; }
arch/ppc/mm/tlb.c +1 -1
@@ -149,7 +149,7 @@ void flush_tlb_mm(struct mm_struct *mm)return ; } -for (mp = mm->mmap; mp !=NULL ; mp = mp->vm_next) +list_for_each_entry (mp, &mm->mm_vmas, vm_list)flush_range (mp->vm_mm, mp->vm_start, mp->vm_end);FINISH_FLUSH ; }
arch/x86_64/ia32/ia32_aout.c +1 -1
@@ -311,7 +311,7 @@ static int load_aout_binary(struct linux current->mm->free_area_cache =TASK_UNMAPPED_BASE ; current->mm->cached_hole_size =0 ; - current->mm->mmap =NULL ; +INIT_LIST_HEAD (¤t->mm->mm_vmas);compute_creds (bprm); current->flags &= ~PF_FORKNOEXEC ;
arch/x86_64/kernel/sys_x86_64.c +1 -1
@@ -119,7 +119,7 @@ arch_get_unmapped_area(struct file *filp start_addr = addr; full_search: -for (vma =find_vma (mm, addr); ; vma = vma->vm_next) { +for (vma =find_vma (mm, addr); ; vma =vma_next (vma)) {/* At this point: (!vma || addr < vma->vm_end). */ if (end - len < addr) {/*
drivers/char/mem.c +1 -1
@@ -640,7 +640,7 @@ static inline size_t read_zero_pagealigndown_read (&mm->mmap_sem);/* For private mappings, just map in zero pages. */ -for (vma =find_vma (mm, addr); vma; vma = vma->vm_next) { +for (vma =find_vma (mm, addr); vma; vma =vma_next (vma)) {unsigned long count;if (vma->vm_start > addr || (vma->vm_flags &VM_WRITE ) ==0 )
drivers/oprofile/buffer_sync.c +2 -2
@@ -217,7 +217,7 @@ static unsigned long get_exec_dcookie(stif (!mm) goto out; -for (vma = mm->mmap; vma; vma = vma->vm_next) { +list_for_each_entry (vma, &mm->mm_vmas, vm_list) {if (!vma->vm_file)continue ;if (!(vma->vm_flags &VM_EXECUTABLE ))
@@ -242,7 +242,7 @@ static unsigned long lookup_dcookie(struunsigned long cookie =NO_COOKIE ;struct vm_area_struct * vma; -for (vma =find_vma (mm, addr); vma; vma = vma->vm_next) { +for (vma =find_vma (mm, addr); vma; vma =vma_next (vma)) {if (addr < vma->vm_start || addr >= vma->vm_end)continue ;
fs/binfmt_aout.c +1 -1
@@ -323,7 +323,7 @@ static int load_aout_binary(struct linux current->mm->free_area_cache = current->mm->mmap_base; current->mm->cached_hole_size =0 ; - current->mm->mmap =NULL ; +INIT_LIST_HEAD (¤t->mm->mm_vmas);compute_creds (bprm); current->flags &= ~PF_FORKNOEXEC ;#ifdef __sparc__
fs/binfmt_elf.c +2 -2
@@ -1458,7 +1458,7 @@ static int elf_dump_thread_status(long sstatic struct vm_area_struct *first_vma (struct task_struct *tsk,struct vm_area_struct *gate_vma) { -struct vm_area_struct *ret = tsk->mm->mmap; +struct vm_area_struct *ret =__vma_next (&tsk->mm->mm_vmas,NULL );if (ret)return ret;
@@ -1473,7 +1473,7 @@ static struct vm_area_struct *next_vma(s {struct vm_area_struct *ret; - ret = this_vma->vm_next; + ret =vma_next (this_vma);if (ret)return ret;if (this_vma == gate_vma)
fs/binfmt_elf_fdpic.c +3 -2
@@ -1471,7 +1471,8 @@ static int elf_fdpic_dump_segments(struc {struct vm_area_struct *vma; -for (vma = current->mm->mmap; vma; vma = vma->vm_next) { +list_for_each_entry (vma, ¤t->mm->mm_vmas, vm_list) { +unsigned long addr;if (!maydump (vma, mm_flags))
@@ -1728,7 +1729,7 @@ static int elf_fdpic_core_dump(long sign/* write program headers for segments dump */ for ( #ifdef CONFIG_MMU - vma = current->mm->mmap; vma; vma = vma->vm_next + vma = __vma_next(¤t->mm->mm_vmas, NULL); vma; vma = vma_next(vma) #else vml = current->mm->context.vmlist; vml; vml = vml->next #endif
fs/exec.c +2 -2
@@ -555,7 +555,7 @@ static int shift_arg_pages(struct vm_are* when the old and new regions overlap clear from new_end. */ free_pgd_range (&tlb, new_end, old_end, new_end, - vma->vm_next ? vma->vm_next->vm_start :0 ); +vma_next (vma) ?vma_next (vma)->vm_start :0 ); }else {/* * otherwise, clean from old_start; this is done to not touch
@@ -564,7 +564,7 @@ static int shift_arg_pages(struct vm_are* for the others its just a little faster. */ free_pgd_range (&tlb, old_start, old_end, new_end, - vma->vm_next ? vma->vm_next->vm_start :0 ); +vma_next (vma) ?vma_next (vma)->vm_start :0 ); }tlb_finish_mmu (tlb, new_end, old_end);
fs/hugetlbfs/inode.c +1 -1
@@ -158,7 +158,7 @@ hugetlb_get_unmapped_area(struct file *f full_search: addr =ALIGN (start_addr,HPAGE_SIZE ); -for (vma =find_vma (mm, addr); ; vma = vma->vm_next) { +for (vma =find_vma (mm, addr); ; vma =vma_next (vma)) {/* At this point: (!vma || addr < vma->vm_end). */ if (TASK_SIZE - len < addr) {/*
fs/proc/task_mmu.c +9 -9
@@ -87,11 +87,11 @@ int proc_exe_link(struct inode *inode, s goto out;down_read (&mm->mmap_sem); - vma = mm->mmap; + vma =__vma_next (&mm->mm_vmas,NULL );while (vma) {if ((vma->vm_flags &VM_EXECUTABLE ) && vma->vm_file)break ; - vma = vma->vm_next; + vma =vma_next (vma); }if (vma) {
@@ -364,7 +364,7 @@ void clear_refs_smap(struct mm_struct *mstruct vm_area_struct *vma;down_read (&mm->mmap_sem); -for (vma = mm->mmap; vma; vma = vma->vm_next) +list_for_each_entry (vma, &mm->mm_vmas, vm_list)if (vma->vm_mm && !is_vm_hugetlb_page (vma))walk_page_range (vma, clear_refs_pte_range,NULL );flush_tlb_mm (mm);
@@ -406,7 +406,7 @@ static void *m_start(struct seq_file *m,/* Start with last addr hint */ if (last_addr && (vma =find_vma (mm, last_addr))) { - vma = vma->vm_next; + vma =vma_next (vma); goto out; }
@@ -416,9 +416,9 @@ static void *m_start(struct seq_file *m,*/ vma =NULL ;if ((unsigned long )l < mm->map_count) { - vma = mm->mmap; + vma =__vma_next (&mm->mm_vmas,NULL );while (l-- && vma) - vma = vma->vm_next; + vma =vma_next (vma); goto out; }
@@ -448,12 +448,12 @@ static void vma_stop(struct proc_maps_prstatic void *m_next (struct seq_file *m,void *v,loff_t *pos) {struct proc_maps_private *priv = m->private; -struct vm_area_struct *vma = v; +struct vm_area_struct *vma = v, *next;struct vm_area_struct *tail_vma = priv->tail_vma; (*pos)++; -if (vma && (vma != tail_vma) && vma->vm_next) -return vma->vm_next; +if (vma && (vma != tail_vma) && (next =vma_next (vma))) +return next;vma_stop (priv, vma);return (vma != tail_vma)? tail_vma:NULL ; }
include/linux/init_task.h +1 -0
@@ -47,6 +47,7 @@#define INIT_MM (name) \ { \ + .mm_vmas = LIST_HEAD_INIT(name.mm_vmas), \ .mm_rb = RB_ROOT, \ .pgd = swapper_pg_dir, \ .mm_users = ATOMIC_INIT(2), \
include/linux/mm.h +41 -3
73 lines not on this page · raw message
include/linux/sched.h +1 -1
@@ -367,7 +367,7 @@ extern int get_dumpable(struct mm_struct ((1 << MMF_DUMP_ANON_PRIVATE) | (1 << MMF_DUMP_ANON_SHARED))struct mm_struct { -struct vm_area_struct * mmap;/* list of VMAs */ +struct list_head mm_vmas;struct rb_root mm_rb;struct vm_area_struct * mmap_cache;/* last find_vma result */ unsigned long (*get_unmapped_area) (struct file *filp,
ipc/shm.c +2 -2
@@ -1034,7 +1034,7 @@ asmlinkage long sys_shmdt(char __user *s vma =find_vma (mm, addr);while (vma) { - next = vma->vm_next; + next =vma_next (vma);/* * Check if the starting address would match, i.e. it's
@@ -1067,7 +1067,7 @@ asmlinkage long sys_shmdt(char __user *s*/ size =PAGE_ALIGN (size);while (vma && (loff_t)(vma->vm_end - addr) <= size) { - next = vma->vm_next; + next =vma_next (vma);/* finding a matching vma now does not alter retval */ if ((vma->vm_ops == &shm_vm_ops) &&
kernel/acct.c +1 -4
@@ -540,11 +540,8 @@ void acct_collect(long exitcode, int groif (group_dead && current->mm) {struct vm_area_struct *vma;down_read (¤t->mm->mmap_sem); - vma = current->mm->mmap; -while (vma) { +list_for_each_entry (vma, ¤t->mm->mm_vmas, vm_list) vsize += vma->vm_end - vma->vm_start; - vma = vma->vm_next; - }up_read (¤t->mm->mmap_sem); }
kernel/auditsc.c +1 -3
@@ -780,8 +780,7 @@ static void audit_log_task_info(struct aif (mm) {down_read (&mm->mmap_sem); - vma = mm->mmap; -while (vma) { +list_for_each_entry (vma, &mm->mm_vmas, vm_list) {if ((vma->vm_flags &VM_EXECUTABLE ) && vma->vm_file) { audit_log_d_path(ab, "exe=",
@@ -789,7 +788,6 @@ static void audit_log_task_info(struct a vma->vm_file->f_path.mnt);break ; } - vma = vma->vm_next; }up_read (&mm->mmap_sem); }
kernel/fork.c +4 -7
@@ -197,7 +197,7 @@ static struct task_struct *dup_task_stru#ifdef CONFIG_MMU static inline int dup_mmap (struct mm_struct *mm,struct mm_struct *oldmm) { -struct vm_area_struct *mpnt, *tmp, **pprev; +struct vm_area_struct *mpnt, *tmp;struct rb_node **rb_link, *rb_parent;int retval;unsigned long charge;
@@ -211,7 +211,6 @@ static inline int dup_mmap(struct mm_strdown_write_nested (&mm->mmap_sem,SINGLE_DEPTH_NESTING ); mm->locked_vm =0 ; - mm->mmap =NULL ; mm->mmap_cache =NULL ; mm->free_area_cache = oldmm->mmap_base; mm->cached_hole_size = ~0UL ;
@@ -220,9 +219,8 @@ static inline int dup_mmap(struct mm_str mm->mm_rb =RB_ROOT ; rb_link = &mm->mm_rb.rb_node; rb_parent =NULL ; - pprev = &mm->mmap; -for (mpnt = oldmm->mmap; mpnt; mpnt = mpnt->vm_next) { +list_for_each_entry (mpnt, &oldmm->mm_vmas, vm_list) {struct file *file;if (mpnt->vm_flags &VM_DONTCOPY ) {
@@ -250,7 +248,6 @@ static inline int dup_mmap(struct mm_strvma_set_policy (tmp, pol); tmp->vm_flags &= ~VM_LOCKED ; tmp->vm_mm = mm; - tmp->vm_next =NULL ;anon_vma_link (tmp); file = tmp->vm_file;if (file) {
@@ -271,9 +268,8 @@ static inline int dup_mmap(struct mm_str/* * Link in the new vma and copy the page table entries. */ - *pprev = tmp; - pprev = &tmp->vm_next; +list_add_tail (&tmp->vm_list, &mm->mm_vmas);__vma_link_rb (mm, tmp, rb_link, rb_parent); rb_link = &tmp->vm_rb.rb_right; rb_parent = &tmp->vm_rb;
@@ -330,6 +326,7 @@ static inline void mm_free_pgd(struct mmstatic struct mm_struct *mm_init (struct mm_struct * mm) { +INIT_LIST_HEAD (&mm->mm_vmas);atomic_set (&mm->mm_users,1 );atomic_set (&mm->mm_count,1 );init_rwsem (&mm->mmap_sem);
mm/madvise.c +1 -1
@@ -351,7 +351,7 @@ asmlinkage long sys_madvise(unsigned lonif (start >= end) goto out;if (prev) - vma = prev->vm_next; + vma =vma_next (prev);else /* madvise_remove dropped mmap_sem */ vma =find_vma (current->mm, start); }
mm/memory.c +11 -10
@@ -264,11 +264,11 @@ void free_pgd_range(struct mmu_gather **flush_tlb_pgtables ((*tlb)->mm, start, end); } -void free_pgtables (struct mmu_gather **tlb,struct vm_area_struct *vma, -unsigned long floor,unsigned long ceiling) +void free_pgtables (struct mmu_gather **tlb,struct list_head *vmas, +struct vm_area_struct *vma,unsigned long floor,unsigned long ceiling) {while (vma) { -struct vm_area_struct *next = vma->vm_next; +struct vm_area_struct *next =__vma_next (vmas, vma);unsigned long addr = vma->vm_start;/*
@@ -287,7 +287,7 @@ void free_pgtables(struct mmu_gather **twhile (next && next->vm_start <= vma->vm_end +PMD_SIZE && !is_vm_hugetlb_page (next)) { vma = next; - next = vma->vm_next; + next =__vma_next (vmas, vma);anon_vma_unlink (vma);unlink_file_vma (vma); }
@@ -806,7 +806,7 @@ static unsigned long unmap_page_range(st* ensure that any thus-far unmapped pages are flushed before unmap_vmas() * drops the lock and schedules. */ -unsigned long unmap_vmas (struct mmu_gather **tlbp, +unsigned long unmap_vmas (struct mmu_gather **tlbp,struct list_head *vmas,struct vm_area_struct *vma,unsigned long start_addr,unsigned long end_addr,unsigned long *nr_accounted,struct zap_details *details)
@@ -818,7 +818,7 @@ unsigned long unmap_vmas(struct mmu_gathspinlock_t *i_mmap_lock = details? details->i_mmap_lock:NULL ;int fullmm = (*tlbp)->fullmm; -for ( ; vma && vma->vm_start < end_addr; vma = vma->vm_next) { +for ( ; vma && vma->vm_start < end_addr; vma =__vma_next (vmas, vma)) {unsigned long end; start =max (vma->vm_start, start_addr);
@@ -889,7 +889,8 @@ unsigned long zap_page_range(struct vm_alru_add_drain (); tlb =tlb_gather_mmu (mm,0 );update_hiwater_rss (mm); - end =unmap_vmas (&tlb, vma, address, end, &nr_accounted, details); + end =unmap_vmas (&tlb, &vma->vm_mm->mm_vmas, vma, + address, end, &nr_accounted, details);if (tlb)tlb_finish_mmu (tlb, address, end);return end;
@@ -2093,7 +2094,7 @@ int vmtruncate_range(struct inode *inodevoid swapin_readahead (swp_entry_t entry,unsigned long addr,struct vm_area_struct *vma) {#ifdef CONFIG_NUMA -struct vm_area_struct *next_vma = vma ? vma->vm_next :NULL ; +struct vm_area_struct *next_vma = vma ?vma_next (vma) :NULL ;#endif int i, num;struct page *new_page;
@@ -2120,14 +2121,14 @@ void swapin_readahead(swp_entry_t entry,if (vma) {if (addr >= vma->vm_end) { vma = next_vma; - next_vma = vma ? vma->vm_next :NULL ; + next_vma = vma ?vma_next (vma) :NULL ; }if (vma && addr < vma->vm_start) vma =NULL ; }else {if (next_vma && addr >= next_vma->vm_start) { vma = next_vma; - next_vma = vma->vm_next; + next_vma =vma_next (vma); } }#endif
mm/mempolicy.c +5 -5
@@ -344,9 +344,9 @@ check_range(struct mm_struct *mm, unsignif (!first)return ERR_PTR (-EFAULT ); prev =NULL ; -for (vma = first; vma && vma->vm_start < end; vma = vma->vm_next) { +for (vma = first; vma && vma->vm_start < end; vma =vma_next (vma)) {if (!(flags &MPOL_MF_DISCONTIG_OK )) { -if (!vma->vm_next && vma->vm_end < end) +if (!vma_next (vma) && vma->vm_end < end)return ERR_PTR (-EFAULT );if (prev && prev->vm_end < vma->vm_start)return ERR_PTR (-EFAULT );
@@ -403,7 +403,7 @@ static int mbind_range(struct vm_area_st err =0 ;for (; vma && vma->vm_start < end; vma = next) { - next = vma->vm_next; + next =vma_next (vma);if (vma->vm_start < start) err =split_vma (vma->vm_mm, vma, start,1 );if (!err && vma->vm_end > end)
@@ -610,7 +610,7 @@ int migrate_to_node(struct mm_struct *mmnodes_clear (nmask);node_set (source, nmask); -check_range (mm, mm->mmap->vm_start,TASK_SIZE , &nmask, +check_range (mm,__vma_next (&mm->mm_vmas,NULL )->vm_start,TASK_SIZE , &nmask, flags |MPOL_MF_DISCONTIG_OK , &pagelist);if (!list_empty (&pagelist))
@@ -1785,7 +1785,7 @@ void mpol_rebind_mm(struct mm_struct *mmstruct vm_area_struct *vma;down_write (&mm->mmap_sem); -for (vma = mm->mmap; vma; vma = vma->vm_next) +list_for_each_entry (vma, &mm->mm_vmas, vm_list)mpol_rebind_policy (vma->vm_policy, new);up_write (&mm->mmap_sem); }
mm/migrate.c +1 -1
@@ -1030,7 +1030,7 @@ int migrate_vmas(struct mm_struct *mm, cstruct vm_area_struct *vma;int err =0 ; -for (vma = mm->mmap; vma->vm_next && !err; vma = vma->vm_next) { +list_for_each_entry (vma, &mm->mm_vmas, vm_list) {if (vma->vm_ops && vma->vm_ops->migrate) { err = vma->vm_ops->migrate (vma, to, from, flags);if (err)
mm/mlock.c +3 -2
@@ -123,7 +123,7 @@ static int do_mlock(unsigned long start,if (nstart >= end)break ; - vma = prev->vm_next; + vma =vma_next (prev);if (!vma || vma->vm_start != nstart) { error = -ENOMEM ;break ;
@@ -181,7 +181,7 @@ static int do_mlockall(int flags)if (flags ==MCL_FUTURE ) goto out; -for (vma = current->mm->mmap; vma ; vma = prev->vm_next) { +list_for_each_entry (vma, ¤t->mm->mm_vmas, vm_list) {unsigned int newflags; newflags = vma->vm_flags |VM_LOCKED ;
@@ -190,6 +190,7 @@ static int do_mlockall(int flags)/* Ignore errors */ mlock_fixup (vma, &prev, vma->vm_start, vma->vm_end, newflags); + vma = prev; } out:return 0 ;
mm/mmap.c +56 -58
313 lines not on this page · raw message
mm/mprotect.c +1 -1
@@ -302,7 +302,7 @@ sys_mprotect(unsigned long start, size_tif (nstart >= end) goto out; - vma = prev->vm_next; + vma =vma_next (prev);if (!vma || vma->vm_start != nstart) { error = -ENOMEM ; goto out;
mm/mremap.c +4 -3
@@ -226,7 +226,7 @@ static unsigned long move_vma(struct vm_if (excess) { vma->vm_flags |=VM_ACCOUNT ;if (split) - vma->vm_next->vm_flags |=VM_ACCOUNT ; +vma_next (vma)->vm_flags |=VM_ACCOUNT ; }if (vm_flags &VM_LOCKED ) {
@@ -360,8 +360,9 @@ unsigned long do_mremap(unsigned long ad !((flags & MREMAP_FIXED) && (addr != new_addr)) && (old_len != new_len || !(flags & MREMAP_MAYMOVE))) {unsigned long max_addr =TASK_SIZE ; -if (vma->vm_next) - max_addr = vma->vm_next->vm_start; +struct vm_area_struct *next =vma_next (vma); +if (next) + max_addr = next->vm_start;/* can we just expand the current mapping? */ if (max_addr - addr >= new_len) {int pages = (new_len - old_len) >>PAGE_SHIFT ;
mm/msync.c +1 -1
@@ -93,7 +93,7 @@ asmlinkage long sys_msync(unsigned long error =0 ; goto out_unlock; } - vma = vma->vm_next; + vma =vma_next (vma); } } out_unlock:
mm/swapfile.c +1 -1
@@ -626,7 +626,7 @@ static int unuse_mm(struct mm_struct *mmdown_read (&mm->mmap_sem);lock_page (page); } -for (vma = mm->mmap; vma; vma = vma->vm_next) { +list_for_each_entry (vma, &mm->mm_vmas, vm_list) {if (vma->anon_vma &&unuse_vma (vma, entry, page))break ; }
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 2/9 lib: RCU friendly B+tree
In reply to Vaidyanathan SrinivasanIntroduce an RCU friendly B+tree in lib
--- include/linux/btree.h | 151 ++++++ init/main.c | 2 lib/Makefile | 3 lib/btree.c | 1189 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1344 insertions(+), 1 deletion(-)
include/linux/btree.h new file +151 -0
@@ -0,0 +1,151 @@ +#ifndef _LINUX_BTREE_H +#define _LINUX_BTREE_H + +#define BTREE_DEBUG 1 + +#include <linux/mempool.h> +#include <linux/log2.h> +#include <linux/rcupdate.h> +#include <asm/cache.h> +#include <asm/bitops.h> + +struct btree_item { +unsigned long key; +void *data; +}; + +#define BTREE_ITEM_CACHELINE (L1_CACHE_BYTES / sizeof(struct btree_item)) +#define BTREE_ITEM_MAX (BTREE_ITEM_CACHELINE < 16 ? 16 : BTREE_ITEM_CACHELINE) +#define BTREE_ITEM_HALF (BTREE_ITEM_MAX/2) + +struct btree_node { +struct btree_item item[BTREE_ITEM_MAX ]; +}; + +/* +* Max depth of the tree. +* Assumes BTREE_ITEM_MAX is power of two. +*/ +#define BTREE_MAX_DEPTH \ + (1 + DIV_ROUND_UP(BITS_PER_LONG, ilog2(BTREE_ITEM_MAX))) + +/* +* Max number of nodes to be RCUed per modification. +*/ +#define BTREE_NODE_REPLACE (2 * BTREE_MAX_DEPTH) + +struct btree_freevec { +struct rcu_head rcu_head; +int pos; +void *slot[BTREE_NODE_REPLACE ]; +}; + +struct btree_root { +struct btree_node *root; +int height; +mempool_t *mempool; +struct btree_freevec *freevec; +gfp_t gfp_mask; +void (*flush)(struct btree_freevec *); +}; + +#ifdef BTREE_DEBUG +void btree_print (struct btree_root *); +#else +#define btree_print (root) do { } while (0) +#endif + +static inline void *btree_item_deref (struct btree_item *itemp) +{ +void *ptr =rcu_dereference (itemp->data); +__clear_bit (0 , (void *)&ptr); +return ptr; +} + +static inline unsigned long btree_item_key (struct btree_item *itemp) +{ +unsigned long key = itemp->key; +/* +* match the smp_wmb() in btree_item_key_set() +*/ +smp_rmb (); +return key; +} + +extern struct btree_item *btree_search_next (struct btree_root *root, +unsigned long index,struct btree_item **nextp); + +static inline void *btree_lookup (struct btree_root *root,unsigned long index) +{ +struct btree_item *item; + + item =btree_search_next (root, index,NULL ); +if (!item ||btree_item_key (item) != index) +return NULL ; + +return item->data; +} + +static inline void *btree_lookup_next (struct btree_root *root, +unsigned long index,void **nextp) +{ +struct btree_item *next =NULL , *item; + + item =btree_search_next (root, index, &next); +if (next) + *nextp = next->data; +if (!item ||btree_item_key (item) != index) +return NULL ; + +return item->data; +} + +static inline void *btree_stab (struct btree_root *root,unsigned long index) +{ +struct btree_item *item; + + item =btree_search_next (root, index,NULL ); +if (!item) +return NULL ; + +return item->data; +} + +static inline void *btree_stab_next (struct btree_root *root, +unsigned long index,void **nextp) +{ +struct btree_item *next =NULL , *item; + + item =btree_search_next (root, index, &next); +if (next) + *nextp = next->data; +if (!item) +return NULL ; + +return item->data; +} + +extern int btree_preload (struct btree_root *,gfp_t ); +extern int btree_insert (struct btree_root *,unsigned long ,void *); +extern int btree_update (struct btree_root *,unsigned long ,unsigned long ); +extern void *btree_remove (struct btree_root *,unsigned long ); + +extern void btree_root_init (struct btree_root *,gfp_t ); +extern void btree_root_destroy (struct btree_root *); + +extern void btree_freevec_flush (struct btree_freevec *); + +#define BTREE_INIT_FLUSH (gfp, f) (struct btree_root){ \ + .root = NULL, \ + .height = 0, \ + .mempool = NULL, \ + .freevec = NULL, \ + .gfp_mask = (gfp), \ + .flush = (f), \ +} + +#define BTREE_INIT (gfp) BTREE_INIT_FLUSH(gfp, btree_freevec_flush) + +extern void __init btree_init (void ); + +#endif /* _LINUX_BTREE_H */
init/main.c +2 -0
@@ -55,6 +55,7 @@#include <linux/pid_namespace.h> #include <linux/device.h> #include <linux/kthread.h> +#include <linux/btree.h> #include <asm/io.h> #include <asm/bugs.h>
@@ -613,6 +614,7 @@ asmlinkage void __init start_kernel(voidcpuset_init_early ();mem_init ();kmem_cache_init (); +btree_init ();setup_per_cpu_pageset ();numa_policy_init ();if (late_time_init)
lib/Makefile +2 -1
@@ -5,7 +5,8 @@ lib-y := ctype.o string.o vsprintf.o kasprintf.o cmdline.o \ rbtree.o radix-tree.o dump_stack.o \ idr.o int_sqrt.o bitmap.o extable.o prio_tree.o \ - sha1.o irq_regs.o reciprocal_div.o argv_split.o + sha1.o irq_regs.o reciprocal_div.o argv_split.o \ + btree.o lib-$(CONFIG_MMU) += ioremap.o lib-$(CONFIG_SMP) += cpumask.o
lib/btree.c new file +1189 -0
1,189 lines not on this page · raw message
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 3/9 mm: use the B+tree for vma lookups
In reply to Vaidyanathan Srinivasan--- include/linux/init_task.h | 2 include/linux/mm.h | 5 - include/linux/sched.h | 4 kernel/fork.c | 17 +-- mm/mmap.c | 230 +++++++++++++++------------------------------- 5 files changed, 92 insertions(+), 166 deletions(-)
include/linux/init_task.h +1 -1
@@ -48,7 +48,7 @@#define INIT_MM (name) \ { \ .mm_vmas = LIST_HEAD_INIT(name.mm_vmas), \ - .mm_rb = RB_ROOT, \ + .mm_btree = BTREE_INIT(GFP_ATOMIC), \ .pgd = swapper_pg_dir, \ .mm_users = ATOMIC_INIT(2), \ .mm_count = ATOMIC_INIT(1), \
include/linux/mm.h +1 -4
@@ -69,8 +69,6 @@ struct vm_area_struct {pgprot_t vm_page_prot;/* Access permissions of this VMA. */ unsigned long vm_flags;/* Flags, listed below. */ -struct rb_node vm_rb; -/* * For areas with an address space and backing store, * linkage into the address_space->i_mmap prio tree, or
@@ -1091,8 +1089,7 @@ extern struct anon_vma *find_mergeable_aextern int split_vma (struct mm_struct *,struct vm_area_struct *,unsigned long addr,int new_below);extern int insert_vm_struct (struct mm_struct *,struct vm_area_struct *); -extern void __vma_link_rb (struct mm_struct *,struct vm_area_struct *, -struct rb_node **,struct rb_node *); +extern void __vma_link_btree (struct mm_struct *,struct vm_area_struct *);extern void unlink_file_vma (struct vm_area_struct *);extern struct vm_area_struct *copy_vma (struct vm_area_struct **,unsigned long addr,unsigned long len,pgoff_t pgoff);
include/linux/sched.h +2 -2
@@ -52,7 +52,7 @@ struct sched_param {#include <linux/types.h> #include <linux/timex.h> #include <linux/jiffies.h> -#include <linux/rbtree.h> +#include <linux/btree.h> #include <linux/thread_info.h> #include <linux/cpumask.h> #include <linux/errno.h>
@@ -368,7 +368,7 @@ extern int get_dumpable(struct mm_structstruct mm_struct {struct list_head mm_vmas; -struct rb_root mm_rb; +struct btree_root mm_btree;struct vm_area_struct * mmap_cache;/* last find_vma result */ unsigned long (*get_unmapped_area) (struct file *filp, unsigned long addr, unsigned long len,
kernel/fork.c +9 -8
@@ -198,7 +198,6 @@ static struct task_struct *dup_task_strustatic inline int dup_mmap (struct mm_struct *mm,struct mm_struct *oldmm) {struct vm_area_struct *mpnt, *tmp; -struct rb_node **rb_link, *rb_parent;int retval;unsigned long charge;struct mempolicy *pol;
@@ -216,9 +215,6 @@ static inline int dup_mmap(struct mm_str mm->cached_hole_size = ~0UL ; mm->map_count =0 ;cpus_clear (mm->cpu_vm_mask); - mm->mm_rb =RB_ROOT ; - rb_link = &mm->mm_rb.rb_node; - rb_parent =NULL ;list_for_each_entry (mpnt, &oldmm->mm_vmas, vm_list) {struct file *file;
@@ -270,9 +266,8 @@ static inline int dup_mmap(struct mm_str*/ list_add_tail (&tmp->vm_list, &mm->mm_vmas); -__vma_link_rb (mm, tmp, rb_link, rb_parent); - rb_link = &tmp->vm_rb.rb_right; - rb_parent = &tmp->vm_rb; +btree_preload (&mm->mm_btree,GFP_KERNEL |__GFP_NOFAIL);// XXX create error path +__vma_link_btree (mm, tmp); mm->map_count++; retval =copy_page_range (mm, oldmm, mpnt);
@@ -320,13 +315,19 @@ static inline void mm_free_pgd(struct mm__cacheline_aligned_in_smp DEFINE_SPINLOCK (mmlist_lock );#define allocate_mm () (kmem_cache_alloc(mm_cachep, GFP_KERNEL)) -#define free_mm (mm) (kmem_cache_free(mm_cachep, (mm))) + +static void free_mm (struct mm_struct *mm) +{ +btree_root_destroy (&mm->mm_btree); +kmem_cache_free (mm_cachep, mm); +}#include <linux/init_task.h> static struct mm_struct *mm_init (struct mm_struct * mm) {INIT_LIST_HEAD (&mm->mm_vmas); + mm->mm_btree =BTREE_INIT (GFP_ATOMIC );atomic_set (&mm->mm_users,1 );atomic_set (&mm->mm_count,1 );init_rwsem (&mm->mmap_sem);
mm/mmap.c +79 -151
406 lines not on this page · raw message
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 4/9 mm: RCU vma lookups
In reply to Vaidyanathan Srinivasanmostly lockless vma lookup using the new b+tree
pin the vma using an atomic refcount
--- include/linux/init_task.h | 2 include/linux/mm.h | 9 + kernel/fork.c | 2 mm/mmap.c | 216 +++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 206 insertions(+), 23 deletions(-)
include/linux/init_task.h +1 -1
@@ -48,7 +48,7 @@#define INIT_MM (name) \ { \ .mm_vmas = LIST_HEAD_INIT(name.mm_vmas), \ - .mm_btree = BTREE_INIT(GFP_ATOMIC), \ + .mm_btree = BTREE_INIT_FLUSH(GFP_ATOMIC, btree_rcu_flush), \ .pgd = swapper_pg_dir, \ .mm_users = ATOMIC_INIT(2), \ .mm_count = ATOMIC_INIT(1), \
include/linux/mm.h +9 -0
@@ -104,12 +104,14 @@ struct vm_area_struct {void * vm_private_data;/* was vm_pte (shared mem) */ unsigned long vm_truncate_count;/* truncate_count or restart_addr */ +struct rw_semaphore vm_sem;#ifndef CONFIG_MMU atomic_t vm_usage;/* refcount (VMAs shared if !MMU) */ #endif #ifdef CONFIG_NUMA struct mempolicy *vm_policy;/* NUMA policy for the VMA */ #endif +struct rcu_head vm_rcu_head; }; static inline struct vm_area_struct *
@@ -1078,6 +1080,8 @@ static inline void vma_nonlinear_insert( }/* mmap.c */ +extern void btree_rcu_flush (struct btree_freevec *); +extern void free_vma (struct vm_area_struct *vma);extern int __vm_enough_memory (struct mm_struct *mm,long pages,int cap_sys_admin);extern void vma_adjust (struct vm_area_struct *vma,unsigned long start,unsigned long end,pgoff_t pgoff,struct vm_area_struct *insert);
@@ -1177,6 +1181,11 @@ extern struct vm_area_struct * find_vma(extern struct vm_area_struct *find_vma_prev (struct mm_struct * mm,unsigned long addr,struct vm_area_struct **pprev); +extern struct vm_area_struct *__find_get_vma (struct mm_struct *mm,unsigned long addr,int *locked); +extern struct vm_area_struct *find_get_vma (struct mm_struct *mm,unsigned long addr); +extern void get_vma (struct vm_area_struct *vma); +extern void put_vma (struct vm_area_struct *vma); +/* Look up the first VMA which intersects the interval start_addr..end_addr-1, NULL if none. Assume start_addr < end_addr. */ static inline struct vm_area_struct *find_vma_intersection (struct mm_struct * mm,unsigned long start_addr,unsigned long end_addr)
kernel/fork.c +1 -1
@@ -327,7 +327,7 @@ static void free_mm(struct mm_struct *mmstatic struct mm_struct *mm_init (struct mm_struct * mm) {INIT_LIST_HEAD (&mm->mm_vmas); - mm->mm_btree =BTREE_INIT (GFP_ATOMIC ); + mm->mm_btree =BTREE_INIT_FLUSH (GFP_ATOMIC , btree_rcu_flush);atomic_set (&mm->mm_users,1 );atomic_set (&mm->mm_count,1 );init_rwsem (&mm->mmap_sem);
mm/mmap.c +195 -21
338 lines not on this page · raw message
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 5/9 i386: rcu vma lookups for faults
In reply to Vaidyanathan SrinivasanUse the new lockless vma lookup in the i386 fault handler. This avoids the exclusive cacheline access for the mmap_sem.
--- arch/i386/mm/fault.c | 56 +++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 26 deletions(-)
arch/i386/mm/fault.c +30 -26
@@ -307,6 +307,7 @@ fastcall void __kprobes do_page_fault(stunsigned long address;int write, si_code;int fault; +int locked =0 ;/* get the address */ address =read_cr2 ();
@@ -357,29 +358,14 @@ fastcall void __kprobes do_page_fault(stif (in_atomic () || !mm) goto bad_area_nosemaphore; -/* When running in the kernel we expect faults to occur only to -* addresses in user space. All other faults represent errors in the -* kernel and should generate an OOPS. Unfortunatly, in the case of an -* erroneous fault occurring in a code path which already holds mmap_sem -* we will deadlock attempting to validate the fault against the -* address space. Luckily the kernel only validly references user -* space from well defined areas of code, which are listed in the -* exceptions table. -* -* As the vast majority of faults will be valid we will only perform -* the source reference check when there is a possibilty of a deadlock. -* Attempt to lock the address space, if we cannot we then validate the -* source. If this is invalid we can skip the address space check, -* thus avoiding the deadlock. -*/ -if (!down_read_trylock (&mm->mmap_sem)) { -if ((error_code &4 ) ==0 && - !search_exception_tables (regs->eip)) - goto bad_area_nosemaphore; +again: +if (likely (!locked)) { + vma =__find_get_vma (mm, address, &locked); + }else {down_read (&mm->mmap_sem); + vma =find_vma (mm, address); +get_vma (vma); } - - vma =find_vma (mm, address);if (!vma) goto bad_area;if (vma->vm_start <= address)
@@ -396,6 +382,15 @@ fastcall void __kprobes do_page_fault(stif (address +65536 +32 *sizeof (unsigned long ) < regs->esp) goto bad_area; } +/* +* expand_stack needs the read lock, hence retry the whole thing +* read locked. +*/ +if (!locked) { +put_vma (vma); + locked =1 ; + goto again; + }if (expand_stack (vma, address)) goto bad_area;/*
@@ -403,6 +398,11 @@ fastcall void __kprobes do_page_fault(st* we can handle it.. */ good_area: +if (unlikely (locked)) { +up_read (&mm->mmap_sem); + locked =0 ; + } + si_code =SEGV_ACCERR ; write =0 ;switch (error_code &3 ) {
@@ -447,7 +447,7 @@ good_area:if (bit <32 ) tsk->thread.screen_bitmap |=1 << bit; } -up_read (&mm->mmap_sem); +put_vma (vma);return ;/*
@@ -455,7 +455,11 @@ good_area:* Fix it, but check if it's kernel or user first.. */ bad_area: -up_read (&mm->mmap_sem); +if (unlikely (locked)) { +up_read (&mm->mmap_sem); + locked =0 ; + } +put_vma (vma); bad_area_nosemaphore:/* User mode accesses just cause a SIGSEGV */
@@ -590,10 +594,10 @@ no_context:* us unable to handle the page fault gracefully. */ out_of_memory: -up_read (&mm->mmap_sem); +put_vma (vma);if (is_init (tsk)) {yield (); -down_read (&mm->mmap_sem); + vma =find_get_vma (mm, address); goto survive; }printk ("VM: killing process %s\n" , tsk->comm);
@@ -602,7 +606,7 @@ out_of_memory: goto no_context; do_sigbus: -up_read (&mm->mmap_sem); +put_vma (vma);/* Kernel mode? Handle exceptions or die */ if (!(error_code &4 ))
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 6/9 x86_64: rcu vma lookups for faults
In reply to Vaidyanathan Srinivasan--- arch/x86_64/mm/fault.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-)
arch/x86_64/mm/fault.c +25 -11
@@ -310,10 +310,10 @@ asmlinkage void __kprobes do_page_fault(int write, fault;unsigned long flags;siginfo_t info; +int locked =0 ; tsk = current; mm = tsk->mm; -prefetchw (&mm->mmap_sem);/* get the address */ address =read_cr2 ();
@@ -390,14 +390,14 @@ asmlinkage void __kprobes do_page_fault(* source. If this is invalid we can skip the address space check, * thus avoiding the deadlock. */ -if (!down_read_trylock (&mm->mmap_sem)) { -if ((error_code &PF_USER ) ==0 && - !search_exception_tables (regs->rip)) - goto bad_area_nosemaphore; + +if (likely (!locked)) { + vma =__find_get_vma (mm, address, &locked); + }else {down_read (&mm->mmap_sem); + vma =find_vma (mm, address); +get_vma (vma); } - - vma =find_vma (mm, address);if (!vma) goto bad_area;if (likely (vma->vm_start <= address))
@@ -411,6 +411,11 @@ asmlinkage void __kprobes do_page_fault(if (address +65536 +32 *sizeof (unsigned long ) < regs->rsp) goto bad_area; } +if (!locked) { +put_vma (vma); + locked =1 ; + goto again; + }if (expand_stack (vma, address)) goto bad_area;/*
@@ -418,6 +423,11 @@ asmlinkage void __kprobes do_page_fault(* we can handle it.. */ good_area: +if (locked) { +up_read (&mm->mmap_sem); + locked =0 ; + } + info.si_code =SEGV_ACCERR ; write =0 ;switch (error_code & (PF_PROT |PF_WRITE )) {
@@ -452,7 +462,7 @@ good_area: tsk->maj_flt++; else tsk->min_flt++; -up_read (&mm->mmap_sem); +put_vma (vma);return ;/*
@@ -460,7 +470,11 @@ good_area:* Fix it, but check if it's kernel or user first.. */ bad_area: -up_read (&mm->mmap_sem); +if (locked) { +up_read (&mm->mmap_sem); + locked =0 ; + } +put_vma (vma); bad_area_nosemaphore:/* User mode accesses just cause a SIGSEGV */
@@ -552,7 +566,7 @@ no_context:* us unable to handle the page fault gracefully. */ out_of_memory: -up_read (&mm->mmap_sem); +put_vma (vma);if (is_init (current)) {yield (); goto again;
@@ -563,7 +577,7 @@ out_of_memory: goto no_context; do_sigbus: -up_read (&mm->mmap_sem); +put_vma (vma);/* Kernel mode? Handle exceptions or die */ if (!(error_code &PF_USER ))
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 7/9 Add page fault code for PPC64 path
In reply to Vaidyanathan Srinivasan--- arch/powerpc/mm/fault.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-)
arch/powerpc/mm/fault.c +33 -11
@@ -148,6 +148,7 @@ int __kprobes do_page_fault(struct pt_reint is_write =0 , ret;int trap =TRAP (regs);int is_exec = trap ==0x400 ; +int locked =0 ;#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE ))/*
@@ -211,14 +212,22 @@ int __kprobes do_page_fault(struct pt_re* source. If this is invalid we can skip the address space check, * thus avoiding the deadlock. */ -if (!down_read_trylock (&mm->mmap_sem)) { -if (!user_mode (regs) && !search_exception_tables (regs->nip)) - goto bad_area_nosemaphore; - +// if (!down_read_trylock(&mm->mmap_sem)) { +// if (!user_mode(regs) && !search_exception_tables(regs->nip)) +// goto bad_area_nosemaphore; +// +// down_read(&mm->mmap_sem); +// } + +again: +if (likely (!locked)) { + vma =__find_get_vma (mm, address, &locked); + }else {down_read (&mm->mmap_sem); - } + vma =find_vma (mm, address); +get_vma (vma); + } - vma =find_vma (mm, address);if (!vma) goto bad_area;if (vma->vm_start <= address)
@@ -257,10 +266,19 @@ int __kprobes do_page_fault(struct pt_re && (!user_mode(regs) || !store_updates_sp(regs))) goto bad_area; } +if (!locked) { +put_vma (vma); + locked =1 ; + goto again; + }if (expand_stack (vma, address)) goto bad_area; good_area: +if (locked) { +up_read (&mm->mmap_sem); + locked =0 ; + } code =SEGV_ACCERR ;#if defined(CONFIG_6xx)if (error_code &0x95700000 )
@@ -311,7 +329,7 @@ good_area:pte_update (ptep,0 , _PAGE_HWEXEC);_tlbie (address);pte_unmap_unlock (ptep, ptl); -up_read (&mm->mmap_sem); +put_vma (vma);return 0 ; }pte_unmap_unlock (ptep, ptl);
@@ -348,11 +366,15 @@ good_area: current->maj_flt++; else current->min_flt++; -up_read (&mm->mmap_sem); +put_vma (vma);return 0 ; bad_area: -up_read (&mm->mmap_sem); +if (locked) { +up_read (&mm->mmap_sem); + locked =0 ; + } +put_vma (vma); bad_area_nosemaphore:/* User mode accesses cause a SIGSEGV */
@@ -374,7 +396,7 @@ bad_area_nosemaphore:* us unable to handle the page fault gracefully. */ out_of_memory: -up_read (&mm->mmap_sem); +put_vma (vma);if (is_init (current)) {yield ();down_read (&mm->mmap_sem);
@@ -386,7 +408,7 @@ out_of_memory:return SIGKILL ; do_sigbus: -up_read (&mm->mmap_sem); +put_vma (vma);if (user_mode (regs)) { info.si_signo =SIGBUS ; info.si_errno =0 ;
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 8/9 debug: instrument the fault path
In reply to Vaidyanathan Srinivasan--- arch/x86_64/mm/fault.c | 8 ++++++++ include/linux/vmstat.h | 1 + mm/vmstat.c | 5 +++++ 3 files changed, 14 insertions(+)
arch/x86_64/mm/fault.c +8 -0
@@ -25,6 +25,7 @@#include <linux/kprobes.h> #include <linux/uaccess.h> #include <linux/kdebug.h> +#include <linux/vmstat.h> #include <asm/system.h> #include <asm/pgalloc.h>
@@ -393,10 +394,16 @@ asmlinkage void __kprobes do_page_fault(if (likely (!locked)) { vma =__find_get_vma (mm, address, &locked); +if (unlikely (locked)) +count_vm_event (FAULT_RCU_SLOW ); +else +count_vm_event (FAULT_RCU ); + }else {down_read (&mm->mmap_sem); vma =find_vma (mm, address);get_vma (vma); +count_vm_event (FAULT_LOCKED ); }if (!vma) goto bad_area;
@@ -416,6 +423,7 @@ asmlinkage void __kprobes do_page_fault( locked =1 ; goto again; } +count_vm_event (FAULT_STACK );if (expand_stack (vma, address)) goto bad_area;/*
include/linux/vmstat.h +1 -0
@@ -37,6 +37,7 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSFOR_ALL_ZONES (PGSCAN_DIRECT ),PGINODESTEAL ,SLABS_SCANNED ,KSWAPD_STEAL ,KSWAPD_INODESTEAL ,PAGEOUTRUN ,ALLOCSTALL ,PGROTATED , +FAULT_RCU ,FAULT_RCU_SLOW ,FAULT_LOCKED ,FAULT_STACK ,NR_VM_EVENT_ITEMS };
mm/vmstat.c +5 -0
@@ -529,6 +529,11 @@ static const char * const vmstat_text[]"allocstall" ,"pgrotated" , + +"fault_rcu" , +"fault_rcu_slow" , +"fault_locked" , + "fault_stack", #endif };
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 9/9 mm: nr_ptes needs to be atomic
In reply to Vaidyanathan Srinivasan--- arch/powerpc/mm/fault.c | 6 ++++++ arch/sh/mm/cache-sh4.c | 2 +- arch/um/kernel/skas/mmu.c | 2 +- fs/proc/task_mmu.c | 2 +- include/linux/sched.h | 4 +++- kernel/fork.c | 2 +- mm/memory.c | 4 ++-- 7 files changed, 15 insertions(+), 7 deletions(-)
arch/powerpc/mm/fault.c +6 -0
@@ -235,6 +235,12 @@ again:if (!(vma->vm_flags &VM_GROWSDOWN )) goto bad_area; +if (!locked) { +put_vma (vma); + locked =1 ; + goto again; + } +/* * N.B. The POWER/Open ABI allows programs to access up to * 288 bytes below the stack pointer.
arch/sh/mm/cache-sh4.c +1 -1
@@ -373,7 +373,7 @@ void flush_cache_mm(struct mm_struct *mm* Don't bother groveling around the dcache for the VMA ranges * if there are too many PTEs to make it worthwhile. */ -if (mm->nr_ptes >=MAX_DCACHE_PAGES ) +if (atomic_long_read (&mm->nr_ptes) >=MAX_DCACHE_PAGES )flush_dcache_all ();else {struct vm_area_struct *vma;
arch/um/kernel/skas/mmu.c +1 -1
@@ -98,7 +98,7 @@ int init_new_context_skas(struct task_stif (ret) goto out_free; - mm->nr_ptes--; +atomic_long_dec (&mm->nr_ptes); } to_mm->id.stack = stack;
fs/proc/task_mmu.c +1 -1
@@ -52,7 +52,7 @@ char *task_mem(struct mm_struct *mm, cha total_rss << (PAGE_SHIFT -10 ), data << (PAGE_SHIFT -10 ), mm->stack_vm << (PAGE_SHIFT -10 ), text, lib, - (PTRS_PER_PTE*sizeof(pte_t)*mm->nr_ptes) >> 10); + (PTRS_PER_PTE*sizeof(pte_t)*atomic_long_read(&mm->nr_ptes)) >> 10);return buffer; }
include/linux/sched.h +3 -1
@@ -400,11 +400,13 @@ struct mm_struct {unsigned long hiwater_vm;/* High-water virtual memory usage */ unsigned long total_vm, locked_vm, shared_vm, exec_vm; -unsigned long stack_vm, reserved_vm, def_flags, nr_ptes; +unsigned long stack_vm, reserved_vm, def_flags;unsigned long start_code, end_code, start_data, end_data;unsigned long start_brk, brk, start_stack;unsigned long arg_start, arg_end, env_start, env_end; +atomic_long_t nr_ptes; +unsigned long saved_auxv[AT_VECTOR_SIZE ];/* for /proc/PID/auxv */ cpumask_t cpu_vm_mask;
kernel/fork.c +1 -1
@@ -335,7 +335,7 @@ static struct mm_struct * mm_init(struct mm->flags = (current->mm) ? current->mm->flags :MMF_DUMP_FILTER_DEFAULT ; mm->core_waiters =0 ; - mm->nr_ptes =0 ; +atomic_long_set (&mm->nr_ptes,0 );set_mm_counter (mm, file_rss,0 );set_mm_counter (mm, anon_rss,0 );spin_lock_init (&mm->page_table_lock);
mm/memory.c +2 -2
@@ -127,7 +127,7 @@ static void free_pte_range(struct mmu_gapte_lock_deinit (page);pte_free_tlb (tlb, page);dec_zone_page_state (page,NR_PAGETABLE ); - tlb->mm->nr_ptes--; +atomic_long_dec (&tlb->mm->nr_ptes); } static inline void free_pmd_range(struct mmu_gather *tlb, pud_t *pud,
@@ -310,7 +310,7 @@ int __pte_alloc(struct mm_struct *mm, pmpte_lock_deinit (new);pte_free (new); }else { - mm->nr_ptes++; +atomic_long_inc (&mm->nr_ptes);inc_zone_page_state (new,NR_PAGETABLE );pmd_populate (mm, pmd, new); }
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>