idr: idr_alloc() shouldn't trigger lowmem warning when preloaded
GFP_NOIO is often used for idr_alloc() inside preloaded section as the allocation mask doesn't really matter. If the idr tree needs to be expanded, idr_alloc() first tries to allocate using the specified allocation mask and if it fails falls back to the preloaded buffer. This order prevent non-preloading idr_alloc() users from taking advantage of preloading ones by using preload buffer without filling it shifting the burden of allocation to the preload users. Unfortunately, this allowed/expected-to-fail kmem_cache allocation ends up generating spurious slab lowmem warning before succeeding the request from the preload buffer. This patch makes idr_layer_alloc() add __GFP_NOWARN to the first kmem_cache attempt and try kmem_cache again w/o __GFP_NOWARN after allocation from preload_buffer fails so that lowmem warning is generated if not suppressed by the original @gfp_mask. Signed-off-by: Tejun Heo <tj@kernel.org> Reported-by: David Teigland <teigland@redhat.com> Tested-by: David Teigland <teigland@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
415586c9e6
commit
59bfbcf019
22
lib/idr.c
22
lib/idr.c
@ -106,8 +106,14 @@ static struct idr_layer *idr_layer_alloc(gfp_t gfp_mask, struct idr *layer_idr)
|
|||||||
if (layer_idr)
|
if (layer_idr)
|
||||||
return get_from_free_list(layer_idr);
|
return get_from_free_list(layer_idr);
|
||||||
|
|
||||||
/* try to allocate directly from kmem_cache */
|
/*
|
||||||
new = kmem_cache_zalloc(idr_layer_cache, gfp_mask);
|
* Try to allocate directly from kmem_cache. We want to try this
|
||||||
|
* before preload buffer; otherwise, non-preloading idr_alloc()
|
||||||
|
* users will end up taking advantage of preloading ones. As the
|
||||||
|
* following is allowed to fail for preloaded cases, suppress
|
||||||
|
* warning this time.
|
||||||
|
*/
|
||||||
|
new = kmem_cache_zalloc(idr_layer_cache, gfp_mask | __GFP_NOWARN);
|
||||||
if (new)
|
if (new)
|
||||||
return new;
|
return new;
|
||||||
|
|
||||||
@ -115,9 +121,7 @@ static struct idr_layer *idr_layer_alloc(gfp_t gfp_mask, struct idr *layer_idr)
|
|||||||
* Try to fetch one from the per-cpu preload buffer if in process
|
* Try to fetch one from the per-cpu preload buffer if in process
|
||||||
* context. See idr_preload() for details.
|
* context. See idr_preload() for details.
|
||||||
*/
|
*/
|
||||||
if (in_interrupt())
|
if (!in_interrupt()) {
|
||||||
return NULL;
|
|
||||||
|
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
new = __this_cpu_read(idr_preload_head);
|
new = __this_cpu_read(idr_preload_head);
|
||||||
if (new) {
|
if (new) {
|
||||||
@ -126,9 +130,17 @@ static struct idr_layer *idr_layer_alloc(gfp_t gfp_mask, struct idr *layer_idr)
|
|||||||
new->ary[0] = NULL;
|
new->ary[0] = NULL;
|
||||||
}
|
}
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
|
if (new)
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Both failed. Try kmem_cache again w/o adding __GFP_NOWARN so
|
||||||
|
* that memory allocation failure warning is printed as intended.
|
||||||
|
*/
|
||||||
|
return kmem_cache_zalloc(idr_layer_cache, gfp_mask);
|
||||||
|
}
|
||||||
|
|
||||||
static void idr_layer_rcu_free(struct rcu_head *head)
|
static void idr_layer_rcu_free(struct rcu_head *head)
|
||||||
{
|
{
|
||||||
struct idr_layer *layer;
|
struct idr_layer *layer;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user