linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Laurent Dufour <ldufour@linux.ibm.com>
To: Suren Baghdasaryan <surenb@google.com>
Cc: akpm@linux-foundation.org, michel@lespinasse.org,
	jglisse@google.com, mhocko@suse.com, vbabka@suse.cz,
	hannes@cmpxchg.org, mgorman@suse.de, dave@stgolabs.net,
	willy@infradead.org, liam.howlett@oracle.com,
	peterz@infradead.org, laurent.dufour@fr.ibm.com,
	paulmck@kernel.org, luto@kernel.org, songliubraving@fb.com,
	peterx@redhat.com, david@redhat.com, dhowells@redhat.com,
	hughd@google.com, bigeasy@linutronix.de,
	kent.overstreet@linux.dev, rientjes@google.com,
	axelrasmussen@google.com, joelaf@google.com, minchan@google.com,
	kernel-team@android.com, linux-mm@kvack.org,
	linux-arm-kernel@lists.infradead.org,
	linuxppc-dev@lists.ozlabs.org, x86@kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [RFC PATCH RESEND 28/28] kernel/fork: throttle call_rcu() calls in vm_area_free
Date: Fri, 9 Sep 2022 18:14:23 +0200	[thread overview]
Message-ID: <e75586a4-7afd-f498-8dc4-02191dea4c3a@linux.ibm.com> (raw)
In-Reply-To: <CAJuCfpGn=Xhc3SnrK2ei1WPoFPaW00xZkS9MebN9Zxfv9joPoA@mail.gmail.com>

