Skip to content

Commit 6e649d0

Browse files
committed
Merge tag 'locking-core-2023-02-20' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull locking updates from Ingo Molnar: - rwsem micro-optimizations - spinlock micro-optimizations - cleanups, simplifications * tag 'locking-core-2023-02-20' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: vduse: Remove include of rwlock.h locking/lockdep: Remove lockdep_init_map_crosslock. x86/ACPI/boot: Use try_cmpxchg() in __acpi_{acquire,release}_global_lock() x86/PAT: Use try_cmpxchg() in set_page_memtype() locking/rwsem: Disable preemption in all down_write*() and up_write() code paths locking/rwsem: Disable preemption in all down_read*() and up_read() code paths locking/rwsem: Prevent non-first waiter from spinning in down_write() slowpath locking/qspinlock: Micro-optimize pending state waiting for unlock
2 parents db77b85 + 3b4863f commit 6e649d0

File tree

6 files changed

+64
-49
lines changed

6 files changed

+64
-49
lines changed

arch/x86/kernel/acpi/boot.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1840,23 +1840,23 @@ early_param("acpi_sci", setup_acpi_sci);
18401840

18411841
int __acpi_acquire_global_lock(unsigned int *lock)
18421842
{
1843-
unsigned int old, new, val;
1843+
unsigned int old, new;
1844+
1845+
old = READ_ONCE(*lock);
18441846
do {
1845-
old = *lock;
18461847
new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1));
1847-
val = cmpxchg(lock, old, new);
1848-
} while (unlikely (val != old));
1848+
} while (!try_cmpxchg(lock, &old, new));
18491849
return ((new & 0x3) < 3) ? -1 : 0;
18501850
}
18511851

18521852
int __acpi_release_global_lock(unsigned int *lock)
18531853
{
1854-
unsigned int old, new, val;
1854+
unsigned int old, new;
1855+
1856+
old = READ_ONCE(*lock);
18551857
do {
1856-
old = *lock;
18571858
new = old & ~0x3;
1858-
val = cmpxchg(lock, old, new);
1859-
} while (unlikely (val != old));
1859+
} while (!try_cmpxchg(lock, &old, new));
18601860
return old & 0x1;
18611861
}
18621862

arch/x86/mm/pat/memtype.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,10 @@ static inline void set_page_memtype(struct page *pg,
159159
break;
160160
}
161161

162+
old_flags = READ_ONCE(pg->flags);
162163
do {
163-
old_flags = pg->flags;
164164
new_flags = (old_flags & _PGMT_CLEAR_MASK) | memtype_flags;
165-
} while (cmpxchg(&pg->flags, old_flags, new_flags) != old_flags);
165+
} while (!try_cmpxchg(&pg->flags, &old_flags, new_flags));
166166
}
167167
#else
168168
static inline enum page_cache_mode get_page_memtype(struct page *pg)

drivers/vdpa/vdpa_user/iova_domain.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include <linux/iova.h>
1515
#include <linux/dma-mapping.h>
1616
#include <linux/vhost_iotlb.h>
17-
#include <linux/rwlock.h>
1817

1918
#define IOVA_START_PFN 1
2019

include/linux/lockdep.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,6 @@ enum xhlock_context_t {
435435
XHLOCK_CTX_NR,
436436
};
437437

438-
#define lockdep_init_map_crosslock(m, n, k, s) do {} while (0)
439438
/*
440439
* To initialize a lockdep_map statically use this macro.
441440
* Note that _name must not be NULL.

kernel/locking/qspinlock.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ void __lockfunc queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
371371
/*
372372
* We're pending, wait for the owner to go away.
373373
*
374-
* 0,1,1 -> 0,1,0
374+
* 0,1,1 -> *,1,0
375375
*
376376
* this wait loop must be a load-acquire such that we match the
377377
* store-release that clears the locked bit and create lock
@@ -380,7 +380,7 @@ void __lockfunc queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
380380
* barriers.
381381
*/
382382
if (val & _Q_LOCKED_MASK)
383-
atomic_cond_read_acquire(&lock->val, !(VAL & _Q_LOCKED_MASK));
383+
smp_cond_load_acquire(&lock->locked, !VAL);
384384

385385
/*
386386
* take ownership and clear the pending bit.

kernel/locking/rwsem.c

Lines changed: 52 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -256,16 +256,13 @@ static inline bool rwsem_read_trylock(struct rw_semaphore *sem, long *cntp)
256256
static inline bool rwsem_write_trylock(struct rw_semaphore *sem)
257257
{
258258
long tmp = RWSEM_UNLOCKED_VALUE;
259-
bool ret = false;
260259

261-
preempt_disable();
262260
if (atomic_long_try_cmpxchg_acquire(&sem->count, &tmp, RWSEM_WRITER_LOCKED)) {
263261
rwsem_set_owner(sem);
264-
ret = true;
262+
return true;
265263
}
266264

267-
preempt_enable();
268-
return ret;
265+
return false;
269266
}
270267

271268
/*
@@ -624,18 +621,16 @@ static inline bool rwsem_try_write_lock(struct rw_semaphore *sem,
624621
*/
625622
if (first->handoff_set && (waiter != first))
626623
return false;
627-
628-
/*
629-
* First waiter can inherit a previously set handoff
630-
* bit and spin on rwsem if lock acquisition fails.
631-
*/
632-
if (waiter == first)
633-
waiter->handoff_set = true;
634624
}
635625

