Add a localtry_trylock() variant without _irqsave that will be used in slab sheaves implementation. Thanks to only disabling preemption and not irqs, it has a lower overhead. It's not necessary to disable irqs to avoid a deadlock if the irq context uses trylock and can handle failures. Also make the comment of localtry_trylock_irqsave() more clear, and fix a compilation failure in localtry_lock_init(). Signed-off-by: Vlastimil Babka <vbabka@xxxxxxx> --- include/linux/local_lock.h | 13 +++++++++++- include/linux/local_lock_internal.h | 31 +++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/include/linux/local_lock.h b/include/linux/local_lock.h index 05c254a5d7d3..1a0bc35839e3 100644 --- a/include/linux/local_lock.h +++ b/include/linux/local_lock.h @@ -77,6 +77,16 @@ #define localtry_lock_irqsave(lock, flags) \ __localtry_lock_irqsave(lock, flags) +/** + * localtry_trylock - Try to acquire a per CPU local lock. + * @lock: The lock variable + * + * The function can be used in any context such as NMI or HARDIRQ. Due to + * locking constrains it will _always_ fail to acquire the lock in NMI or + * HARDIRQ context on PREEMPT_RT. + */ +#define localtry_trylock(lock) __localtry_trylock(lock) + /** * localtry_trylock_irqsave - Try to acquire a per CPU local lock, save and disable * interrupts if acquired @@ -84,7 +94,8 @@ * @flags: Storage for interrupt flags * * The function can be used in any context such as NMI or HARDIRQ. Due to - * locking constrains it will _always_ fail to acquire the lock on PREEMPT_RT. + * locking constrains it will _always_ fail to acquire the lock in NMI or + * HARDIRQ context on PREEMPT_RT. */ #define localtry_trylock_irqsave(lock, flags) \ __localtry_trylock_irqsave(lock, flags) diff --git a/include/linux/local_lock_internal.h b/include/linux/local_lock_internal.h index c1369b300777..67bd13d142fa 100644 --- a/include/linux/local_lock_internal.h +++ b/include/linux/local_lock_internal.h @@ -137,7 +137,7 @@ do { \ #define __localtry_lock_init(lock) \ do { \ __local_lock_init(&(lock)->llock); \ - WRITE_ONCE(&(lock)->acquired, 0); \ + WRITE_ONCE((lock)->acquired, 0); \ } while (0) #define __localtry_lock(lock) \ @@ -167,6 +167,24 @@ do { \ WRITE_ONCE(lt->acquired, 1); \ } while (0) +#define __localtry_trylock(lock) \ + ({ \ + localtry_lock_t *lt; \ + bool _ret; \ + \ + preempt_disable(); \ + lt = this_cpu_ptr(lock); \ + if (!READ_ONCE(lt->acquired)) { \ + WRITE_ONCE(lt->acquired, 1); \ + local_trylock_acquire(<->llock); \ + _ret = true; \ + } else { \ + _ret = false; \ + preempt_enable(); \ + } \ + _ret; \ + }) + #define __localtry_trylock_irqsave(lock, flags) \ ({ \ localtry_lock_t *lt; \ @@ -275,12 +293,10 @@ do { \ #define __localtry_unlock_irq(lock) __local_unlock(lock) #define __localtry_unlock_irqrestore(lock, flags) __local_unlock_irqrestore(lock, flags) -#define __localtry_trylock_irqsave(lock, flags) \ +#define __localtry_trylock(lock) \ ({ \ int __locked; \ \ - typecheck(unsigned long, flags); \ - flags = 0; \ if (in_nmi() | in_hardirq()) { \ __locked = 0; \ } else { \ @@ -292,4 +308,11 @@ do { \ __locked; \ }) +#define __localtry_trylock_irqsave(lock, flags) \ + ({ \ + typecheck(unsigned long, flags); \ + flags = 0; \ + __localtry_trylock(lock); \ + }) + #endif /* CONFIG_PREEMPT_RT */ -- 2.48.1