zram: convert to SG-list zsmalloc object read API

Patch series "zsmallc: remove old object read API".

zram remains the only user of old zsmalloc object read API.  This series
removes the old API and converts zram to use the new SG-list based API.


This patch (of 2):

zram remains the last user of old zsmalloc object read API, that performed
linearisation on the zsmalloc side.  There is a new SG-list API, that has
a bunch of benefits.  Switch zram to SG-list zsmalloc object read API.

Link: https://lore.kernel.org/20260907105739.1793316-1-senozhatsky@chromium.org
Link: https://lore.kernel.org/20260907105739.1793316-2-senozhatsky@chromium.org
Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Nhat Pham <nphamcs@gmail.com>
This commit is contained in:
Sergey Senozhatsky 2026-09-07 19:57:28 +09:00 committed by Andrew Morton
parent cc500013c8
commit 803f6a03f2
3 changed files with 55 additions and 28 deletions

View File

@ -7,6 +7,8 @@
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/cpuhotplug.h>
#include <linux/highmem.h>
#include <linux/scatterlist.h>
#include <linux/vmalloc.h>
#include <linux/sysfs.h>
@ -158,17 +160,32 @@ int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
}
int zcomp_decompress(struct zcomp *comp, struct zcomp_strm *zstrm,
const void *src, unsigned int src_len, void *dst)
struct scatterlist *sg, unsigned int src_len, void *dst)
{
struct zcomp_req req = {
.src = src,
.dst = dst,
.src_len = src_len,
.dst_len = PAGE_SIZE,
};
void *src = NULL;
int ret;
might_sleep();
return comp->ops->decompress(comp->params, &zstrm->ctx, &req);
if (sg_is_last(sg)) {
/* the object is contained within one page, read it in-place */
src = kmap_local_page(sg_page(sg));
req.src = src + sg->offset;
} else {
/* the object spans two pages, linearize it into local copy */
sg_copy_to_buffer(sg, 2, zstrm->local_copy, src_len);
req.src = zstrm->local_copy;
}
ret = comp->ops->decompress(comp->params, &zstrm->ctx, &req);
if (src)
kunmap_local(src);
return ret;
}
int zcomp_cpu_up_prepare(unsigned int cpu, struct hlist_node *node)

View File

@ -5,6 +5,8 @@
#include <linux/mutex.h>
struct scatterlist;
#define ZCOMP_PARAM_NOT_SET INT_MIN
struct deflate_params {
@ -91,6 +93,6 @@ void zcomp_stream_put(struct zcomp_strm *zstrm);
int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
const void *src, unsigned int *dst_len);
int zcomp_decompress(struct zcomp *comp, struct zcomp_strm *zstrm,
const void *src, unsigned int src_len, void *dst);
struct scatterlist *sg, unsigned int src_len, void *dst);
#endif /* _ZCOMP_H_ */

View File