636626
new = count;
637627

638628
if (count & RWSEM_LOCK_MASK) {
629+
/*
630+
* A waiter (first or not) can set the handoff bit
631+
* if it is an RT task or wait in the wait queue
632+
* for too long.
633+
*/
639634
if (has_handoff || (!rt_task(waiter->task) &&
640635
!time_after(jiffies, waiter->timeout)))
641636
return false;
@@ -651,11 +646,12 @@ static inline bool rwsem_try_write_lock(struct rw_semaphore *sem,
651646
} while (!atomic_long_try_cmpxchg_acquire(&sem->count, &count, new));
652647

653648
/*
654-
* We have either acquired the lock with handoff bit cleared or
655-
* set the handoff bit.
649+
* We have either acquired the lock with handoff bit cleared or set
650+
* the handoff bit. Only the first waiter can have its handoff_set
651+
* set here to enable optimistic spinning in slowpath loop.
656652
*/
657653
if (new & RWSEM_FLAG_HANDOFF) {
658-
waiter->handoff_set = true;
654+
first->handoff_set = true;
659655
lockevent_inc(rwsem_wlock_handoff);
660656
return false;
661657
}
@@ -717,7 +713,6 @@ static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem)
717713
return false;
718714
}
719715

720-
preempt_disable();
721716
/*
722717
* Disable preemption is equal to the RCU read-side crital section,
723718
* thus the task_strcut structure won't go away.
@@ -729,7 +724,6 @@ static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem)
729724
if ((flags & RWSEM_NONSPINNABLE) ||
730725
(owner && !(flags & RWSEM_READER_OWNED) && !owner_on_cpu(owner)))
731726
ret = false;
732-
preempt_enable();
733727

734728
lockevent_cond_inc(rwsem_opt_fail, !ret);
735729
return ret;
@@ -829,8 +823,6 @@ static bool rwsem_optimistic_spin(struct rw_semaphore *sem)
829823
int loop = 0;
830824
u64 rspin_threshold = 0;
831825

832-
preempt_disable();
833-
834826
/* sem->wait_lock should not be held when doing optimistic spinning */
835827
if (!osq_lock(&sem->osq))
836828
goto done;
@@ -938,7 +930,6 @@ static bool rwsem_optimistic_spin(struct rw_semaphore *sem)
938930
}
939931
osq_unlock(&sem->osq);
940932
done:
941-
preempt_enable();
942933
lockevent_cond_inc(rwsem_opt_fail, !taken);
943934
return taken;
944935
}
@@ -1092,7 +1083,7 @@ rwsem_down_read_slowpath(struct rw_semaphore *sem, long count, unsigned int stat
10921083
/* Ordered by sem->wait_lock against rwsem_mark_wake(). */
10931084
break;
10941085
}
1095-
schedule();
1086+
schedule_preempt_disabled();
10961087
lockevent_inc(rwsem_sleep_reader);
10971088
}
10981089

@@ -1179,15 +1170,12 @@ rwsem_down_write_slowpath(struct rw_semaphore *sem, int state)
11791170
if (waiter.handoff_set) {
11801171
enum owner_state owner_state;
11811172

1182-
preempt_disable();
11831173
owner_state = rwsem_spin_on_owner(sem);
1184-
preempt_enable();
1185-
11861174
if (owner_state == OWNER_NULL)
11871175
goto trylock_again;
11881176
}
11891177

1190-
schedule();
1178+
schedule_preempt_disabled();
11911179
lockevent_inc(rwsem_sleep_writer);
11921180
set_current_state(state);
11931181
trylock_again:
@@ -1254,14 +1242,20 @@ static struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem)
12541242
*/
12551243
static inline int __down_read_common(struct rw_semaphore *sem, int state)
12561244
{
1245+
int ret = 0;
12571246
long count;
12581247

1248+
preempt_disable();
12591249
if (!rwsem_read_trylock(sem, &count)) {
1260-
if (IS_ERR(rwsem_down_read_slowpath(sem, count, state)))
1261-
return -EINTR;
1250+
if (IS_ERR(rwsem_down_read_slowpath(sem, count, state))) {
1251+
ret = -EINTR;
1252+
goto out;
1253+
}
12621254
DEBUG_RWSEMS_WARN_ON(!is_rwsem_reader_owned(sem), sem);
12631255
}
1264-
return 0;
1256+
out:
1257+
preempt_enable();
1258+
return ret;
12651259
}
12661260

