[PATCH] zram: avoid doing zs_malloc() with direct reclaim within mutex
From: Barry Song (Xiaomi)
Date: Wed Aug 05 2026 - 05:53:49 EST
Signed-off-by: Barry Song (Xiaomi) <baohua@xxxxxxxxxx>
---
drivers/block/zram/zram_drv.c | 43 ++++++++++++++++++++++++++++-------
1 file changed, 35 insertions(+), 8 deletions(-)
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index cfa98846ac48..e00d896a101f 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -2218,6 +2218,35 @@ static int write_same_filled_page(struct zram *zram, unsigned long fill,
return 0;
}
+/*
+ * try non-sleepable allocation for !async backend, then try
+ * sleepable allocation; for async backend, we always begin
+ * from sleepable allocation
+ */
+static unsigned long zram_zs_malloc(struct zram *zram, struct zcomp_strm *zstrm,
+ size_t comp_len, const int nid, void **bounce)
+{
+ unsigned long handle;
+
+ handle = zs_malloc(zram->mem_pool, comp_len,
+ __GFP_KSWAPD_RECLAIM | __GFP_NOWARN |
+ __GFP_HIGHMEM | __GFP_MOVABLE, nid);
+ if (!IS_ERR_VALUE(handle))
+ return handle;
+
+ *bounce = kmalloc(comp_len, GFP_ATOMIC);
+ if (!*bounce)
+ return (unsigned long)ERR_PTR(-ENOMEM);
+ memcpy(*bounce, zstrm->buffer, comp_len);
+
+ /* Don't hold mutex to do a sleepable allocation */
+ zcomp_stream_put(zstrm);
+ handle = zs_malloc(zram->mem_pool, comp_len,
+ GFP_NOIO | __GFP_NOWARN |
+ __GFP_HIGHMEM | __GFP_MOVABLE, nid);
+ return handle;
+}
+
static int write_incompressible_page(struct zram *zram, struct page *page,
u32 index)
{
@@ -2264,7 +2293,7 @@ static int zram_write_page(struct zram *zram, struct page *page, u32 index)
int ret = 0;
unsigned long handle;
unsigned int comp_len;
- void *mem;
+ void *mem, *bounce = NULL;
struct zcomp_strm *zstrm;
unsigned long element;
bool same_filled;
@@ -2292,22 +2321,20 @@ static int zram_write_page(struct zram *zram, struct page *page, u32 index)
return write_incompressible_page(zram, page, index);
}
- handle = zs_malloc(zram->mem_pool, comp_len,
- GFP_NOIO | __GFP_NOWARN |
- __GFP_HIGHMEM | __GFP_MOVABLE, page_to_nid(page));
+ handle = zram_zs_malloc(zram, zstrm, comp_len, page_to_nid(page), &bounce);
if (IS_ERR_VALUE(handle)) {
- zcomp_stream_put(zstrm);
+ bounce ? kfree(bounce) : zcomp_stream_put(zstrm);
return PTR_ERR((void *)handle);
}
if (!zram_can_store_page(zram)) {
- zcomp_stream_put(zstrm);
+ bounce ? kfree(bounce) : zcomp_stream_put(zstrm);
zs_free(zram->mem_pool, handle);
return -ENOMEM;
}
- zs_obj_write(zram->mem_pool, handle, zstrm->buffer, comp_len);
- zcomp_stream_put(zstrm);
+ zs_obj_write(zram->mem_pool, handle, bounce ? : zstrm->buffer, comp_len);
+ bounce ? kfree(bounce) : zcomp_stream_put(zstrm);
slot_lock(zram, index);
slot_free(zram, index);
--
2.39.3 (Apple Git-146)