@ -32,6 +32,7 @@
#include <linux/debugfs.h>
#include <linux/cpuhotplug.h>
#include <linux/part_stat.h>
#include <linux/scatterlist.h>
#include <linux/kernel_read_file.h>
#include <linux/rcupdate.h>
@ -1347,9 +1348,9 @@ static int decompress_bdev_page(struct zram *zram, struct page *page,
unsigned long index)
{
struct zcomp_strm *zstrm;
struct scatterlist sg[1];
unsigned int size;
int ret, prio;
void *src;
slot_lock(zram, index);
/* Since slot was unlocked we need to make sure it's still ZRAM_WB */
@ -1368,13 +1369,18 @@ static int decompress_bdev_page(struct zram *zram, struct page *page,
size = get_slot_size(zram, index);
prio = get_slot_comp_priority(zram, index);
sg_init_table(sg, 1);
sg_set_page(sg, page, size, 0);
zstrm = zcomp_stream_get(zram->comps[prio]);
src = kmap_local_page(page);
ret = zcomp_decompress(zram->comps[prio], zstrm, src, size,
ret = zcomp_decompress(zram->comps[prio], zstrm, sg, size,
zstrm->local_copy);
if (!ret)
copy_page(src, zstrm->local_copy);
kunmap_local(src);
if (!ret) {
void *dst = kmap_local_page(page);
copy_page(dst, zstrm->local_copy);
kunmap_local(dst);
}
zcomp_stream_put(zstrm);
slot_unlock(zram, index);
@ -2086,15 +2092,19 @@ static int read_same_filled_page(struct zram *zram, struct page *page,
static int read_incompressible_page(struct zram *zram, struct page *page,
unsigned long index)
{
struct scatterlist sg[2];
unsigned long handle;
void *src, *dst;
handle = get_slot_handle(zram, index);
src = zs_obj_read_begin(zram->mem_pool, handle, PAGE_SIZE, NULL);
zs_obj_read_sg_begin(zram->mem_pool, handle, sg, PAGE_SIZE);
/* an incompressible object never spans two pages */
src = kmap_local_page(sg_page(sg));
dst = kmap_local_page(page);
copy_page(dst, src);
kunmap_local(dst);
zs_obj_read_end(zram->mem_pool, handle, PAGE_SIZE, src);
kunmap_local(src);
zs_obj_read_sg_end(zram->mem_pool, handle);
return 0;
}
@ -2103,9 +2113,10 @@ static int read_compressed_page(struct zram *zram, struct page *page,
unsigned long index)
{
struct zcomp_strm *zstrm;
struct scatterlist sg[2];
unsigned long handle;
unsigned int size;
void *src, *dst;
void *dst;
int ret, prio;
handle = get_slot_handle(zram, index);
@ -2113,12 +2124,11 @@ static int read_compressed_page(struct zram *zram, struct page *page,
prio = get_slot_comp_priority(zram, index);
zstrm = zcomp_stream_get(zram->comps[prio]);
src = zs_obj_read_begin(zram->mem_pool, handle, size,
zstrm->local_copy);
zs_obj_read_sg_begin(zram->mem_pool, handle, sg, size);
dst = kmap_local_page(page);
ret = zcomp_decompress(zram->comps[prio], zstrm, src, size, dst);
ret = zcomp_decompress(zram->comps[prio], zstrm, sg, size, dst);
kunmap_local(dst);
zs_obj_read_end(zram->mem_pool, handle, size, src);
zs_obj_read_sg_end(zram->mem_pool, handle);
zcomp_stream_put(zstrm);
return ret;
@ -2128,25 +2138,23 @@ static int read_compressed_page(struct zram *zram, struct page *page,
static int read_from_zspool_raw(struct zram *zram, struct page *page,
unsigned long index)
{
struct zcomp_strm *zstrm;
struct scatterlist sg[2];
unsigned long handle;
unsigned int size;
void *src;
void *dst;
handle = get_slot_handle(zram, index);
size = get_slot_size(zram, index);
/*
* We need to get stream just for ->local_copy buffer, in
* case if object spans two physical pages. No decompression
* takes place here, as we read raw compressed data.
* No decompression takes place here, we copy out raw compressed
* data directly into the destination page.
*/
zstrm = zcomp_stream_get(zram->comps[ZRAM_PRIMARY_COMP]);
src = zs_obj_read_begin(zram->mem_pool, handle, size,
zstrm->local_copy);
memcpy_to_page(page, 0, src, size);
zs_obj_read_end(zram->mem_pool, handle, size, src);
zcomp_stream_put(zstrm);
zs_obj_read_sg_begin(zram->mem_pool, handle, sg, size);
dst = kmap_local_page(page);
sg_copy_to_buffer(sg, sg_nents(sg), dst, size);
kunmap_local(dst);
zs_obj_read_sg_end(zram->mem_pool, handle);
memzero_page(page, size, PAGE_SIZE - size);