From e070569f2fa273212280128b7d07f3d39f0fbd27 Mon Sep 17 00:00:00 2001 From: Michel Lespinasse Date: Fri, 28 Jan 2022 05:09:42 -0800 Subject: [PATCH] mm: rcu safe vma freeing This prepares for speculative page faults looking up and copying vmas under protection of an rcu read lock, instead of the usual mmap read lock. Note - it might also be feasible to just use SLAB_TYPESAFE_BY_RCU when creating the vm_area_cachep, but that's probably too subtle to consider here. Signed-off-by: Michel Lespinasse --- include/linux/mm_types.h | 16 +++++++++++----- kernel/fork.c | 13 +++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index e4965a6f34f247..b6678578a72989 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -374,12 +374,18 @@ struct anon_vma_name { struct vm_area_struct { /* The first cache line has the info for VMA tree walking. */ - unsigned long vm_start; /* Our start address within vm_mm. */ - unsigned long vm_end; /* The first byte after our end address - within vm_mm. */ + union { + struct { + /* VMA covers [vm_start; vm_end) addresses within mm */ + unsigned long vm_start, vm_end; - /* linked list of VM areas per task, sorted by address */ - struct vm_area_struct *vm_next, *vm_prev; + /* linked list of VMAs per task, sorted by address */ + struct vm_area_struct *vm_next, *vm_prev; + }; +#ifdef CONFIG_SPECULATIVE_PAGE_FAULT + struct rcu_head vm_rcu; /* Used for deferred freeing. */ +#endif + }; struct rb_node vm_rb; diff --git a/kernel/fork.c b/kernel/fork.c index d75a528f7b2196..2e5f2e8de31a68 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -371,10 +371,23 @@ struct vm_area_struct *vm_area_dup(struct vm_area_struct *orig) return new; } +#ifdef CONFIG_SPECULATIVE_PAGE_FAULT +static void __vm_area_free(struct rcu_head *head) +{ + struct vm_area_struct *vma = container_of(head, struct vm_area_struct, + vm_rcu); + kmem_cache_free(vm_area_cachep, vma); +} +#endif + void vm_area_free(struct vm_area_struct *vma) { free_vma_anon_name(vma); +#ifdef CONFIG_SPECULATIVE_PAGE_FAULT + call_rcu(&vma->vm_rcu, __vm_area_free); +#else kmem_cache_free(vm_area_cachep, vma); +#endif } static void account_kernel_stack(struct task_struct *tsk, int account)