xfrm: use a dedicated slab cache for struct xfrm_state

struct xfrm_state is rather large (768 bytes here) and therefore wastes
quite a lot of memory as it falls into the kmalloc-1024 slab cache,
leaving 256 bytes of unused memory per XFRM state object -- a net waste
of 25%.

Using a dedicated slab cache for struct xfrm_state reduces the level of
internal fragmentation to a minimum.

On my configuration SLUB chooses to create a slab cache covering 4
pages holding 21 objects, resulting in an average memory waste of ~13
bytes per object -- a net waste of only 1.6%.

In my tests this led to memory savings of roughly 2.3MB for 10k XFRM
states.

Signed-off-by: Mathias Krause <minipli@googlemail.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
This commit is contained in:
Mathias Krause 2018-05-03 10:55:07 +02:00 committed by Steffen Klassert
parent 154a8c46ba
commit 565f0fa902

View File

@ -42,6 +42,7 @@ static void xfrm_state_gc_task(struct work_struct *work);
static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
static __read_mostly seqcount_t xfrm_state_hash_generation = SEQCNT_ZERO(xfrm_state_hash_generation); static __read_mostly seqcount_t xfrm_state_hash_generation = SEQCNT_ZERO(xfrm_state_hash_generation);
static struct kmem_cache *xfrm_state_cache __ro_after_init;
static DECLARE_WORK(xfrm_state_gc_work, xfrm_state_gc_task); static DECLARE_WORK(xfrm_state_gc_work, xfrm_state_gc_task);
static HLIST_HEAD(xfrm_state_gc_list); static HLIST_HEAD(xfrm_state_gc_list);
@ -451,7 +452,7 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x)
} }
xfrm_dev_state_free(x); xfrm_dev_state_free(x);
security_xfrm_state_free(x); security_xfrm_state_free(x);
kfree(x); kmem_cache_free(xfrm_state_cache, x);
} }
static void xfrm_state_gc_task(struct work_struct *work) static void xfrm_state_gc_task(struct work_struct *work)
@ -563,7 +564,7 @@ struct xfrm_state *xfrm_state_alloc(struct net *net)
{ {
struct xfrm_state *x; struct xfrm_state *x;
x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC); x = kmem_cache_alloc(xfrm_state_cache, GFP_ATOMIC | __GFP_ZERO);
if (x) { if (x) {
write_pnet(&x->xs_net, net); write_pnet(&x->xs_net, net);
@ -2307,6 +2308,10 @@ int __net_init xfrm_state_init(struct net *net)
{ {
unsigned int sz; unsigned int sz;
if (net_eq(net, &init_net))
xfrm_state_cache = KMEM_CACHE(xfrm_state,
SLAB_HWCACHE_ALIGN | SLAB_PANIC);
INIT_LIST_HEAD(&net->xfrm.state_all); INIT_LIST_HEAD(&net->xfrm.state_all);
sz = sizeof(struct hlist_head) * 8; sz = sizeof(struct hlist_head) * 8;