mirror of https://github.com/torvalds/linux.git
slab: allow NUMA restricted allocations to use percpu sheaves
Currently allocations asking for a specific node explicitly or via mempolicy in strict_numa node bypass percpu sheaves. Since sheaves contain mostly local objects, we can try allocating from them if the local node happens to be the requested node or allowed by the mempolicy. If we find the object from percpu sheaves is not from the expected node, we skip the sheaves - this should be rare. Reviewed-by: Harry Yoo <harry.yoo@oracle.com> Reviewed-by: Suren Baghdasaryan <surenb@google.com> Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
This commit is contained in:
parent
989b09b739
commit
4ec1a08d20
53
mm/slub.c
53
mm/slub.c
|
|
@ -4882,18 +4882,43 @@ __pcs_replace_empty_main(struct kmem_cache *s, struct slub_percpu_sheaves *pcs,
|
||||||
}
|
}
|
||||||
|
|
||||||
static __fastpath_inline
|
static __fastpath_inline
|
||||||
void *alloc_from_pcs(struct kmem_cache *s, gfp_t gfp)
|
void *alloc_from_pcs(struct kmem_cache *s, gfp_t gfp, int node)
|
||||||
{
|
{
|
||||||
struct slub_percpu_sheaves *pcs;
|
struct slub_percpu_sheaves *pcs;
|
||||||
|
bool node_requested;
|
||||||
void *object;
|
void *object;
|
||||||
|
|
||||||
#ifdef CONFIG_NUMA
|
#ifdef CONFIG_NUMA
|
||||||
if (static_branch_unlikely(&strict_numa)) {
|
if (static_branch_unlikely(&strict_numa) &&
|
||||||
if (current->mempolicy)
|
node == NUMA_NO_NODE) {
|
||||||
return NULL;
|
|
||||||
|
struct mempolicy *mpol = current->mempolicy;
|
||||||
|
|
||||||
|
if (mpol) {
|
||||||
|
/*
|
||||||
|
* Special BIND rule support. If the local node
|
||||||
|
* is in permitted set then do not redirect
|
||||||
|
* to a particular node.
|
||||||
|
* Otherwise we apply the memory policy to get
|
||||||
|
* the node we need to allocate on.
|
||||||
|
*/
|
||||||
|
if (mpol->mode != MPOL_BIND ||
|
||||||
|
!node_isset(numa_mem_id(), mpol->nodes))
|
||||||
|
|
||||||
|
node = mempolicy_slab_node();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
node_requested = IS_ENABLED(CONFIG_NUMA) && node != NUMA_NO_NODE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We assume the percpu sheaves contain only local objects although it's
|
||||||
|
* not completely guaranteed, so we verify later.
|
||||||
|
*/
|
||||||
|
if (unlikely(node_requested && node != numa_mem_id()))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (!local_trylock(&s->cpu_sheaves->lock))
|
if (!local_trylock(&s->cpu_sheaves->lock))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
@ -4905,7 +4930,21 @@ void *alloc_from_pcs(struct kmem_cache *s, gfp_t gfp)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
object = pcs->main->objects[--pcs->main->size];
|
object = pcs->main->objects[pcs->main->size - 1];
|
||||||
|
|
||||||
|
if (unlikely(node_requested)) {
|
||||||
|
/*
|
||||||
|
* Verify that the object was from the node we want. This could
|
||||||
|
* be false because of cpu migration during an unlocked part of
|
||||||
|
* the current allocation or previous freeing process.
|
||||||
|
*/
|
||||||
|
if (folio_nid(virt_to_folio(object)) != node) {
|
||||||
|
local_unlock(&s->cpu_sheaves->lock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pcs->main->size--;
|
||||||
|
|
||||||
local_unlock(&s->cpu_sheaves->lock);
|
local_unlock(&s->cpu_sheaves->lock);
|
||||||
|
|
||||||
|
|
@ -5005,8 +5044,8 @@ static __fastpath_inline void *slab_alloc_node(struct kmem_cache *s, struct list
|
||||||
if (unlikely(object))
|
if (unlikely(object))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (s->cpu_sheaves && node == NUMA_NO_NODE)
|
if (s->cpu_sheaves)
|
||||||
object = alloc_from_pcs(s, gfpflags);
|
object = alloc_from_pcs(s, gfpflags, node);
|
||||||
|
|
||||||
if (!object)
|
if (!object)
|
||||||
object = __slab_alloc_node(s, gfpflags, node, addr, orig_size);
|
object = __slab_alloc_node(s, gfpflags, node, addr, orig_size);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue