[Devel] [PATCH VZ9 2/2] dm-qcow2: add memory pool for compression buffers
Pavel Tikhomirov
ptikhomirov at virtuozzo.com
Mon Nov 18 08:54:16 MSK 2024
We see high order allocation warnings:
kernel: order 10 >= 10, gfp 0x40c00
kernel: WARNING: CPU: 5 PID: 182 at mm/page_alloc.c:5630 __alloc_pages+0x1d7/0x3f0
kernel: process_compressed_read+0x6f/0x590 [dm_qcow2]
This is because we have 1M clusters and in case of zstd compression the
buffer size used for decompression is (clu_size + sizeof(ZSTD_DCtx) +
ZSTD_BLOCKSIZE_MAX + clu_size + ZSTD_BLOCKSIZE_MAX + 64 = 2520776) which
requires 4M allocation.
This is a really big allocation especially for io path (GFP_NOIO), and
it has very high probability to fail.
Let's fix it by making a memory pool for such 4M allocations.
note: I'm not fully sure that num_possible_cpus is enough minimal size
for this pool as if any code path in process_compressed_read can
schedule then for one cpu we might require two or more allocations from
the pool. At least for now I don't see any schedule there. Anyway, it
would only lead those excess process_compressed_read to schedule and
wait for buffers to be released, so it should not be that bad.
https://virtuozzo.atlassian.net/browse/VSTOR-94596
Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
---
drivers/md/dm-qcow2-map.c | 18 ++++++++++++++----
drivers/md/dm-qcow2-target.c | 18 ++++++++++++++++--
2 files changed, 30 insertions(+), 6 deletions(-)
diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c
index 6585f3fac6e7b..c60ba9f341c26 100644
--- a/drivers/md/dm-qcow2-map.c
+++ b/drivers/md/dm-qcow2-map.c
@@ -10,6 +10,7 @@
#include <linux/zlib.h>
#include <linux/error-injection.h>
#include <linux/zstd.h>
+#include <linux/sizes.h>
#include "dm.h"
#include "dm-rq.h"
@@ -3650,6 +3651,8 @@ static int complete_metadata_writeback(struct qcow2 *qcow2)
return fsync_ret;
}
+extern mempool_t *zbuf_pool;
+
/* Process completed compressed READs */
static void process_compressed_read(struct qcow2 *qcow2, struct list_head *read_list,
struct list_head *cow_list)
@@ -3671,7 +3674,10 @@ static void process_compressed_read(struct qcow2 *qcow2, struct list_head *read_
dctxlen = zlib_inflate_workspacesize();
- buf = kmalloc(qcow2->clu_size + dctxlen, GFP_NOIO);
+ if (qcow2->clu_size + dctxlen <= SZ_4M)
+ buf = mempool_alloc(zbuf_pool, GFP_NOIO);
+ else
+ buf = kmalloc(qcow2->clu_size + dctxlen, GFP_NOIO);
if (!buf) {
end_qios(read_list, BLK_STS_RESOURCE);
return;
@@ -3681,8 +3687,7 @@ static void process_compressed_read(struct qcow2 *qcow2, struct list_head *read_
arg = zstd_init_dstream(qcow2->clu_size, buf + qcow2->clu_size, dctxlen);
if (!arg) {
end_qios(read_list, BLK_STS_RESOURCE);
- kfree(buf);
- return;
+ goto err_free;
}
} else {
arg = buf + qcow2->clu_size;
@@ -3716,7 +3721,12 @@ static void process_compressed_read(struct qcow2 *qcow2, struct list_head *read_
list_add_tail(&qio->link, cow_list);
}
- kfree(buf);
+err_free:
+ if (qcow2->clu_size + dctxlen <= SZ_4M)
+ mempool_free(buf, zbuf_pool);
+ else
+ kfree(buf);
+ return;
}
static int prepare_sliced_data_write(struct qcow2 *qcow2, struct qio *qio,
diff --git a/drivers/md/dm-qcow2-target.c b/drivers/md/dm-qcow2-target.c
index 276eab9acc4f3..a323bd2747af6 100644
--- a/drivers/md/dm-qcow2-target.c
+++ b/drivers/md/dm-qcow2-target.c
@@ -7,6 +7,8 @@
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/error-injection.h>
+#include <linux/cpumask.h>
+#include <linux/sizes.h>
#include "dm.h"
#include "dm-qcow2.h"
@@ -1036,6 +1038,8 @@ static struct target_type qcow2_target = {
.llseek_hole = qcow2_llseek_hole,
};
+mempool_t *zbuf_pool = NULL;
+
static int __init dm_qcow2_init(void)
{
int ret;
@@ -1046,14 +1050,24 @@ static int __init dm_qcow2_init(void)
return -ENOMEM;
ret = dm_register_target(&qcow2_target);
- if (ret)
+ if (ret) {
kmem_cache_destroy(qrq_cache);
+ return ret;
+ }
- return ret;
+ zbuf_pool = mempool_create_kvmalloc_pool(num_possible_cpus(), SZ_4M);
+ if (!zbuf_pool) {
+ dm_unregister_target(&qcow2_target);
+ kmem_cache_destroy(qrq_cache);
+ return -ENOMEM;
+ }
+
+ return 0;
}
static void __exit dm_qcow2_exit(void)
{
+ mempool_destroy(zbuf_pool);
dm_unregister_target(&qcow2_target);
kmem_cache_destroy(qrq_cache);
}
--
2.47.0
More information about the Devel
mailing list