58 lines
2.1 KiB
Diff
58 lines
2.1 KiB
Diff
From: Anna-Maria Gleixner <anna-maria@linutronix.de>
|
|
Date: Fri, 4 May 2018 17:45:29 +0200
|
|
Subject: [PATCH 1/3] spinlock: atomic_dec_and_lock: Add an irqsave variant
|
|
|
|
There are in-tree users of atomic_dec_and_lock() which must acquire the
|
|
spin lock with interrupts disabled. To workaround the lack of an irqsave
|
|
variant of atomic_dec_and_lock() they use local_irq_save() at the call
|
|
site. This causes extra code and creates in some places unneeded long
|
|
interrupt disabled times. These places need also extra treatment for
|
|
PREEMPT_RT due to the disconnect of the irq disabling and the lock
|
|
function.
|
|
|
|
Implement the missing irqsave variant of the function.
|
|
|
|
Signed-off-by: Anna-Maria Gleixner <anna-maria@linutronix.de>
|
|
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
|
---
|
|
include/linux/spinlock.h | 5 +++++
|
|
lib/dec_and_lock.c | 16 ++++++++++++++++
|
|
2 files changed, 21 insertions(+)
|
|
|
|
--- a/include/linux/spinlock.h
|
|
+++ b/include/linux/spinlock.h
|
|
@@ -409,6 +409,11 @@ extern int _atomic_dec_and_lock(atomic_t
|
|
#define atomic_dec_and_lock(atomic, lock) \
|
|
__cond_lock(lock, _atomic_dec_and_lock(atomic, lock))
|
|
|
|
+extern int _atomic_dec_and_lock_irqsave(atomic_t *atomic, spinlock_t *lock,
|
|
+ unsigned long *flags);
|
|
+#define atomic_dec_and_lock_irqsave(atomic, lock, flags) \
|
|
+ __cond_lock(lock, _atomic_dec_and_lock_irqsave(atomic, lock, &(flags)))
|
|
+
|
|
int alloc_bucket_spinlocks(spinlock_t **locks, unsigned int *lock_mask,
|
|
size_t max_size, unsigned int cpu_mult,
|
|
gfp_t gfp);
|
|
--- a/lib/dec_and_lock.c
|
|
+++ b/lib/dec_and_lock.c
|
|
@@ -33,3 +33,19 @@ int _atomic_dec_and_lock(atomic_t *atomi
|
|
}
|
|
|
|
EXPORT_SYMBOL(_atomic_dec_and_lock);
|
|
+
|
|
+int _atomic_dec_and_lock_irqsave(atomic_t *atomic, spinlock_t *lock,
|
|
+ unsigned long *flags)
|
|
+{
|
|
+ /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */
|
|
+ if (atomic_add_unless(atomic, -1, 1))
|
|
+ return 0;
|
|
+
|
|
+ /* Otherwise do it the slow way */
|
|
+ spin_lock_irqsave(lock, *flags);
|
|
+ if (atomic_dec_and_test(atomic))
|
|
+ return 1;
|
|
+ spin_unlock_irqrestore(lock, *flags);
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(_atomic_dec_and_lock_irqsave);
|