| From: Thomas Gleixner <tglx@linutronix.de> |
| Subject: idr: Use local lock instead of preempt enable/disable |
| |
| We need to protect the per cpu variable and prevent migration. |
| |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| --- |
| include/linux/idr.h | 4 ++++ |
| lib/idr.c | 37 ++++++++++++++++++++++++++++++++++--- |
| 2 files changed, 38 insertions(+), 3 deletions(-) |
| |
| --- a/include/linux/idr.h |
| +++ b/include/linux/idr.h |
| @@ -92,10 +92,14 @@ void idr_init(struct idr *idp); |
| * Each idr_preload() should be matched with an invocation of this |
| * function. See idr_preload() for details. |
| */ |
| +#ifdef CONFIG_PREEMPT_RT_FULL |
| +void idr_preload_end(void); |
| +#else |
| static inline void idr_preload_end(void) |
| { |
| preempt_enable(); |
| } |
| +#endif |
| |
| /** |
| * idr_find - return pointer for given id |
| --- a/lib/idr.c |
| +++ b/lib/idr.c |
| @@ -37,6 +37,7 @@ |
| #include <linux/spinlock.h> |
| #include <linux/percpu.h> |
| #include <linux/hardirq.h> |
| +#include <linux/locallock.h> |
| |
| #define MAX_IDR_SHIFT (sizeof(int) * 8 - 1) |
| #define MAX_IDR_BIT (1U << MAX_IDR_SHIFT) |
| @@ -389,6 +390,36 @@ int __idr_get_new_above(struct idr *idp, |
| } |
| EXPORT_SYMBOL(__idr_get_new_above); |
| |
| +#ifdef CONFIG_PREEMPT_RT_FULL |
| +static DEFINE_LOCAL_IRQ_LOCK(idr_lock); |
| + |
| +static inline void idr_preload_lock(void) |
| +{ |
| + local_lock(idr_lock); |
| +} |
| + |
| +static inline void idr_preload_unlock(void) |
| +{ |
| + local_unlock(idr_lock); |
| +} |
| + |
| +void idr_preload_end(void) |
| +{ |
| + idr_preload_unlock(); |
| +} |
| +EXPORT_SYMBOL(idr_preload_end); |
| +#else |
| +static inline void idr_preload_lock(void) |
| +{ |
| + preempt_disable(); |
| +} |
| + |
| +static inline void idr_preload_unlock(void) |
| +{ |
| + preempt_enable(); |
| +} |
| +#endif |
| + |
| /** |
| * idr_preload - preload for idr_alloc() |
| * @gfp_mask: allocation mask to use for preloading |
| @@ -423,7 +454,7 @@ void idr_preload(gfp_t gfp_mask) |
| WARN_ON_ONCE(in_interrupt()); |
| might_sleep_if(gfp_mask & __GFP_WAIT); |
| |
| - preempt_disable(); |
| + idr_preload_lock(); |
| |
| /* |
| * idr_alloc() is likely to succeed w/o full idr_layer buffer and |
| @@ -435,9 +466,9 @@ void idr_preload(gfp_t gfp_mask) |
| while (__this_cpu_read(idr_preload_cnt) < MAX_IDR_FREE) { |
| struct idr_layer *new; |
| |
| - preempt_enable(); |
| + idr_preload_unlock(); |
| new = kmem_cache_zalloc(idr_layer_cache, gfp_mask); |
| - preempt_disable(); |
| + idr_preload_lock(); |
| if (!new) |
| break; |
| |