Re: [tip: locking/core] locking/rwsem: Remove the list_head from struct rw_semaphore
From: Andrei Vagin
Date: Fri Mar 13 2026 - 20:05:19 EST
On Mon, Mar 9, 2026 at 12:48 PM tip-bot2 for Matthew Wilcox (Oracle)
<tip-bot2@xxxxxxxxxxxxx> wrote:
>
> The following commit has been merged into the locking/core branch of tip:
>
> Commit-ID: 1ea4b473504b6dc6a0d21c298519aff2d52433c9
> Gitweb: https://git.kernel.org/tip/1ea4b473504b6dc6a0d21c298519aff2d52433c9
> Author: Matthew Wilcox (Oracle) <willy@xxxxxxxxxxxxx>
> AuthorDate: Thu, 05 Mar 2026 19:55:41
> Committer: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
> CommitterDate: Sun, 08 Mar 2026 11:06:51 +01:00
>
> locking/rwsem: Remove the list_head from struct rw_semaphore
>
> Instead of embedding a list_head in struct rw_semaphore, store a pointer
> to the first waiter. The list of waiters remains a doubly linked list
> so we can efficiently add to the tail of the list, remove from the front
> (or middle) of the list.
>
> Some of the list manipulation becomes more complicated, but it's a
> reasonable tradeoff on the slow paths to shrink some core data structures
> like struct inode.
>
> Signed-off-by: Matthew Wilcox (Oracle) <willy@xxxxxxxxxxxxx>
> Signed-off-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx>
> Link: https://patch.msgid.link/20260305195545.3707590-2-willy@xxxxxxxxxxxxx
> ---
> include/linux/rwsem.h | 8 ++--
> kernel/locking/rwsem.c | 90 ++++++++++++++++++++++++++---------------
> 2 files changed, 62 insertions(+), 36 deletions(-)
>
...
> -static inline void
> -rwsem_add_waiter(struct rw_semaphore *sem, struct rwsem_waiter *waiter)
> +static inline
> +bool __rwsem_del_waiter(struct rw_semaphore *sem, struct rwsem_waiter *waiter)
> {
> - lockdep_assert_held(&sem->wait_lock);
> - list_add_tail(&waiter->list, &sem->wait_list);
> - /* caller will set RWSEM_FLAG_WAITERS */
> + if (list_empty(&waiter->list)) {
> + sem->first_waiter = NULL;
> + return true;
> + }
> +
> + if (sem->first_waiter == waiter) {
> + sem->first_waiter = list_first_entry(&waiter->list,
> + struct rwsem_waiter, list);
> + }
> + list_del(&waiter->list);
> +
> + return false;
> }
>
> /*
> @@ -385,14 +392,23 @@ static inline bool
> rwsem_del_waiter(struct rw_semaphore *sem, struct rwsem_waiter *waiter)
> {
> lockdep_assert_held(&sem->wait_lock);
> - list_del(&waiter->list);
> - if (likely(!list_empty(&sem->wait_list)))
> + if (__rwsem_del_waiter(sem, waiter))
__rwsem_del_waiter() returns true when the wait list becomes empty.
rwsem_del_waiter() is supposed to return true if the wait list is not empty...
> return true;
> -
> atomic_long_andnot(RWSEM_FLAG_HANDOFF | RWSEM_FLAG_WAITERS, &sem->count);
> return false;
> }
Thanks,
Andrei