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>
This commit is contained in:
Thomas Gleixner 2014-10-31 10:54:36 -04:00 committed by Alibek Omarov
parent 1d1230719a
commit 3126470072
2 changed files with 38 additions and 3 deletions

View File

@ -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

View File

@ -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, void *ptr, int starting_id, int *id)
}
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;