Skip to content

Commit

Permalink
locking/rwsem: Disable preemption for spinning region
Browse files Browse the repository at this point in the history
[ Upstream commit 7cdacc5 ]

The spinning region rwsem_spin_on_owner() should not be preempted,
however the rwsem_down_write_slowpath() invokes it and don't disable
preemption. Fix it by adding a pair of preempt_disable/enable().

Signed-off-by: Yanfei Xu <yanfei.xu@windriver.com>
[peterz: Fix CONFIG_RWSEM_SPIN_ON_OWNER=n build]
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Waiman Long <longman@redhat.com>
Link: https://lore.kernel.org/r/20211013134154.1085649-3-yanfei.xu@windriver.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Yanfei Xu authored and gregkh committed Nov 18, 2021
1 parent e5d5e53 commit 562d350
Showing 1 changed file with 30 additions and 23 deletions.
53 changes: 30 additions & 23 deletions kernel/locking/rwsem.c
Expand Up @@ -577,6 +577,24 @@ static inline bool rwsem_try_write_lock(struct rw_semaphore *sem,
return true;
}

/*
* The rwsem_spin_on_owner() function returns the following 4 values
* depending on the lock owner state.
* OWNER_NULL : owner is currently NULL
* OWNER_WRITER: when owner changes and is a writer
* OWNER_READER: when owner changes and the new owner may be a reader.
* OWNER_NONSPINNABLE:
* when optimistic spinning has to stop because either the
* owner stops running, is unknown, or its timeslice has
* been used up.
*/
enum owner_state {
OWNER_NULL = 1 << 0,
OWNER_WRITER = 1 << 1,
OWNER_READER = 1 << 2,
OWNER_NONSPINNABLE = 1 << 3,
};

#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
/*
* Try to acquire write lock before the writer has been put on wait queue.
Expand Down Expand Up @@ -632,23 +650,6 @@ static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem)
return ret;
}

/*
* The rwsem_spin_on_owner() function returns the following 4 values
* depending on the lock owner state.
* OWNER_NULL : owner is currently NULL
* OWNER_WRITER: when owner changes and is a writer
* OWNER_READER: when owner changes and the new owner may be a reader.
* OWNER_NONSPINNABLE:
* when optimistic spinning has to stop because either the
* owner stops running, is unknown, or its timeslice has
* been used up.
*/
enum owner_state {
OWNER_NULL = 1 << 0,
OWNER_WRITER = 1 << 1,
OWNER_READER = 1 << 2,
OWNER_NONSPINNABLE = 1 << 3,
};
#define OWNER_SPINNABLE (OWNER_NULL | OWNER_WRITER | OWNER_READER)

static inline enum owner_state
Expand Down Expand Up @@ -878,12 +879,11 @@ static inline bool rwsem_optimistic_spin(struct rw_semaphore *sem)

static inline void clear_nonspinnable(struct rw_semaphore *sem) { }

static inline int
static inline enum owner_state
rwsem_spin_on_owner(struct rw_semaphore *sem)
{
return 0;
return OWNER_NONSPINNABLE;
}
#define OWNER_NULL 1
#endif

/*
Expand Down Expand Up @@ -1095,9 +1095,16 @@ rwsem_down_write_slowpath(struct rw_semaphore *sem, int state)
* In this case, we attempt to acquire the lock again
* without sleeping.
*/
if (wstate == WRITER_HANDOFF &&
rwsem_spin_on_owner(sem) == OWNER_NULL)
goto trylock_again;
if (wstate == WRITER_HANDOFF) {
enum owner_state owner_state;

preempt_disable();
owner_state = rwsem_spin_on_owner(sem);
preempt_enable();

if (owner_state == OWNER_NULL)
goto trylock_again;
}

/* Block until there are no active lockers. */
for (;;) {
Expand Down

0 comments on commit 562d350

Please sign in to comment.