diff --git a/include/sys/zstd/zstd.h b/include/sys/zstd/zstd.h index f965df3198..e42e44c236 100644 --- a/include/sys/zstd/zstd.h +++ b/include/sys/zstd/zstd.h @@ -90,6 +90,7 @@ int zfs_zstd_decompress_level(void *s_start, void *d_start, size_t s_len, size_t d_len, uint8_t *level); int zfs_zstd_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len, int n); +void zfs_zstd_cache_reap_now(void); #ifdef __cplusplus } diff --git a/module/zfs/arc.c b/module/zfs/arc.c index 1cce068e65..c54d53908e 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -308,6 +308,7 @@ #include #include #include +#include #ifndef _KERNEL /* set with ZFS_DEBUG=watch, to enable watchpoints on frozen buffers */ @@ -4972,6 +4973,7 @@ static boolean_t arc_reap_cb_check(void *arg, zthr_t *zthr) { int64_t free_memory = arc_available_memory(); + static int reap_cb_check_counter = 0; /* * If a kmem reap is already active, don't schedule more. We must @@ -4996,6 +4998,14 @@ arc_reap_cb_check(void *arg, zthr_t *zthr) arc_no_grow = B_FALSE; } + /* + * Called unconditionally every 60 seconds to reclaim unused + * zstd compression and decompression context. This is done + * here to avoid the need for an independent thread. + */ + if (!((reap_cb_check_counter++) % 60)) + zfs_zstd_cache_reap_now(); + return (B_FALSE); } diff --git a/module/zstd/zfs_zstd.c b/module/zstd/zfs_zstd.c index c10b7a84d6..34c56b7a7f 100644 --- a/module/zstd/zfs_zstd.c +++ b/module/zstd/zfs_zstd.c @@ -238,7 +238,7 @@ zstd_mempool_alloc(struct zstd_pool *zstd_mempool, size_t size) * Check if objects fits the size, if so we take it and * update the timestamp. */ - if (!mem && pool->mem && size <= pool->size) { + if (size && !mem && pool->mem && size <= pool->size) { pool->timeout = gethrestime_sec() + ZSTD_POOL_TIMEOUT; mem = pool->mem; @@ -257,7 +257,7 @@ zstd_mempool_alloc(struct zstd_pool *zstd_mempool, size_t size) } } - if (mem) { + if (!size || mem) { return (mem); } @@ -688,6 +688,19 @@ zstd_mempool_deinit(void) zstd_mempool_cctx = NULL; } +/* release unused memory from pool */ + +void +zfs_zstd_cache_reap_now(void) +{ + /* + * calling alloc with zero size seeks + * and releases old unused objects + */ + zstd_mempool_alloc(zstd_mempool_cctx, 0); + zstd_mempool_alloc(zstd_mempool_dctx, 0); +} + extern int __init zstd_init(void) { @@ -735,4 +748,5 @@ ZFS_MODULE_VERSION(ZSTD_VERSION_STRING); EXPORT_SYMBOL(zfs_zstd_compress); EXPORT_SYMBOL(zfs_zstd_decompress_level); EXPORT_SYMBOL(zfs_zstd_decompress); +EXPORT_SYMBOL(zfs_zstd_cache_reap_now); #endif