Skip to content

Commit 02f1082

Browse files
Waiman-LongIngo Molnar
authored andcommitted
locking/rwsem: Clarify usage of owner's nonspinaable bit
Bit 1 of sem->owner (RWSEM_ANONYMOUSLY_OWNED) is used to designate an anonymous owner - readers or an anonymous writer. The setting of this anonymous bit is used as an indicator that optimistic spinning cannot be done on this rwsem. With the upcoming reader optimistic spinning patches, a reader-owned rwsem can be spinned on for a limit period of time. We still need this bit to indicate a rwsem is nonspinnable, but not setting this bit loses its meaning that the owner is known. So rename the bit to RWSEM_NONSPINNABLE to clarify its meaning. This patch also fixes a DEBUG_RWSEMS_WARN_ON() bug in __up_write(). Signed-off-by: Waiman Long <longman@redhat.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Davidlohr Bueso <dave@stgolabs.net> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Tim Chen <tim.c.chen@linux.intel.com> Cc: Will Deacon <will.deacon@arm.com> Cc: huang ying <huang.ying.caritas@gmail.com> Link: https://lkml.kernel.org/r/20190520205918.22251-12-longman@redhat.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
1 parent d3681e2 commit 02f1082

File tree

2 files changed

+22
-23
lines changed

2 files changed

+22
-23
lines changed

include/linux/rwsem.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ struct rw_semaphore {
5050
};
5151

5252
/*
53-
* Setting bit 1 of the owner field but not bit 0 will indicate
53+
* Setting all bits of the owner field except bit 0 will indicate
5454
* that the rwsem is writer-owned with an unknown owner.
5555
*/
5656
#define RWSEM_OWNER_UNKNOWN ((struct task_struct *)-2L)

kernel/locking/rwsem.c

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,18 @@
3333
/*
3434
* The least significant 2 bits of the owner value has the following
3535
* meanings when set.
36-
* - RWSEM_READER_OWNED (bit 0): The rwsem is owned by readers
37-
* - RWSEM_ANONYMOUSLY_OWNED (bit 1): The rwsem is anonymously owned,
38-
* i.e. the owner(s) cannot be readily determined. It can be reader
39-
* owned or the owning writer is indeterminate.
36+
* - Bit 0: RWSEM_READER_OWNED - The rwsem is owned by readers
37+
* - Bit 1: RWSEM_NONSPINNABLE - Waiters cannot spin on the rwsem
38+
* The rwsem is anonymously owned, i.e. the owner(s) cannot be
39+
* readily determined. It can be reader owned or the owning writer
40+
* is indeterminate.
4041
*
4142
* When a writer acquires a rwsem, it puts its task_struct pointer
4243
* into the owner field. It is cleared after an unlock.
4344
*
4445
* When a reader acquires a rwsem, it will also puts its task_struct
4546
* pointer into the owner field with both the RWSEM_READER_OWNED and
46-
* RWSEM_ANONYMOUSLY_OWNED bits set. On unlock, the owner field will
47+
* RWSEM_NONSPINNABLE bits set. On unlock, the owner field will
4748
* largely be left untouched. So for a free or reader-owned rwsem,
4849
* the owner value may contain information about the last reader that
4950
* acquires the rwsem. The anonymous bit is set because that particular
@@ -55,7 +56,8 @@
5556
* a rwsem, but the overhead is simply too big.
5657
*/
5758
#define RWSEM_READER_OWNED (1UL << 0)
58-
#define RWSEM_ANONYMOUSLY_OWNED (1UL << 1)
59+
#define RWSEM_NONSPINNABLE (1UL << 1)
60+
#define RWSEM_OWNER_FLAGS_MASK (RWSEM_READER_OWNED | RWSEM_NONSPINNABLE)
5961

