From: Vlastimil Babka <vbabka@suse.cz>
To: Suren Baghdasaryan <surenb@google.com>, akpm@linux-foundation.org
Cc: peterz@infradead.org, willy@infradead.org,
liam.howlett@oracle.com, lorenzo.stoakes@oracle.com,
mhocko@suse.com, hannes@cmpxchg.org, mjguzik@gmail.com,
oliver.sang@intel.com, mgorman@techsingularity.net,
david@redhat.com, peterx@redhat.com, oleg@redhat.com,
dave@stgolabs.net, paulmck@kernel.org, brauner@kernel.org,
dhowells@redhat.com, hdanton@sina.com, hughd@google.com,
lokeshgidra@google.com, minchan@google.com, jannh@google.com,
shakeel.butt@linux.dev, souravpanda@google.com,
pasha.tatashin@soleen.com, klarasmodin@gmail.com,
richard.weiyang@gmail.com, corbet@lwn.net,
linux-doc@vger.kernel.org, linux-mm@kvack.org,
linux-kernel@vger.kernel.org, kernel-team@android.com
Subject: Re: [PATCH v8 11/16] mm: replace vm_lock and detached flag with a reference count
Date: Fri, 10 Jan 2025 15:34:26 +0100 [thread overview]
Message-ID: <95e9d80e-6c19-4a1f-9c21-307006858dff@suse.cz> (raw)
In-Reply-To: <20250109023025.2242447-12-surenb@google.com>
On 1/9/25 3:30 AM, Suren Baghdasaryan wrote:
> rw_semaphore is a sizable structure of 40 bytes and consumes
> considerable space for each vm_area_struct. However vma_lock has
> two important specifics which can be used to replace rw_semaphore
> with a simpler structure:
> 1. Readers never wait. They try to take the vma_lock and fall back to
> mmap_lock if that fails.
> 2. Only one writer at a time will ever try to write-lock a vma_lock
> because writers first take mmap_lock in write mode.
> Because of these requirements, full rw_semaphore functionality is not
> needed and we can replace rw_semaphore and the vma->detached flag with
> a refcount (vm_refcnt).
> When vma is in detached state, vm_refcnt is 0 and only a call to
> vma_mark_attached() can take it out of this state. Note that unlike
> before, now we enforce both vma_mark_attached() and vma_mark_detached()
> to be done only after vma has been write-locked. vma_mark_attached()
> changes vm_refcnt to 1 to indicate that it has been attached to the vma
> tree. When a reader takes read lock, it increments vm_refcnt, unless the
> top usable bit of vm_refcnt (0x40000000) is set, indicating presence of
> a writer. When writer takes write lock, it sets the top usable bit to
> indicate its presence. If there are readers, writer will wait using newly
> introduced mm->vma_writer_wait. Since all writers take mmap_lock in write
> mode first, there can be only one writer at a time. The last reader to
> release the lock will signal the writer to wake up.
> refcount might overflow if there are many competing readers, in which case
> read-locking will fail. Readers are expected to handle such failures.
> In summary:
> 1. all readers increment the vm_refcnt;
> 2. writer sets top usable (writer) bit of vm_refcnt;
> 3. readers cannot increment the vm_refcnt if the writer bit is set;
> 4. in the presence of readers, writer must wait for the vm_refcnt to drop
> to 1 (ignoring the writer bit), indicating an attached vma with no readers;
> 5. vm_refcnt overflow is handled by the readers.
>
> Suggested-by: Peter Zijlstra <peterz@infradead.org>
> Suggested-by: Matthew Wilcox <willy@infradead.org>
> Signed-off-by: Suren Baghdasaryan <surenb@google.com>
Reviewed-by: Vlastimil Babka <vbabka@suse.cz>
But think there's a problem that will manifest after patch 15.
Also I don't feel qualified enough about the lockdep parts though
(although I think I spotted another issue with those, below) so best if
PeterZ can review those.
Some nits below too.
> +
> +static inline void vma_refcount_put(struct vm_area_struct *vma)
> +{
> + int oldcnt;
> +
> + if (!__refcount_dec_and_test(&vma->vm_refcnt, &oldcnt)) {
> + rwsem_release(&vma->vmlock_dep_map, _RET_IP_);
Shouldn't we rwsem_release always? And also shouldn't it precede the
refcount operation itself?
> + if (is_vma_writer_only(oldcnt - 1))
> + rcuwait_wake_up(&vma->vm_mm->vma_writer_wait);
Hmm hmm we should maybe read the vm_mm pointer before dropping the
refcount? In case this races in a way that is_vma_writer_only tests true
but the writer meanwhile finishes and frees the vma. It's safe now but
not after making the cache SLAB_TYPESAFE_BY_RCU ?
> + }
> +}
> +
> static inline void vma_end_read(struct vm_area_struct *vma)
> {
> rcu_read_lock(); /* keeps vma alive till the end of up_read */
This should refer to vma_refcount_put(). But after fixing it I think we
could stop doing this altogether? It will no longer keep vma "alive"
with SLAB_TYPESAFE_BY_RCU.
> - up_read(&vma->vm_lock.lock);
> + vma_refcount_put(vma);
> rcu_read_unlock();
> }
>
<snip>
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -6370,9 +6370,41 @@ struct vm_area_struct *lock_mm_and_find_vma(struct mm_struct *mm,
> #endif
>
> #ifdef CONFIG_PER_VMA_LOCK
> +static inline bool __vma_enter_locked(struct vm_area_struct *vma, unsigned int tgt_refcnt)
> +{
> + /*
> + * If vma is detached then only vma_mark_attached() can raise the
> + * vm_refcnt. mmap_write_lock prevents racing with vma_mark_attached().
> + */
> + if (!refcount_add_not_zero(VMA_LOCK_OFFSET, &vma->vm_refcnt))
> + return false;
> +
> + rwsem_acquire(&vma->vmlock_dep_map, 0, 0, _RET_IP_);
> + rcuwait_wait_event(&vma->vm_mm->vma_writer_wait,
> + refcount_read(&vma->vm_refcnt) == tgt_refcnt,
> + TASK_UNINTERRUPTIBLE);
> + lock_acquired(&vma->vmlock_dep_map, _RET_IP_);
> +
> + return true;
> +}
> +
> +static inline void __vma_exit_locked(struct vm_area_struct *vma, bool *detached)
> +{
> + *detached = refcount_sub_and_test(VMA_LOCK_OFFSET, &vma->vm_refcnt);
> + rwsem_release(&vma->vmlock_dep_map, _RET_IP_);
> +}
> +
> void __vma_start_write(struct vm_area_struct *vma, unsigned int mm_lock_seq)
> {
> - down_write(&vma->vm_lock.lock);
> + bool locked;
> +
> + /*
> + * __vma_enter_locked() returns false immediately if the vma is not
> + * attached, otherwise it waits until refcnt is (VMA_LOCK_OFFSET + 1)
> + * indicating that vma is attached with no readers.
> + */
> + locked = __vma_enter_locked(vma, VMA_LOCK_OFFSET + 1);
Wonder if it would be slightly better if tgt_refcount was just 1 (or 0
below in vma_mark_detached()) and the VMA_LOCK_OFFSET added to it in
__vma_enter_locked() itself as it's the one adding it in the first place.
next prev parent reply other threads:[~2025-01-10 14:33 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-09 2:30 [PATCH v8 00/16] move per-vma lock into vm_area_struct Suren Baghdasaryan
2025-01-09 2:30 ` [PATCH v8 01/16] mm: introduce vma_start_read_locked{_nested} helpers Suren Baghdasaryan
2025-01-09 2:30 ` [PATCH v8 02/16] mm: move per-vma lock into vm_area_struct Suren Baghdasaryan
2025-01-09 2:30 ` [PATCH v8 03/16] mm: mark vma as detached until it's added into vma tree Suren Baghdasaryan
2025-01-09 2:30 ` [PATCH v8 04/16] mm: introduce vma_iter_store_attached() to use with attached vmas Suren Baghdasaryan
2025-01-09 14:01 ` Vlastimil Babka
2025-01-09 2:30 ` [PATCH v8 05/16] mm: mark vmas detached upon exit Suren Baghdasaryan
2025-01-09 2:30 ` [PATCH v8 06/16] types: move struct rcuwait into types.h Suren Baghdasaryan
2025-01-09 2:30 ` [PATCH v8 07/16] mm: allow vma_start_read_locked/vma_start_read_locked_nested to fail Suren Baghdasaryan
2025-01-09 2:30 ` [PATCH v8 08/16] mm: move mmap_init_lock() out of the header file Suren Baghdasaryan
2025-01-09 2:30 ` [PATCH v8 09/16] mm: uninline the main body of vma_start_write() Suren Baghdasaryan
2025-01-09 2:30 ` [PATCH v8 10/16] refcount: introduce __refcount_{add|inc}_not_zero_limited Suren Baghdasaryan
2025-01-09 14:42 ` Vlastimil Babka
2025-01-11 1:33 ` Suren Baghdasaryan
2025-01-09 2:30 ` [PATCH v8 11/16] mm: replace vm_lock and detached flag with a reference count Suren Baghdasaryan
2025-01-09 10:35 ` Hillf Danton
2025-01-09 16:01 ` Suren Baghdasaryan
2025-01-10 14:34 ` Vlastimil Babka [this message]
2025-01-10 15:56 ` Suren Baghdasaryan
2025-01-10 16:47 ` Suren Baghdasaryan
2025-01-10 16:50 ` Suren Baghdasaryan
2025-01-10 22:26 ` Vlastimil Babka
2025-01-10 22:37 ` Suren Baghdasaryan
2025-01-09 2:30 ` [PATCH v8 12/16] mm/debug: print vm_refcnt state when dumping the vma Suren Baghdasaryan
2025-01-09 2:30 ` [PATCH v8 13/16] mm: remove extra vma_numab_state_init() call Suren Baghdasaryan
2025-01-09 2:30 ` [PATCH v8 14/16] mm: prepare lock_vma_under_rcu() for vma reuse possibility Suren Baghdasaryan
2025-01-09 2:30 ` [PATCH v8 15/16] mm: make vma cache SLAB_TYPESAFE_BY_RCU Suren Baghdasaryan
2025-01-10 15:32 ` Vlastimil Babka
2025-01-10 16:07 ` Suren Baghdasaryan
2025-01-10 22:14 ` Vlastimil Babka
2025-01-11 3:37 ` Suren Baghdasaryan
2025-01-10 17:47 ` Liam R. Howlett
2025-01-10 19:07 ` Suren Baghdasaryan
2025-01-10 19:46 ` Liam R. Howlett
2025-01-10 20:34 ` Suren Baghdasaryan
2025-01-10 20:47 ` Liam R. Howlett
2025-01-10 21:32 ` Suren Baghdasaryan
2025-01-10 19:51 ` Liam R. Howlett
2025-01-10 20:40 ` Suren Baghdasaryan
2025-01-10 20:48 ` Liam R. Howlett
2025-01-09 2:30 ` [PATCH v8 16/16] docs/mm: document latest changes to vm_lock Suren Baghdasaryan
2025-01-09 2:32 ` [PATCH v8 00/16] move per-vma lock into vm_area_struct Suren Baghdasaryan
2025-01-09 11:51 ` Peter Zijlstra
2025-01-09 15:48 ` Suren Baghdasaryan
2025-01-10 17:01 ` Peter Zijlstra
2025-01-15 8:59 ` Peter Zijlstra
2025-01-09 13:41 ` Vlastimil Babka
2025-01-09 15:57 ` Suren Baghdasaryan
2025-01-10 0:14 ` Suren Baghdasaryan
2025-01-09 15:59 ` Suren Baghdasaryan
2025-01-10 0:16 ` Suren Baghdasaryan
2025-01-10 15:36 ` Vlastimil Babka
2025-01-10 16:08 ` 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=95e9d80e-6c19-4a1f-9c21-307006858dff@suse.cz \
--to=vbabka@suse.cz \
--cc=akpm@linux-foundation.org \
--cc=brauner@kernel.org \
--cc=corbet@lwn.net \
--cc=dave@stgolabs.net \
--cc=david@redhat.com \
--cc=dhowells@redhat.com \
--cc=hannes@cmpxchg.org \
--cc=hdanton@sina.com \
--cc=hughd@google.com \
--cc=jannh@google.com \
--cc=kernel-team@android.com \
--cc=klarasmodin@gmail.com \
--cc=liam.howlett@oracle.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=lokeshgidra@google.com \
--cc=lorenzo.stoakes@oracle.com \
--cc=mgorman@techsingularity.net \
--cc=mhocko@suse.com \
--cc=minchan@google.com \
--cc=mjguzik@gmail.com \
--cc=oleg@redhat.com \
--cc=oliver.sang@intel.com \
--cc=pasha.tatashin@soleen.com \
--cc=paulmck@kernel.org \
--cc=peterx@redhat.com \
--cc=peterz@infradead.org \
--cc=richard.weiyang@gmail.com \
--cc=shakeel.butt@linux.dev \
--cc=souravpanda@google.com \
--cc=surenb@google.com \
--cc=willy@infradead.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