6464 if (!debug_locks_silent && \
6565 WARN_ONCE(c, "DEBUG_RWSEMS_WARN_ON(%s): count = 0x%lx, owner = 0x%lx, curr 0x%lx, list %sempty\n",\
6666 #c, atomic_long_read(&(sem)->count), \
67- (long)(( sem)->owner), (long)current, \
67+ atomic_long_read(&( sem)->owner), (long)current, \
6868 list_empty(&(sem)->wait_list) ? "" : "not ")) \
6969 debug_locks_off(); \
7070 } while (0)
114114 */
115115static inline void rwsem_set_owner (struct rw_semaphore * sem )
116116{
117- WRITE_ONCE ( sem -> owner , current );
117+ atomic_long_set ( & sem -> owner , ( long ) current );
118118}
119119
120120static inline void rwsem_clear_owner (struct rw_semaphore * sem )
121121{
122- WRITE_ONCE (sem -> owner , NULL );
122+ atomic_long_set (& sem -> owner , 0 );
123+ }
124+
125+ /*
126+ * Test the flags in the owner field.
127+ */
128+ static inline bool rwsem_test_oflags (struct rw_semaphore * sem , long flags )
129+ {
130+ return atomic_long_read (& sem -> owner ) & flags ;
123131}
124132
125133/*
@@ -133,10 +141,9 @@ static inline void rwsem_clear_owner(struct rw_semaphore *sem)
133141static inline void __rwsem_set_reader_owned (struct rw_semaphore * sem ,
134142 struct task_struct * owner )
135143{
136- unsigned long val = (unsigned long )owner | RWSEM_READER_OWNED
137- | RWSEM_NONSPINNABLE ;
144+ unsigned long val = (unsigned long )owner | RWSEM_READER_OWNED | RWSEM_NONSPINNABLE ;
138145
139- WRITE_ONCE ( sem -> owner , ( struct task_struct * ) val );
146+ atomic_long_set ( & sem -> owner , val );
140147}
141148
142149static inline void rwsem_set_reader_owned (struct rw_semaphore * sem )
@@ -145,13 +152,20 @@ static inline void rwsem_set_reader_owned(struct rw_semaphore *sem)
145152}
146153
147154/*
148- * Return true if the a rwsem waiter can spin on the rwsem's owner
149- * and steal the lock.
150- * N.B. !owner is considered spinnable.
155+ * Return true if the rwsem is owned by a reader.
151156 */
152- static inline bool is_rwsem_owner_spinnable (struct task_struct * owner )
157+ static inline bool is_rwsem_reader_owned (struct rw_semaphore * sem )
153158{
154- return !((unsigned long )owner & RWSEM_NONSPINNABLE );
159+ #ifdef CONFIG_DEBUG_RWSEMS
160+ /*
161+ * Check the count to see if it is write-locked.
162+ */
163+ long count = atomic_long_read (& sem -> count );
164+
165+ if (count & RWSEM_WRITER_MASK )
166+ return false;
167+ #endif
168+ return rwsem_test_oflags (sem , RWSEM_READER_OWNED );
155169}
156170
157171#ifdef CONFIG_DEBUG_RWSEMS
@@ -163,18 +177,42 @@ static inline bool is_rwsem_owner_spinnable(struct task_struct *owner)
163177 */
164178static inline void rwsem_clear_reader_owned (struct rw_semaphore * sem )
165179{
166- unsigned long val = (unsigned long )current | RWSEM_READER_OWNED
167- | RWSEM_NONSPINNABLE ;
168- if (READ_ONCE (sem -> owner ) == (struct task_struct * )val )
169- cmpxchg_relaxed ((unsigned long * )& sem -> owner , val ,
170- RWSEM_READER_OWNED | RWSEM_NONSPINNABLE );
180+ unsigned long val = atomic_long_read (& sem -> owner );
181+
182+ while ((val & ~RWSEM_OWNER_FLAGS_MASK ) == (unsigned long )current ) {
183+ if (atomic_long_try_cmpxchg (& sem -> owner , & val ,
184+ val & RWSEM_OWNER_FLAGS_MASK ))
185+ return ;
186+ }
171187}
172188#else
173189static inline void rwsem_clear_reader_owned (struct rw_semaphore * sem )
174190{
175191}
176192#endif
177193
194+ /*
195+ * Return just the real task structure pointer of the owner
196+ */
197+ static inline struct task_struct * rwsem_owner (struct rw_semaphore * sem )
198+ {
199+ return (struct task_struct * )
200+ (atomic_long_read (& sem -> owner ) & ~RWSEM_OWNER_FLAGS_MASK );
201+ }
202+
203+ /*
204+ * Return the real task structure pointer of the owner and the embedded
205+ * flags in the owner. pflags must be non-NULL.
206+ */
207+ static inline struct task_struct *
208+ rwsem_owner_flags (struct rw_semaphore * sem , unsigned long * pflags )
209+ {
210+ unsigned long owner = atomic_long_read (& sem -> owner );
211+
212+ * pflags = owner & RWSEM_OWNER_FLAGS_MASK ;
213+ return (struct task_struct * )(owner & ~RWSEM_OWNER_FLAGS_MASK );
214+ }
215+
178216/*
179217 * Guide to the rw_semaphore's count field.
180218 *
@@ -208,7 +246,7 @@ void __init_rwsem(struct rw_semaphore *sem, const char *name,
208246 atomic_long_set (& sem -> count , RWSEM_UNLOCKED_VALUE );
209247 raw_spin_lock_init (& sem -> wait_lock );
210248 INIT_LIST_HEAD (& sem -> wait_list );
211- sem -> owner = NULL ;
249+ atomic_long_set ( & sem -> owner , 0L ) ;
212250#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
213251 osq_lock_init (& sem -> osq );
214252#endif
@@ -511,9 +549,10 @@ static inline bool owner_on_cpu(struct task_struct *owner)
511549static inline bool rwsem_can_spin_on_owner (struct rw_semaphore * sem )
512550{
513551 struct task_struct * owner ;
552+ unsigned long flags ;
514553 bool ret = true;
515554
516- BUILD_BUG_ON (is_rwsem_owner_spinnable (RWSEM_OWNER_UNKNOWN ));
555+ BUILD_BUG_ON (! (RWSEM_OWNER_UNKNOWN & RWSEM_NONSPINNABLE ));
517556
518557 if (need_resched ()) {
519558 lockevent_inc (rwsem_opt_fail );
@@ -522,11 +561,9 @@ static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem)
522561
523562 preempt_disable ();
524563 rcu_read_lock ();
525- owner = READ_ONCE (sem -> owner );
526- if (owner ) {
527- ret = is_rwsem_owner_spinnable (owner ) &&
528- owner_on_cpu (owner );
529- }
564+ owner = rwsem_owner_flags (sem , & flags );
565+ if ((flags & RWSEM_NONSPINNABLE ) || (owner && !owner_on_cpu (owner )))
566+ ret = false;
530567 rcu_read_unlock ();
531568 preempt_enable ();
532569
@@ -553,25 +590,26 @@ enum owner_state {
553590};
554591#define OWNER_SPINNABLE (OWNER_NULL | OWNER_WRITER)
555592
556- static inline enum owner_state rwsem_owner_state (unsigned long owner )
593+ static inline enum owner_state
594+ rwsem_owner_state (struct task_struct * owner , unsigned long flags )
557595{
558- if (!owner )
559- return OWNER_NULL ;
560-
561- if (owner & RWSEM_NONSPINNABLE )
596+ if (flags & RWSEM_NONSPINNABLE )
562597 return OWNER_NONSPINNABLE ;
563598
564- if (owner & RWSEM_READER_OWNED )
599+ if (flags & RWSEM_READER_OWNED )
565600 return OWNER_READER ;
566601
567- return OWNER_WRITER ;
602+ return owner ? OWNER_WRITER : OWNER_NULL ;
568603}
569604
570605static noinline enum owner_state rwsem_spin_on_owner (struct rw_semaphore * sem )
571606{
572- struct task_struct * tmp , * owner = READ_ONCE (sem -> owner );
573- enum owner_state state = rwsem_owner_state ((unsigned long )owner );
607+ struct task_struct * new , * owner ;
608+ unsigned long flags , new_flags ;
609+ enum owner_state state ;
574610
611+ owner = rwsem_owner_flags (sem , & flags );
612+ state = rwsem_owner_state (owner , flags );
575613 if (state != OWNER_WRITER )
576614 return state ;
577615
@@ -582,9 +620,9 @@ static noinline enum owner_state rwsem_spin_on_owner(struct rw_semaphore *sem)
582620 break ;
583621 }
584622
585- tmp = READ_ONCE (sem -> owner );
586- if (tmp != owner ) {
587- state = rwsem_owner_state (( unsigned long ) tmp );
623+ new = rwsem_owner_flags (sem , & new_flags );
624+ if (( new != owner ) || ( new_flags != flags ) ) {
625+ state = rwsem_owner_state (new , new_flags );
588626 break ;
589627 }
590628
@@ -1001,8 +1039,7 @@ inline void __down_read(struct rw_semaphore *sem)
10011039 if (unlikely (atomic_long_fetch_add_acquire (RWSEM_READER_BIAS ,
10021040 & sem -> count ) & RWSEM_READ_FAILED_MASK )) {
10031041 rwsem_down_read_slowpath (sem , TASK_UNINTERRUPTIBLE );
1004- DEBUG_RWSEMS_WARN_ON (!((unsigned long )sem -> owner &
1005- RWSEM_READER_OWNED ), sem );
1042+ DEBUG_RWSEMS_WARN_ON (!is_rwsem_reader_owned (sem ), sem );
10061043 } else {
10071044 rwsem_set_reader_owned (sem );
10081045 }
@@ -1014,8 +1051,7 @@ static inline int __down_read_killable(struct rw_semaphore *sem)
10141051 & sem -> count ) & RWSEM_READ_FAILED_MASK )) {
10151052 if (IS_ERR (rwsem_down_read_slowpath (sem , TASK_KILLABLE )))
10161053 return - EINTR ;
1017- DEBUG_RWSEMS_WARN_ON (!((unsigned long )sem -> owner &
1018- RWSEM_READER_OWNED ), sem );
1054+ DEBUG_RWSEMS_WARN_ON (!is_rwsem_reader_owned (sem ), sem );
10191055 } else {
10201056 rwsem_set_reader_owned (sem );
10211057 }
@@ -1084,7 +1120,7 @@ inline void __up_read(struct rw_semaphore *sem)
10841120{
10851121 long tmp ;
10861122
1087- DEBUG_RWSEMS_WARN_ON (!(( unsigned long ) sem -> owner & RWSEM_READER_OWNED ), sem );
1123+ DEBUG_RWSEMS_WARN_ON (!is_rwsem_reader_owned ( sem ), sem );
10881124 rwsem_clear_reader_owned (sem );
10891125 tmp = atomic_long_add_return_release (- RWSEM_READER_BIAS , & sem -> count );
10901126 if (unlikely ((tmp & (RWSEM_LOCK_MASK |RWSEM_FLAG_WAITERS )) ==
@@ -1103,8 +1139,8 @@ static inline void __up_write(struct rw_semaphore *sem)
11031139 * sem->owner may differ from current if the ownership is transferred
11041140 * to an anonymous writer by setting the RWSEM_NONSPINNABLE bits.
11051141 */
1106- DEBUG_RWSEMS_WARN_ON ((sem -> owner != current ) &&
1107- !(( long ) sem -> owner & RWSEM_NONSPINNABLE ), sem );
1142+ DEBUG_RWSEMS_WARN_ON ((rwsem_owner ( sem ) != current ) &&
1143+ !rwsem_test_oflags ( sem , RWSEM_NONSPINNABLE ), sem );
11081144 rwsem_clear_owner (sem );
11091145 tmp = atomic_long_fetch_add_release (- RWSEM_WRITER_LOCKED , & sem -> count );
11101146 if (unlikely (tmp & RWSEM_FLAG_WAITERS ))
@@ -1125,7 +1161,7 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
11251161 * read-locked region is ok to be re-ordered into the
11261162 * write side. As such, rely on RELEASE semantics.
11271163 */
1128- DEBUG_RWSEMS_WARN_ON (sem -> owner != current , sem );
1164+ DEBUG_RWSEMS_WARN_ON (rwsem_owner ( sem ) != current , sem );
11291165 tmp = atomic_long_fetch_add_release (
11301166 - RWSEM_WRITER_LOCKED + RWSEM_READER_BIAS , & sem -> count );
11311167 rwsem_set_reader_owned (sem );
@@ -1296,8 +1332,7 @@ EXPORT_SYMBOL(down_write_killable_nested);
12961332
12971333void up_read_non_owner (struct rw_semaphore * sem )
12981334{
1299- DEBUG_RWSEMS_WARN_ON (!((unsigned long )sem -> owner & RWSEM_READER_OWNED ),
1300- sem );
1335+ DEBUG_RWSEMS_WARN_ON (!is_rwsem_reader_owned (sem ), sem );
13011336 __up_read (sem );
13021337}
13031338EXPORT_SYMBOL (up_read_non_owner );
0 commit comments