When a dictionary is configured, zstd allocates all of its memory (C/D dictionaries, compression and decompression contexts and compression workspaces) via zstd_custom_alloc(). zstd_custom_alloc() uses kvzalloc(), which falls back to vmalloc() only when kmalloc() fails, and kmalloc() rounds such sizes up to a power-of-two number of pages. For example, on x86_64 with a 110K dictionary, switching from kvzalloc() to __vmalloc() reduces allocations from: - CDict (level 3): 512 KB -> 400 KB - CDict (levels 12+): 2048 KB -> 1552 KB - DCtx (per-CPU): 128 KB -> 96 KB - CCtx workspace (level 3): 128 KB -> 84 KB (per-CPU) - CCtx workspace (level 14+): 1024 KB -> 764 KB (per-CPU) Use __vmalloc() for allocations larger than PAGE_SIZE (and kzalloc() for smaller ones), which is also how zram allocates zstd workspaces when no dictionary is configured. zstd_custom_free() already uses kvfree(), which handles both. Acked-by: Brian Geffon Signed-off-by: Sergey Senozhatsky --- drivers/block/zram/backend_zstd.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/block/zram/backend_zstd.c b/drivers/block/zram/backend_zstd.c index b367049f131d..7a8b5ff186f2 100644 --- a/drivers/block/zram/backend_zstd.c +++ b/drivers/block/zram/backend_zstd.c @@ -26,10 +26,17 @@ struct zstd_params { /* * For C/D dictionaries we need to provide zstd with zstd_custom_mem, * which zstd uses internally to allocate/free memory when needed. + * + * zstd allocations (C/D dictionaries and contexts) are large and + * long-lived. Don't use kvzalloc() for them: when enough physically + * contiguous memory is available it serves them from kmalloc(), which + * rounds them up to a power-of-two number of pages. */ static void *zstd_custom_alloc(void *opaque, size_t size) { - return kvzalloc(size, GFP_NOIO | __GFP_NOWARN); + if (size <= PAGE_SIZE) + return kzalloc(size, GFP_NOIO | __GFP_NOWARN); + return __vmalloc(size, GFP_NOIO | __GFP_NOWARN | __GFP_ZERO); } static void zstd_custom_free(void *opaque, void *address) -- 2.56.0.385.gd3acb90ef8-goog