Le 09/09/2022 à 18:02, Suren Baghdasaryan a écrit :
> On Fri, Sep 9, 2022 at 8:19 AM Laurent Dufour <ldufour@linux.ibm.com> wrote:
>>
>> Le 01/09/2022 à 19:35, Suren Baghdasaryan a écrit :
>>> call_rcu() can take a long time when callback offloading is enabled.
>>> Its use in the vm_area_free can cause regressions in the exit path when
>>> multiple VMAs are being freed. To minimize that impact, place VMAs into
>>> a list and free them in groups using one call_rcu() call per group.
>>>
>>> Signed-off-by: Suren Baghdasaryan <surenb@google.com>
>>> ---
>>>  include/linux/mm.h       |  1 +
>>>  include/linux/mm_types.h | 11 ++++++-
>>>  kernel/fork.c            | 68 +++++++++++++++++++++++++++++++++++-----
>>>  mm/init-mm.c             |  3 ++
>>>  mm/mmap.c                |  1 +
>>>  5 files changed, 75 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/include/linux/mm.h b/include/linux/mm.h
>>> index a3cbaa7b9119..81dff694ac14 100644
>>> --- a/include/linux/mm.h
>>> +++ b/include/linux/mm.h
>>> @@ -249,6 +249,7 @@ void setup_initial_init_mm(void *start_code, void *end_code,
>>>  struct vm_area_struct *vm_area_alloc(struct mm_struct *);
>>>  struct vm_area_struct *vm_area_dup(struct vm_area_struct *);
>>>  void vm_area_free(struct vm_area_struct *);
>>> +void drain_free_vmas(struct mm_struct *mm);
>>>
>>>  #ifndef CONFIG_MMU
>>>  extern struct rb_root nommu_region_tree;
>>> diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
>>> index 36562e702baf..6f3effc493b1 100644
>>> --- a/include/linux/mm_types.h
>>> +++ b/include/linux/mm_types.h
>>> @@ -412,7 +412,11 @@ struct vm_area_struct {
>>>                       struct vm_area_struct *vm_next, *vm_prev;
>>>               };
>>>  #ifdef CONFIG_PER_VMA_LOCK
>>> -             struct rcu_head vm_rcu; /* Used for deferred freeing. */
>>> +             struct {
>>> +                     struct list_head vm_free_list;
>>> +                     /* Used for deferred freeing. */
>>> +                     struct rcu_head vm_rcu;
>>> +             };
>>>  #endif
>>>       };
>>>
>>> @@ -573,6 +577,11 @@ struct mm_struct {
>>>                                         */
>>>  #ifdef CONFIG_PER_VMA_LOCK
>>>               int mm_lock_seq;
>>> +             struct {
>>> +                     struct list_head head;
>>> +                     spinlock_t lock;
>>> +                     int size;
>>> +             } vma_free_list;
>>>  #endif
>>>
>>>
>>> diff --git a/kernel/fork.c b/kernel/fork.c
>>> index b443ba3a247a..7c88710aed72 100644
>>> --- a/kernel/fork.c
>>> +++ b/kernel/fork.c
>>> @@ -483,26 +483,75 @@ struct vm_area_struct *vm_area_dup(struct vm_area_struct *orig)
>>>  }
>>>
>>>  #ifdef CONFIG_PER_VMA_LOCK
>>> -static void __vm_area_free(struct rcu_head *head)
>>> +static inline void __vm_area_free(struct vm_area_struct *vma)
>>>  {
>>> -     struct vm_area_struct *vma = container_of(head, struct vm_area_struct,
>>> -                                               vm_rcu);
>>>       /* The vma should either have no lock holders or be write-locked. */
>>>       vma_assert_no_reader(vma);
>>>       kmem_cache_free(vm_area_cachep, vma);
>>>  }
>>> -#endif
>>> +
>>> +static void vma_free_rcu_callback(struct rcu_head *head)
>>> +{
>>> +     struct vm_area_struct *first_vma;
>>> +     struct vm_area_struct *vma, *vma2;
>>> +
>>> +     first_vma = container_of(head, struct vm_area_struct, vm_rcu);
>>> +     list_for_each_entry_safe(vma, vma2, &first_vma->vm_free_list, vm_free_list)
>>
>> Is that safe to walk the list against concurrent calls to
>> list_splice_init(), or list_add()?
> 
> I think it is. drain_free_vmas() moves the to-be-destroyed and already
> isolated VMAs from mm->vma_free_list into to_destroy list and then
> passes that list to vma_free_rcu_callback(). At this point the list of
> VMAs passed to vma_free_rcu_callback() is not accessible either from
> mm (VMAs were isolated before vm_area_free() was called) or from
> drain_free_vmas() since they were already removed from
> mm->vma_free_list. Does that make sense?

Got it!
Thanks for the explanation.

> 
>>
>>> +             __vm_area_free(vma);
>>> +     __vm_area_free(first_vma);
>>> +}
>>> +
>>> +void drain_free_vmas(struct mm_struct *mm)
>>> +{
>>> +     struct vm_area_struct *first_vma;
>>> +     LIST_HEAD(to_destroy);
>>> +
>>> +     spin_lock(&mm->vma_free_list.lock);
>>> +     list_splice_init(&mm->vma_free_list.head, &to_destroy);
>>> +     mm->vma_free_list.size = 0;
>>> +     spin_unlock(&mm->vma_free_list.lock);
>>> +
>>> +     if (list_empty(&to_destroy))
>>> +             return;
>>> +
>>> +     first_vma = list_first_entry(&to_destroy, struct vm_area_struct, vm_free_list);
>>> +     /* Remove the head which is allocated on the stack */
>>> +     list_del(&to_destroy);
>>> +
>>> +     call_rcu(&first_vma->vm_rcu, vma_free_rcu_callback);
>>> +}
>>> +
>>> +#define VM_AREA_FREE_LIST_MAX        32
>>> +
>>> +void vm_area_free(struct vm_area_struct *vma)
>>> +{
>>> +     struct mm_struct *mm = vma->vm_mm;
>>> +     bool drain;
>>> +
>>> +     free_anon_vma_name(vma);
>>> +
>>> +     spin_lock(&mm->vma_free_list.lock);
>>> +     list_add(&vma->vm_free_list, &mm->vma_free_list.head);
>>> +     mm->vma_free_list.size++;
>>> +     drain = mm->vma_free_list.size > VM_AREA_FREE_LIST_MAX;
>>> +     spin_unlock(&mm->vma_free_list.lock);
>>> +
>>> +     if (drain)
>>> +             drain_free_vmas(mm);
>>> +}
>>> +
>>> +#else /* CONFIG_PER_VMA_LOCK */
>>> +
>>> +void drain_free_vmas(struct mm_struct *mm) {}
>>>
>>>  void vm_area_free(struct vm_area_struct *vma)
>>>  {
>>>       free_anon_vma_name(vma);
>>> -#ifdef CONFIG_PER_VMA_LOCK
>>> -     call_rcu(&vma->vm_rcu, __vm_area_free);
>>> -#else
>>>       kmem_cache_free(vm_area_cachep, vma);
>>> -#endif
>>>  }
>>>
>>> +#endif /* CONFIG_PER_VMA_LOCK */
>>> +
>>>  static void account_kernel_stack(struct task_struct *tsk, int account)
>>>  {
>>>       if (IS_ENABLED(CONFIG_VMAP_STACK)) {
>>> @@ -1137,6 +1186,9 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
>>>       INIT_LIST_HEAD(&mm->mmlist);
>>>  #ifdef CONFIG_PER_VMA_LOCK
>>>       WRITE_ONCE(mm->mm_lock_seq, 0);
>>> +     INIT_LIST_HEAD(&mm->vma_free_list.head);
>>> +     spin_lock_init(&mm->vma_free_list.lock);
>>> +     mm->vma_free_list.size = 0;
>>>  #endif
>>>       mm_pgtables_bytes_init(mm);
>>>       mm->map_count = 0;
>>> diff --git a/mm/init-mm.c b/mm/init-mm.c
>>> index 8399f90d631c..7b6d2460545f 100644
>>> --- a/mm/init-mm.c
>>> +++ b/mm/init-mm.c
>>> @@ -39,6 +39,9 @@ struct mm_struct init_mm = {
>>>       .mmlist         = LIST_HEAD_INIT(init_mm.mmlist),
>>>  #ifdef CONFIG_PER_VMA_LOCK
>>>       .mm_lock_seq    = 0,
>>> +     .vma_free_list.head = LIST_HEAD_INIT(init_mm.vma_free_list.head),
>>> +     .vma_free_list.lock =  __SPIN_LOCK_UNLOCKED(init_mm.vma_free_list.lock),
>>> +     .vma_free_list.size = 0,
>>>  #endif
>>>       .user_ns        = &init_user_ns,
>>>       .cpu_bitmap     = CPU_BITS_NONE,
>>> diff --git a/mm/mmap.c b/mm/mmap.c
>>> index 1edfcd384f5e..d61b7ef84ba6 100644
>>> --- a/mm/mmap.c
>>> +++ b/mm/mmap.c
>>> @@ -3149,6 +3149,7 @@ void exit_mmap(struct mm_struct *mm)
>>>       }
>>>       mm->mmap = NULL;
>>>       mmap_write_unlock(mm);
>>> +     drain_free_vmas(mm);
>>>       vm_unacct_memory(nr_accounted);
>>>  }
>>>
>>



  reply	other threads:[~2022-09-09 16:14 UTC|newest]

Thread overview: 91+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-01 17:34 [RFC PATCH RESEND 00/28] per-VMA locks proposal Suren Baghdasaryan
2022-09-01 17:34 ` [RFC PATCH RESEND 01/28] mm: introduce CONFIG_PER_VMA_LOCK Suren Baghdasaryan
2022-09-01 17:34 ` [RFC PATCH RESEND 02/28] mm: rcu safe VMA freeing Suren Baghdasaryan
2022-09-01 17:34 ` [RFC PATCH RESEND 03/28] mm: introduce __find_vma to be used without mmap_lock protection Suren Baghdasaryan
2022-09-01 20:22   ` Kent Overstreet
2022-09-01 23:18     ` Suren Baghdasaryan
2022-09-01 17:34 ` [RFC PATCH RESEND 04/28] mm: move mmap_lock assert function definitions Suren Baghdasaryan
2022-09-01 20:24   ` Kent Overstreet
2022-09-01 20:51     ` Liam Howlett
2022-09-01 23:21       ` Suren Baghdasaryan
2022-09-02  6:23     ` Sebastian Andrzej Siewior
2022-09-02 17:46       ` Suren Baghdasaryan
2022-09-01 17:34 ` [RFC PATCH RESEND 05/28] mm: add per-VMA lock and helper functions to control it Suren Baghdasaryan
2022-09-06 13:46   ` Laurent Dufour
2022-09-06 17:24     ` Suren Baghdasaryan
2022-09-01 17:34 ` [RFC PATCH RESEND 06/28] mm: mark VMA as locked whenever vma->vm_flags are modified Suren Baghdasaryan
2022-09-06 14:26   ` Laurent Dufour
2022-09-06 19:00     ` Suren Baghdasaryan
2022-09-06 20:00       ` Liam Howlett
2022-09-06 20:13         ` Suren Baghdasaryan
2022-09-01 17:34 ` [RFC PATCH RESEND 07/28] kernel/fork: mark VMAs as locked before copying pages during fork Suren Baghdasaryan
2022-09-06 14:37   ` Laurent Dufour
2022-09-08 23:57     ` Suren Baghdasaryan
2022-09-09 13:27       ` Laurent Dufour
2022-09-09 16:29         ` Suren Baghdasaryan
2022-09-01 17:34 ` [RFC PATCH RESEND 08/28] mm/khugepaged: mark VMA as locked while collapsing a hugepage Suren Baghdasaryan
2022-09-06 14:43   ` Laurent Dufour
2022-09-09  0:15     ` Suren Baghdasaryan
2022-09-01 17:34 ` [RFC PATCH RESEND 09/28] mm/mempolicy: mark VMA as locked when changing protection policy Suren Baghdasaryan
2022-09-06 14:47   ` Laurent Dufour
2022-09-09  0:27     ` Suren Baghdasaryan
2022-09-01 17:34 ` [RFC PATCH RESEND 10/28] mm/mmap: mark VMAs as locked in vma_adjust Suren Baghdasaryan
2022-09-06 15:35   ` Laurent Dufour
2022-09-09  0:51     ` Suren Baghdasaryan
2022-09-09 15:52       ` Laurent Dufour
2022-09-01 17:34 ` [RFC PATCH RESEND 11/28] mm/mmap: mark VMAs as locked before merging or splitting them Suren Baghdasaryan
2022-09-06 15:44   ` Laurent Dufour
2022-09-01 17:35 ` [RFC PATCH RESEND 12/28] mm/mremap: mark VMA as locked while remapping it to a new address range Suren Baghdasaryan
2022-09-06 16:09   ` Laurent Dufour
2022-09-01 17:35 ` [RFC PATCH RESEND 13/28] mm: conditionally mark VMA as locked in free_pgtables and unmap_page_range Suren Baghdasaryan
2022-09-09 10:33   ` Laurent Dufour
2022-09-09 16:43     ` Suren Baghdasaryan
2022-09-01 17:35 ` [RFC PATCH RESEND 14/28] mm: mark VMAs as locked before isolating them Suren Baghdasaryan
2022-09-09 13:35   ` Laurent Dufour
2022-09-09 16:28     ` Suren Baghdasaryan
2022-09-01 17:35 ` [RFC PATCH RESEND 15/28] mm/mmap: mark adjacent VMAs as locked if they can grow into unmapped area Suren Baghdasaryan
2022-09-09 13:43   ` Laurent Dufour
2022-09-09 16:25     ` Suren Baghdasaryan
2022-09-01 17:35 ` [RFC PATCH RESEND 16/28] kernel/fork: assert no VMA readers during its destruction Suren Baghdasaryan
2022-09-09 13:56   ` Laurent Dufour
2022-09-09 16:19     ` Suren Baghdasaryan
2022-09-01 17:35 ` [RFC PATCH RESEND 17/28] mm/mmap: prevent pagefault handler from racing with mmu_notifier registration Suren Baghdasaryan
2022-09-09 14:20   ` Laurent Dufour
2022-09-09 16:12     ` Suren Baghdasaryan
2022-09-01 17:35 ` [RFC PATCH RESEND 18/28] mm: add FAULT_FLAG_VMA_LOCK flag Suren Baghdasaryan
2022-09-09 14:26   ` Laurent Dufour
2022-09-01 17:35 ` [RFC PATCH RESEND 19/28] mm: disallow do_swap_page to handle page faults under VMA lock Suren Baghdasaryan
2022-09-06 19:39   ` Peter Xu
2022-09-06 20:08     ` Suren Baghdasaryan
2022-09-06 20:22       ` Peter Xu
2022-09-07  0:58         ` Suren Baghdasaryan
2022-09-09 14:26   ` Laurent Dufour
2022-09-01 17:35 ` [RFC PATCH RESEND 20/28] mm: introduce per-VMA lock statistics Suren Baghdasaryan
2022-09-09 14:28   ` Laurent Dufour
2022-09-09 16:11     ` Suren Baghdasaryan
2022-09-01 17:35 ` [RFC PATCH RESEND 21/28] mm: introduce find_and_lock_anon_vma to be used from arch-specific code Suren Baghdasaryan
2022-09-09 14:38   ` Laurent Dufour
2022-09-09 16:10     ` Suren Baghdasaryan
2022-09-01 17:35 ` [RFC PATCH RESEND 22/28] x86/mm: try VMA lock-based page fault handling first Suren Baghdasaryan
2022-09-01 17:35 ` [RFC PATCH RESEND 23/28] x86/mm: define ARCH_SUPPORTS_PER_VMA_LOCK Suren Baghdasaryan
2022-09-01 20:20   ` Kent Overstreet
2022-09-01 23:17     ` Suren Baghdasaryan
2022-09-01 17:35 ` [RFC PATCH RESEND 24/28] arm64/mm: try VMA lock-based page fault handling first Suren Baghdasaryan
2022-09-01 17:35 ` [RFC PATCH RESEND 25/28] arm64/mm: define ARCH_SUPPORTS_PER_VMA_LOCK Suren Baghdasaryan
2022-09-01 17:35 ` [RFC PATCH RESEND 26/28] powerc/mm: try VMA lock-based page fault handling first Suren Baghdasaryan
2022-09-01 17:35 ` [RFC PATCH RESEND 27/28] powerpc/mm: define ARCH_SUPPORTS_PER_VMA_LOCK Suren Baghdasaryan
2022-09-01 17:35 ` [RFC PATCH RESEND 28/28] kernel/fork: throttle call_rcu() calls in vm_area_free Suren Baghdasaryan
2022-09-09 15:19   ` Laurent Dufour
2022-09-09 16:02     ` Suren Baghdasaryan
2022-09-09 16:14       ` Laurent Dufour [this message]
2022-09-01 20:58 ` [RFC PATCH RESEND 00/28] per-VMA locks proposal Kent Overstreet
2022-09-01 23:26   ` Suren Baghdasaryan
2022-09-11  9:35     ` Vlastimil Babka
2022-09-28  2:28       ` Suren Baghdasaryan
2022-09-29 11:18         ` Vlastimil Babka
2022-09-02  7:42 ` Peter Zijlstra
2022-09-02 14:45   ` Suren Baghdasaryan
2022-09-05 12:32 ` Michal Hocko
2022-09-05 18:32   ` Suren Baghdasaryan
2022-09-05 20:35     ` Kent Overstreet
2022-09-06 15:46       ` Suren Baghdasaryan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=e75586a4-7afd-f498-8dc4-02191dea4c3a@linux.ibm.com \
    --to=ldufour@linux.ibm.com \
    --cc=akpm@linux-foundation.org \
    --cc=axelrasmussen@google.com \
    --cc=bigeasy@linutronix.de \
    --cc=dave@stgolabs.net \
    --cc=david@redhat.com \
    --cc=dhowells@redhat.com \
    --cc=hannes@cmpxchg.org \
    --cc=hughd@google.com \
    --cc=jglisse@google.com \
    --cc=joelaf@google.com \
    --cc=kent.overstreet@linux.dev \
    --cc=kernel-team@android.com \
    --cc=laurent.dufour@fr.ibm.com \
    --cc=liam.howlett@oracle.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=luto@kernel.org \
    --cc=mgorman@suse.de \
    --cc=mhocko@suse.com \
    --cc=michel@lespinasse.org \
    --cc=minchan@google.com \
    --cc=paulmck@kernel.org \
    --cc=peterx@redhat.com \
    --cc=peterz@infradead.org \
    --cc=rientjes@google.com \
    --cc=songliubraving@fb.com \
    --cc=surenb@google.com \
    --cc=vbabka@suse.cz \
    --cc=willy@infradead.org \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).