Skip to content

Commit 7cdacc5

Browse files
Yanfei XuPeter Zijlstra
authored andcommitted
locking/rwsem: Disable preemption for spinning region
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 <[email protected]> [peterz: Fix CONFIG_RWSEM_SPIN_ON_OWNER=n build] Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Acked-by: Waiman Long <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent bc67f1c commit 7cdacc5

File tree

1 file changed

+30
-23
lines changed

1 file changed

+30
-23
lines changed

kernel/locking/rwsem.c

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,24 @@ static inline bool rwsem_try_write_lock(struct rw_semaphore *sem,
577577
return true;
578578
}
579579

580+
/*
581+
* The rwsem_spin_on_owner() function returns the following 4 values
582+
* depending on the lock owner state.
583+
* OWNER_NULL : owner is currently NULL
584+
* OWNER_WRITER: when owner changes and is a writer
585+
* OWNER_READER: when owner changes and the new owner may be a reader.
586+
* OWNER_NONSPINNABLE:
587+
* when optimistic spinning has to stop because either the
588+
* owner stops running, is unknown, or its timeslice has
589+
* been used up.
590+
*/
591+
enum owner_state {
592+
OWNER_NULL = 1 << 0,
593+
OWNER_WRITER = 1 << 1,
594+
OWNER_READER = 1 << 2,
595+
OWNER_NONSPINNABLE = 1 << 3,
596+
};
597+
580598
#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
581599
/*
582600
* Try to acquire write lock before the writer has been put on wait queue.
@@ -632,23 +650,6 @@ static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem)
632650
return ret;
633651
}
634652

635-
/*
636-
* The rwsem_spin_on_owner() function returns the following 4 values
637-
* depending on the lock owner state.
638-
* OWNER_NULL : owner is currently NULL
639-
* OWNER_WRITER: when owner changes and is a writer
640-
* OWNER_READER: when owner changes and the new owner may be a reader.
641-
* OWNER_NONSPINNABLE:
642-
* when optimistic spinning has to stop because either the
643-
* owner stops running, is unknown, or its timeslice has
644-
* been used up.
645-
*/
646-
enum owner_state {
647-
OWNER_NULL = 1 << 0,
648-
OWNER_WRITER = 1 << 1,
649-
OWNER_READER = 1 << 2,
650-
OWNER_NONSPINNABLE = 1 << 3,
651-
};
652653
#define OWNER_SPINNABLE (OWNER_NULL | OWNER_WRITER | OWNER_READER)
653654

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

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

881-
static inline int
882+
static inline enum owner_state
882883
rwsem_spin_on_owner(struct rw_semaphore *sem)
883884
{
884-
return 0;
885+
return OWNER_NONSPINNABLE;
885886
}
886-
#define OWNER_NULL 1
887887
#endif
888888

889889
/*
@@ -1095,9 +1095,16 @@ rwsem_down_write_slowpath(struct rw_semaphore *sem, int state)
10951095
* In this case, we attempt to acquire the lock again
10961096
* without sleeping.
10971097
*/
1098-
if (wstate == WRITER_HANDOFF &&
1099-
rwsem_spin_on_owner(sem) == OWNER_NULL)
1100-
goto trylock_again;
1098+
if (wstate == WRITER_HANDOFF) {
1099+
enum owner_state owner_state;
1100+
1101+
preempt_disable();
1102+
owner_state = rwsem_spin_on_owner(sem);
1103+
preempt_enable();
1104+
1105+
if (owner_state == OWNER_NULL)
1106+
goto trylock_again;
1107+
}
11011108

11021109
/* Block until there are no active lockers. */
11031110
for (;;) {

0 commit comments

Comments
 (0)