Re: [RFC PATCH] zram: avoid preemption with CPU-based compression backends

"Barry Song (Xiaomi)" <[email protected]>
Newsgroups gmane.linux.kernel,gmane.linux.kernel.mm
Message-ID <[email protected]>
On Wed, Aug 5, 2026 at 3:50 PM Barry Song <[email protected]> wrote:
>
> On Wed, Aug 5, 2026 at 1:21 PM Sergey Senozhatsky
> <[email protected]> wrote:
> >
> > Hi Barry,
> >
> > On (26/08/05 17:09), Barry Song wrote:
> > > > > This report shows that the zram mutex has become the top lock
> > > > > contributing to UI frame drops, even surpassing mmap_lock, which we
> > > > > are also addressing in multiple threads. :-)
> > > >
> > > > Any chance you can share more details?  Are there perhaps RT tasks
> > > > in the mix, priority inversion, starvations and so on?  Can proxy
> > > > execution address any of those (if it has relevance to the report
> > > > you are looking at)?
> > >
> > > Hi Sergey,
> > >
> > > talked with our engineers reporting the issue. i believe it is all
> > > about priority inversion.
> > > proxy execution wont resolve it as we have a sleepable zs-malloc
> > > within the mutex.
> > >  i believe i need v2 to release the mutex before doing the 2nd stage
> > > zs_malloc with
> > > direct reclaim.
> >
> > Well, we cannot just drop the stream mutex and do sleepable zsmalloc
> > allocation, because this will invalidate compression buffer.  So we
> > then will need to do re-compression.  Something that I was really
> > happy to drop [1].
>
> We used to do that by an temp GFP_ATOMIC buffer and memcpy:
> https://lore.kernel.org/all/[email protected]/
>
> As long as we copy `zstrm->buffer` to a temporary buffer, we are
> free to go anywhere afterwards.
>

Hi Sergey,

Just as a proof of concept, I changed one path and it seems to work.
We release the mutex before calling zs_malloc(), which may enter
direct reclaim, and we no longer need the mutex afterwards.
also, we can avoid re-compression:

From d1a4cbe63fc2f7336c23bc268b1dffe15b0e7444 Mon Sep 17 00:00:00 2001
From: "Barry Song (Xiaomi)" <[email protected]>
Date: Wed, 5 Aug 2026 17:53:49 +0800
Subject: [PATCH] zram: avoid doing zs_malloc() with direct reclaim within
 mutex

Signed-off-by: Barry Song (Xiaomi) <[email protected]>
---
 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)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.