12671261
static inline void __down_read(struct rw_semaphore *sem)
@@ -1281,32 +1275,39 @@ static inline int __down_read_killable(struct rw_semaphore *sem)
12811275

12821276
static inline int __down_read_trylock(struct rw_semaphore *sem)
12831277
{
1278+
int ret = 0;
12841279
long tmp;
12851280

12861281
DEBUG_RWSEMS_WARN_ON(sem->magic != sem, sem);
12871282

1283+
preempt_disable();
12881284
tmp = atomic_long_read(&sem->count);
12891285
while (!(tmp & RWSEM_READ_FAILED_MASK)) {
12901286
if (atomic_long_try_cmpxchg_acquire(&sem->count, &tmp,
12911287
tmp + RWSEM_READER_BIAS)) {
12921288
rwsem_set_reader_owned(sem);
1293-
return 1;
1289+
ret = 1;
1290+
break;
12941291
}
12951292
}
1296-
return 0;
1293+
preempt_enable();
1294+
return ret;
12971295
}
12981296

12991297
/*
13001298
* lock for writing
13011299
*/
13021300
static inline int __down_write_common(struct rw_semaphore *sem, int state)
13031301
{
1302+
int ret = 0;
1303+
1304+
preempt_disable();
13041305
if (unlikely(!rwsem_write_trylock(sem))) {
13051306
if (IS_ERR(rwsem_down_write_slowpath(sem, state)))
1306-
return -EINTR;
1307+
ret = -EINTR;
13071308
}
1308-
1309-
return 0;
1309+
preempt_enable();
1310+
return ret;
13101311
}
13111312

13121313
static inline void __down_write(struct rw_semaphore *sem)
@@ -1321,8 +1322,14 @@ static inline int __down_write_killable(struct rw_semaphore *sem)
13211322

13221323
static inline int __down_write_trylock(struct rw_semaphore *sem)
13231324
{
1325+
int ret;
1326+
1327+
preempt_disable();
13241328
DEBUG_RWSEMS_WARN_ON(sem->magic != sem, sem);
1325-
return rwsem_write_trylock(sem);
1329+
ret = rwsem_write_trylock(sem);
1330+
preempt_enable();
1331+
1332+
return ret;
13261333
}
13271334

13281335
/*
@@ -1335,6 +1342,7 @@ static inline void __up_read(struct rw_semaphore *sem)
13351342
DEBUG_RWSEMS_WARN_ON(sem->magic != sem, sem);
13361343
DEBUG_RWSEMS_WARN_ON(!is_rwsem_reader_owned(sem), sem);
13371344

1345+
preempt_disable();
13381346
rwsem_clear_reader_owned(sem);
13391347
tmp = atomic_long_add_return_release(-RWSEM_READER_BIAS, &sem->count);
13401348
DEBUG_RWSEMS_WARN_ON(tmp < 0, sem);
@@ -1343,6 +1351,7 @@ static inline void __up_read(struct rw_semaphore *sem)
13431351
clear_nonspinnable(sem);
13441352
rwsem_wake(sem);
13451353
}
1354+
preempt_enable();
13461355
}
13471356

13481357
/*
@@ -1363,9 +1372,9 @@ static inline void __up_write(struct rw_semaphore *sem)
13631372
preempt_disable();
13641373
rwsem_clear_owner(sem);
13651374
tmp = atomic_long_fetch_add_release(-RWSEM_WRITER_LOCKED, &sem->count);
1366-
preempt_enable();
13671375
if (unlikely(tmp & RWSEM_FLAG_WAITERS))
13681376
rwsem_wake(sem);
1377+
preempt_enable();
13691378
}
13701379

13711380
/*
@@ -1383,11 +1392,13 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
13831392
* write side. As such, rely on RELEASE semantics.
13841393
*/
13851394
DEBUG_RWSEMS_WARN_ON(rwsem_owner(sem) != current, sem);
1395+
preempt_disable();
13861396
tmp = atomic_long_fetch_add_release(
13871397
-RWSEM_WRITER_LOCKED+RWSEM_READER_BIAS, &sem->count);
13881398
rwsem_set_reader_owned(sem);
13891399
if (tmp & RWSEM_FLAG_WAITERS)
13901400
rwsem_downgrade_wake(sem);
1401+
preempt_enable();
13911402
}
13921403

13931404
#else /* !CONFIG_PREEMPT_RT */
@@ -1662,6 +1673,12 @@ void down_read_non_owner(struct rw_semaphore *sem)
16621673
{
16631674
might_sleep();
16641675
__down_read(sem);
1676+
/*
1677+
* The owner value for a reader-owned lock is mostly for debugging
1678+
* purpose only and is not critical to the correct functioning of
1679+
* rwsem. So it is perfectly fine to set it in a preempt-enabled
1680+
* context here.
1681+
*/
16651682
__rwsem_set_reader_owned(sem, NULL);
16661683
}
16671684
EXPORT_SYMBOL(down_read_non_owner);

0 commit comments

Comments
 (0)