6062
#ifdef CONFIG_DEBUG_RWSEMS
6163
# define DEBUG_RWSEMS_WARN_ON(c, sem) do { \
@@ -132,7 +134,7 @@ static inline void __rwsem_set_reader_owned(struct rw_semaphore *sem,
132134
struct task_struct *owner)
133135
{
134136
unsigned long val = (unsigned long)owner | RWSEM_READER_OWNED
135-
| RWSEM_ANONYMOUSLY_OWNED;
137+
| RWSEM_NONSPINNABLE;
136138

137139
WRITE_ONCE(sem->owner, (struct task_struct *)val);
138140
}
@@ -144,20 +146,12 @@ static inline void rwsem_set_reader_owned(struct rw_semaphore *sem)
144146

145147
/*
146148
* Return true if the a rwsem waiter can spin on the rwsem's owner
147-
* and steal the lock, i.e. the lock is not anonymously owned.
149+
* and steal the lock.
148150
* N.B. !owner is considered spinnable.
149151
*/
150152
static inline bool is_rwsem_owner_spinnable(struct task_struct *owner)
151153
{
152-
return !((unsigned long)owner & RWSEM_ANONYMOUSLY_OWNED);
153-
}
154-
155-
/*
156-
* Return true if rwsem is owned by an anonymous writer or readers.
157-
*/
158-
static inline bool rwsem_has_anonymous_owner(struct task_struct *owner)
159-
{
160-
return (unsigned long)owner & RWSEM_ANONYMOUSLY_OWNED;
154+
return !((unsigned long)owner & RWSEM_NONSPINNABLE);
161155
}
162156

163157
#ifdef CONFIG_DEBUG_RWSEMS
@@ -170,10 +164,10 @@ static inline bool rwsem_has_anonymous_owner(struct task_struct *owner)
170164
static inline void rwsem_clear_reader_owned(struct rw_semaphore *sem)
171165
{
172166
unsigned long val = (unsigned long)current | RWSEM_READER_OWNED
173-
| RWSEM_ANONYMOUSLY_OWNED;
167+
| RWSEM_NONSPINNABLE;
174168
if (READ_ONCE(sem->owner) == (struct task_struct *)val)
175169
cmpxchg_relaxed((unsigned long *)&sem->owner, val,
176-
RWSEM_READER_OWNED | RWSEM_ANONYMOUSLY_OWNED);
170+
RWSEM_READER_OWNED | RWSEM_NONSPINNABLE);
177171
}
178172
#else
179173
static inline void rwsem_clear_reader_owned(struct rw_semaphore *sem)
@@ -495,7 +489,7 @@ static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem)
495489
struct task_struct *owner;
496490
bool ret = true;
497491

498-
BUILD_BUG_ON(!rwsem_has_anonymous_owner(RWSEM_OWNER_UNKNOWN));
492+
BUILD_BUG_ON(is_rwsem_owner_spinnable(RWSEM_OWNER_UNKNOWN));
499493

500494
if (need_resched())
501495
return false;
@@ -534,7 +528,7 @@ static inline enum owner_state rwsem_owner_state(unsigned long owner)
534528
if (!owner)
535529
return OWNER_NULL;
536530

537-
if (owner & RWSEM_ANONYMOUSLY_OWNED)
531+
if (owner & RWSEM_NONSPINNABLE)
538532
return OWNER_NONSPINNABLE;
539533

540534
if (owner & RWSEM_READER_OWNED)
@@ -1043,7 +1037,12 @@ static inline void __up_write(struct rw_semaphore *sem)
10431037
{
10441038
long tmp;
10451039

1046-
DEBUG_RWSEMS_WARN_ON(sem->owner != current, sem);
1040+
/*
1041+
* sem->owner may differ from current if the ownership is transferred
1042+
* to an anonymous writer by setting the RWSEM_NONSPINNABLE bits.
1043+
*/
1044+
DEBUG_RWSEMS_WARN_ON((sem->owner != current) &&
1045+
!((long)sem->owner & RWSEM_NONSPINNABLE), sem);
10471046
rwsem_clear_owner(sem);
10481047
tmp = atomic_long_fetch_add_release(-RWSEM_WRITER_LOCKED, &sem->count);
10491048
if (unlikely(tmp & RWSEM_FLAG_WAITERS))

0 commit comments

Comments
 (0)