162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * drivers/block/zram/zram_group/group_writeback.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2020-2022 Huawei Technologies Co., Ltd.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/mm.h>
962306a36Sopenharmony_ci#include <linux/memcontrol.h>
1062306a36Sopenharmony_ci#include <linux/blk_types.h>
1162306a36Sopenharmony_ci#include <linux/zswapd.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "../zram_drv.h"
1462306a36Sopenharmony_ci#include "zram_group.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#ifdef CONFIG_HYPERHOLD
1762306a36Sopenharmony_ci#include "hyperhold.h"
1862306a36Sopenharmony_ci#endif
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define CHECK(cond, ...) ((cond) || (pr_err(__VA_ARGS__), false))
2162306a36Sopenharmony_ci#define CHECK_BOUND(var, min, max) \
2262306a36Sopenharmony_ci	CHECK((var) >= (min) && (var) <= (max), \
2362306a36Sopenharmony_ci			"%s %u out of bounds %u ~ %u!\n", \
2462306a36Sopenharmony_ci			#var, (var), (min), (max))
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic u16 zram_get_memcg_id(struct zram *zram, u32 index)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	return (zram->table[index].flags & ZRAM_GRPID_MASK) >> ZRAM_SIZE_SHIFT;
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic void zram_set_memcg_id(struct zram *zram, u32 index, u16 gid)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	unsigned long old = zram->table[index].flags & (~ZRAM_GRPID_MASK);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	zram->table[index].flags = old | ((u64)gid << ZRAM_SIZE_SHIFT);
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP_WRITEBACK
3962306a36Sopenharmony_cistatic bool obj_can_wb(struct zram *zram, u32 index, u16 gid)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	/* overwrited obj, just skip */
4262306a36Sopenharmony_ci	if (zram_get_memcg_id(zram, index) != gid) {
4362306a36Sopenharmony_ci		pr_debug("obj %u is from group %u instead of group %u.\n",
4462306a36Sopenharmony_ci				index, zram_get_memcg_id(zram, index), gid);
4562306a36Sopenharmony_ci		return false;
4662306a36Sopenharmony_ci	}
4762306a36Sopenharmony_ci	if (!zgrp_obj_is_isolated(zram->zgrp, index)) {
4862306a36Sopenharmony_ci		pr_debug("obj %u is not isolated.\n", index);
4962306a36Sopenharmony_ci		return false;
5062306a36Sopenharmony_ci	}
5162306a36Sopenharmony_ci	/* need not to writeback, put back the obj as HOTEST */
5262306a36Sopenharmony_ci	if (zram_test_flag(zram, index, ZRAM_SAME)) {
5362306a36Sopenharmony_ci		pr_debug("obj %u is filled with same element.\n", index);
5462306a36Sopenharmony_ci		goto insert;
5562306a36Sopenharmony_ci	}
5662306a36Sopenharmony_ci	if (zram_test_flag(zram, index, ZRAM_WB)) {
5762306a36Sopenharmony_ci		pr_debug("obj %u is writeback.\n", index);
5862306a36Sopenharmony_ci		goto insert;
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci	/* obj is needed by a pagefault req, do not writeback it. */
6162306a36Sopenharmony_ci	if (zram_test_flag(zram, index, ZRAM_FAULT)) {
6262306a36Sopenharmony_ci		pr_debug("obj %u is needed by a pagefault request.\n", index);
6362306a36Sopenharmony_ci		goto insert;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci	/* should never happen */
6662306a36Sopenharmony_ci	if (zram_test_flag(zram, index, ZRAM_GWB)) {
6762306a36Sopenharmony_ci		pr_debug("obj %u is group writeback.\n", index);
6862306a36Sopenharmony_ci		BUG();
6962306a36Sopenharmony_ci		return false;
7062306a36Sopenharmony_ci	}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	return true;
7362306a36Sopenharmony_ciinsert:
7462306a36Sopenharmony_ci	zgrp_obj_insert(zram->zgrp, index, gid);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	return false;
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic void copy_obj(struct hpio *hpio, u32 offset, char *obj, u32 size, bool to)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	u32 page_id, start;
8262306a36Sopenharmony_ci	char *buf = NULL;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	page_id = offset / PAGE_SIZE;
8562306a36Sopenharmony_ci	start = offset % PAGE_SIZE;
8662306a36Sopenharmony_ci	if (size + start <= PAGE_SIZE) {
8762306a36Sopenharmony_ci		buf = page_to_virt(hyperhold_io_page(hpio, page_id));
8862306a36Sopenharmony_ci		if (to)
8962306a36Sopenharmony_ci			memcpy(buf + start, obj, size);
9062306a36Sopenharmony_ci		else
9162306a36Sopenharmony_ci			memcpy(obj, buf + start, size);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci		return;
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci	buf = page_to_virt(hyperhold_io_page(hpio, page_id));
9662306a36Sopenharmony_ci	if (to)
9762306a36Sopenharmony_ci		memcpy(buf + start, obj, PAGE_SIZE - start);
9862306a36Sopenharmony_ci	else
9962306a36Sopenharmony_ci		memcpy(obj, buf + start, PAGE_SIZE - start);
10062306a36Sopenharmony_ci	buf = page_to_virt(hyperhold_io_page(hpio, page_id + 1));
10162306a36Sopenharmony_ci	if (to)
10262306a36Sopenharmony_ci		memcpy(buf, obj + PAGE_SIZE - start, size + start - PAGE_SIZE);
10362306a36Sopenharmony_ci	else
10462306a36Sopenharmony_ci		memcpy(obj + PAGE_SIZE - start, buf, size + start - PAGE_SIZE);
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic u32 move_obj_to_hpio(struct zram *zram, u32 index, u16 gid,
10862306a36Sopenharmony_ci				struct hpio *hpio, u32 offset)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	u32 size = 0;
11162306a36Sopenharmony_ci	unsigned long handle;
11262306a36Sopenharmony_ci	char *src = NULL;
11362306a36Sopenharmony_ci	u32 ext_size;
11462306a36Sopenharmony_ci	u32 eid;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	eid = hyperhold_io_extent(hpio);
11762306a36Sopenharmony_ci	ext_size = hyperhold_extent_size(eid);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	zram_slot_lock(zram, index);
12062306a36Sopenharmony_ci	if (!obj_can_wb(zram, index, gid))
12162306a36Sopenharmony_ci		goto unlock;
12262306a36Sopenharmony_ci	size = zram_get_obj_size(zram, index);
12362306a36Sopenharmony_ci	/* no space, put back the obj as COLDEST */
12462306a36Sopenharmony_ci	if (size + offset > ext_size) {
12562306a36Sopenharmony_ci		pr_debug("obj %u size is %u, but ext %u only %u space left.\n",
12662306a36Sopenharmony_ci				index, size, eid, ext_size - offset);
12762306a36Sopenharmony_ci		zgrp_obj_putback(zram->zgrp, index, gid);
12862306a36Sopenharmony_ci		size = 0;
12962306a36Sopenharmony_ci		goto unlock;
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci	handle = zram_get_handle(zram, index);
13262306a36Sopenharmony_ci	src = zs_map_object(zram->mem_pool, handle, ZS_MM_RO);
13362306a36Sopenharmony_ci	copy_obj(hpio, offset, src, size, true);
13462306a36Sopenharmony_ci	zs_unmap_object(zram->mem_pool, handle);
13562306a36Sopenharmony_ci	zs_free(zram->mem_pool, handle);
13662306a36Sopenharmony_ci	zram_set_handle(zram, index, hyperhold_address(eid, offset));
13762306a36Sopenharmony_ci	zram_set_flag(zram, index, ZRAM_GWB);
13862306a36Sopenharmony_ci	wbgrp_obj_insert(zram->zgrp, index, eid);
13962306a36Sopenharmony_ci	wbgrp_obj_stats_inc(zram->zgrp, gid, eid, size);
14062306a36Sopenharmony_ci	zgrp_obj_stats_dec(zram->zgrp, gid, size);
14162306a36Sopenharmony_ci	pr_debug("move obj %u of group %u to hpio %p of eid %u, size = %u, offset = %u\n",
14262306a36Sopenharmony_ci		index, gid, hpio, eid, size, offset);
14362306a36Sopenharmony_ciunlock:
14462306a36Sopenharmony_ci	zram_slot_unlock(zram, index);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	return size;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic void move_obj_from_hpio(struct zram *zram, int index, struct hpio *hpio)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	u32 size = 0;
15262306a36Sopenharmony_ci	unsigned long handle = 0;
15362306a36Sopenharmony_ci	u32 eid, offset;
15462306a36Sopenharmony_ci	u64 addr;
15562306a36Sopenharmony_ci	char *dst = NULL;
15662306a36Sopenharmony_ci	u16 gid;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	eid = hyperhold_io_extent(hpio);
15962306a36Sopenharmony_ciretry:
16062306a36Sopenharmony_ci	zram_slot_lock(zram, index);
16162306a36Sopenharmony_ci	if (!zram_test_flag(zram, index, ZRAM_GWB))
16262306a36Sopenharmony_ci		goto unlock;
16362306a36Sopenharmony_ci	addr = zram_get_handle(zram, index);
16462306a36Sopenharmony_ci	if (hyperhold_addr_extent(addr) != eid)
16562306a36Sopenharmony_ci		goto unlock;
16662306a36Sopenharmony_ci	size = zram_get_obj_size(zram, index);
16762306a36Sopenharmony_ci	if (handle)
16862306a36Sopenharmony_ci		goto move;
16962306a36Sopenharmony_ci	handle = zs_malloc(zram->mem_pool, size, GFP_NOWAIT);
17062306a36Sopenharmony_ci	if (handle)
17162306a36Sopenharmony_ci		goto move;
17262306a36Sopenharmony_ci	zram_slot_unlock(zram, index);
17362306a36Sopenharmony_ci	handle = zs_malloc(zram->mem_pool, size, GFP_NOIO | __GFP_NOFAIL);
17462306a36Sopenharmony_ci	if (handle)
17562306a36Sopenharmony_ci		goto retry;
17662306a36Sopenharmony_ci	BUG();
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	return;
17962306a36Sopenharmony_cimove:
18062306a36Sopenharmony_ci	offset = hyperhold_addr_offset(addr);
18162306a36Sopenharmony_ci	dst = zs_map_object(zram->mem_pool, handle, ZS_MM_WO);
18262306a36Sopenharmony_ci	copy_obj(hpio, offset, dst, size, false);
18362306a36Sopenharmony_ci	zs_unmap_object(zram->mem_pool, handle);
18462306a36Sopenharmony_ci	zram_set_handle(zram, index, handle);
18562306a36Sopenharmony_ci	zram_clear_flag(zram, index, ZRAM_GWB);
18662306a36Sopenharmony_ci	gid = zram_get_memcg_id(zram, index);
18762306a36Sopenharmony_ci	zgrp_obj_insert(zram->zgrp, index, gid);
18862306a36Sopenharmony_ci	wbgrp_obj_stats_dec(zram->zgrp, gid, eid, size);
18962306a36Sopenharmony_ci	zgrp_obj_stats_inc(zram->zgrp, gid, size);
19062306a36Sopenharmony_ci	pr_debug("move obj %u of group %u from hpio %p of eid %u, size = %u, offset = %u\n",
19162306a36Sopenharmony_ci		index, gid, hpio, eid, size, offset);
19262306a36Sopenharmony_ciunlock:
19362306a36Sopenharmony_ci	zram_slot_unlock(zram, index);
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci#define NR_ISOLATE 32
19862306a36Sopenharmony_cistatic bool move_extent_from_hpio(struct zram *zram, struct hpio *hpio)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	u32 idxs[NR_ISOLATE];
20162306a36Sopenharmony_ci	u32 eid;
20262306a36Sopenharmony_ci	u32 nr;
20362306a36Sopenharmony_ci	int i;
20462306a36Sopenharmony_ci	bool last = false;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	eid = hyperhold_io_extent(hpio);
20762306a36Sopenharmony_cirepeat:
20862306a36Sopenharmony_ci	nr = wbgrp_isolate_objs(zram->zgrp, eid, idxs, NR_ISOLATE, &last);
20962306a36Sopenharmony_ci	for (i = 0; i < nr; i++)
21062306a36Sopenharmony_ci		move_obj_from_hpio(zram, idxs[i], hpio);
21162306a36Sopenharmony_ci	if (last)
21262306a36Sopenharmony_ci		return true;
21362306a36Sopenharmony_ci	if (nr)
21462306a36Sopenharmony_ci		goto repeat;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	return false;
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistruct hpio_priv {
22062306a36Sopenharmony_ci	struct zram *zram;
22162306a36Sopenharmony_ci	u16 gid;
22262306a36Sopenharmony_ci};
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic void write_endio(struct hpio *hpio)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	struct hpio_priv *priv = hyperhold_io_private(hpio);
22762306a36Sopenharmony_ci	struct zram *zram = priv->zram;
22862306a36Sopenharmony_ci	u16 gid = priv->gid;
22962306a36Sopenharmony_ci	u32 eid = hyperhold_io_extent(hpio);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (hyperhold_io_success(hpio))
23262306a36Sopenharmony_ci		goto out;
23362306a36Sopenharmony_ci	if (move_extent_from_hpio(zram, hpio)) {
23462306a36Sopenharmony_ci		zgrp_ext_delete(zram->zgrp, eid, gid);
23562306a36Sopenharmony_ci		hyperhold_should_free_extent(eid);
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ciout:
23862306a36Sopenharmony_ci	hyperhold_io_complete(hpio);
23962306a36Sopenharmony_ci	hyperhold_io_put(hpio);
24062306a36Sopenharmony_ci	kfree(priv);
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistatic u32 collect_objs(struct zram *zram, u16 gid, struct hpio *hpio, u32 ext_size)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	u32 offset = 0;
24662306a36Sopenharmony_ci	u32 last_offset;
24762306a36Sopenharmony_ci	u32 nr;
24862306a36Sopenharmony_ci	u32 idxs[NR_ISOLATE];
24962306a36Sopenharmony_ci	int i;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cimore:
25262306a36Sopenharmony_ci	last_offset = offset;
25362306a36Sopenharmony_ci	nr = zgrp_isolate_objs(zram->zgrp, gid, idxs, NR_ISOLATE, NULL);
25462306a36Sopenharmony_ci	for (i = 0; i < nr; i++)
25562306a36Sopenharmony_ci		offset += move_obj_to_hpio(zram, idxs[i], gid, hpio, offset);
25662306a36Sopenharmony_ci	pr_debug("%u data attached, offset = %u.\n", offset - last_offset, offset);
25762306a36Sopenharmony_ci	if (offset < ext_size && offset != last_offset)
25862306a36Sopenharmony_ci		goto more;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	return offset;
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic u64 write_one_extent(struct zram *zram, u16 gid)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	int eid;
26662306a36Sopenharmony_ci	struct hpio *hpio = NULL;
26762306a36Sopenharmony_ci	struct hpio_priv *priv = NULL;
26862306a36Sopenharmony_ci	u32 size = 0;
26962306a36Sopenharmony_ci	int ret;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	priv = kmalloc(sizeof(struct hpio_priv), GFP_NOIO);
27262306a36Sopenharmony_ci	if (!priv)
27362306a36Sopenharmony_ci		return 0;
27462306a36Sopenharmony_ci	priv->gid = gid;
27562306a36Sopenharmony_ci	priv->zram = zram;
27662306a36Sopenharmony_ci	eid = hyperhold_alloc_extent();
27762306a36Sopenharmony_ci	if (eid < 0)
27862306a36Sopenharmony_ci		goto err;
27962306a36Sopenharmony_ci	hpio = hyperhold_io_get(eid, GFP_NOIO, REQ_OP_WRITE);
28062306a36Sopenharmony_ci	if (!hpio)
28162306a36Sopenharmony_ci		goto free_extent;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	zgrp_get_ext(zram->zgrp, eid);
28462306a36Sopenharmony_ci	size = collect_objs(zram, gid, hpio, hyperhold_extent_size(eid));
28562306a36Sopenharmony_ci	if (size == 0) {
28662306a36Sopenharmony_ci		pr_err("group %u has no data in zram.\n", gid);
28762306a36Sopenharmony_ci		zgrp_put_ext(zram->zgrp, eid);
28862306a36Sopenharmony_ci		goto put_hpio;
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci	zgrp_ext_insert(zram->zgrp, eid, gid);
29162306a36Sopenharmony_ci	if (zgrp_put_ext(zram->zgrp, eid)) {
29262306a36Sopenharmony_ci		zgrp_ext_delete(zram->zgrp, eid, gid);
29362306a36Sopenharmony_ci		hyperhold_should_free_extent(eid);
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	ret = hyperhold_write_async(hpio, write_endio, priv);
29762306a36Sopenharmony_ci	if (ret)
29862306a36Sopenharmony_ci		goto move_back;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	return size;
30162306a36Sopenharmony_cimove_back:
30262306a36Sopenharmony_ci	if (move_extent_from_hpio(zram, hpio)) {
30362306a36Sopenharmony_ci		zgrp_ext_delete(zram->zgrp, eid, gid);
30462306a36Sopenharmony_ci		hyperhold_should_free_extent(eid);
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci	eid = -EINVAL;
30762306a36Sopenharmony_ciput_hpio:
30862306a36Sopenharmony_ci	hyperhold_io_put(hpio);
30962306a36Sopenharmony_cifree_extent:
31062306a36Sopenharmony_ci	if (eid >= 0)
31162306a36Sopenharmony_ci		hyperhold_free_extent(eid);
31262306a36Sopenharmony_cierr:
31362306a36Sopenharmony_ci	kfree(priv);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	return 0;
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic void read_endio(struct hpio *hpio)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	struct hpio_priv *priv = hyperhold_io_private(hpio);
32162306a36Sopenharmony_ci	struct zram *zram = priv->zram;
32262306a36Sopenharmony_ci	u16 gid = priv->gid;
32362306a36Sopenharmony_ci	u32 eid = hyperhold_io_extent(hpio);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	if (!hyperhold_io_success(hpio)) {
32662306a36Sopenharmony_ci		BUG();
32762306a36Sopenharmony_ci		goto out;
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci	if (move_extent_from_hpio(zram, hpio)) {
33062306a36Sopenharmony_ci		zgrp_ext_delete(zram->zgrp, eid, gid);
33162306a36Sopenharmony_ci		hyperhold_should_free_extent(eid);
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ciout:
33462306a36Sopenharmony_ci	hyperhold_io_complete(hpio);
33562306a36Sopenharmony_ci	hyperhold_io_put(hpio);
33662306a36Sopenharmony_ci	kfree(priv);
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic u64 read_one_extent(struct zram *zram, u32 eid, u16 gid)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	struct hpio *hpio = NULL;
34262306a36Sopenharmony_ci	u32 ext_size = 0;
34362306a36Sopenharmony_ci	int ret;
34462306a36Sopenharmony_ci	struct hpio_priv *priv = NULL;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	priv = kmalloc(sizeof(struct hpio_priv), GFP_NOIO);
34762306a36Sopenharmony_ci	if (!priv)
34862306a36Sopenharmony_ci		goto err;
34962306a36Sopenharmony_ci	priv->gid = gid;
35062306a36Sopenharmony_ci	priv->zram = zram;
35162306a36Sopenharmony_ci	hpio = hyperhold_io_get(eid, GFP_NOIO, REQ_OP_READ);
35262306a36Sopenharmony_ci	if (!hpio)
35362306a36Sopenharmony_ci		goto err;
35462306a36Sopenharmony_ci	ext_size = hyperhold_extent_size(eid);
35562306a36Sopenharmony_ci	ret = hyperhold_read_async(hpio, read_endio, priv);
35662306a36Sopenharmony_ci	if (ret)
35762306a36Sopenharmony_ci		goto err;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	return ext_size;
36062306a36Sopenharmony_cierr:
36162306a36Sopenharmony_ci	hyperhold_io_put(hpio);
36262306a36Sopenharmony_ci	kfree(priv);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	return 0;
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic void sync_read_endio(struct hpio *hpio)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	hyperhold_io_complete(hpio);
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic int read_one_obj_sync(struct zram *zram, u32 index)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	struct hpio *hpio = NULL;
37562306a36Sopenharmony_ci	int ret;
37662306a36Sopenharmony_ci	u32 eid;
37762306a36Sopenharmony_ci	u16 gid;
37862306a36Sopenharmony_ci	u32 size;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	if (!zram_test_flag(zram, index, ZRAM_GWB))
38162306a36Sopenharmony_ci		return 0;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	pr_debug("read obj %u.\n", index);
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	gid = zram_get_memcg_id(zram, index);
38662306a36Sopenharmony_ci	eid = hyperhold_addr_extent(zram_get_handle(zram, index));
38762306a36Sopenharmony_ci	size = zram_get_obj_size(zram, index);
38862306a36Sopenharmony_ci	wbgrp_fault_stats_inc(zram->zgrp, gid, eid, size);
38962306a36Sopenharmony_cicheck:
39062306a36Sopenharmony_ci	if (!zram_test_flag(zram, index, ZRAM_GWB))
39162306a36Sopenharmony_ci		return 0;
39262306a36Sopenharmony_ci	if (!zram_test_flag(zram, index, ZRAM_FAULT))
39362306a36Sopenharmony_ci		goto read;
39462306a36Sopenharmony_ci	zram_slot_unlock(zram, index);
39562306a36Sopenharmony_ci	wait_event(zram->zgrp->wbgrp.fault_wq, !zram_test_flag(zram, index, ZRAM_FAULT));
39662306a36Sopenharmony_ci	zram_slot_lock(zram, index);
39762306a36Sopenharmony_ci	goto check;
39862306a36Sopenharmony_ciread:
39962306a36Sopenharmony_ci	zram_set_flag(zram, index, ZRAM_FAULT);
40062306a36Sopenharmony_ci	zram_slot_unlock(zram, index);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	hpio = hyperhold_io_get(eid, GFP_NOIO, REQ_OP_READ);
40362306a36Sopenharmony_ci	if (!hpio) {
40462306a36Sopenharmony_ci		ret = -ENOMEM;
40562306a36Sopenharmony_ci		goto out;
40662306a36Sopenharmony_ci	}
40762306a36Sopenharmony_ci	ret = hyperhold_read_async(hpio, sync_read_endio, NULL);
40862306a36Sopenharmony_ci	/* io submit error */
40962306a36Sopenharmony_ci	if (ret && ret != -EAGAIN)
41062306a36Sopenharmony_ci		goto out;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	hyperhold_io_wait(hpio);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	/* if not reset to zero, will return err sometimes and cause SIG_BUS error */
41562306a36Sopenharmony_ci	ret = 0;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	/* get a write io, data is ready, copy the pages even write failed */
41862306a36Sopenharmony_ci	if (op_is_write(hyperhold_io_operate(hpio)))
41962306a36Sopenharmony_ci		goto move;
42062306a36Sopenharmony_ci	/* read io failed, return -EIO */
42162306a36Sopenharmony_ci	if (!hyperhold_io_success(hpio)) {
42262306a36Sopenharmony_ci		ret = -EIO;
42362306a36Sopenharmony_ci		goto out;
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci	/* success, copy the data and free extent */
42662306a36Sopenharmony_cimove:
42762306a36Sopenharmony_ci	if (move_extent_from_hpio(zram, hpio)) {
42862306a36Sopenharmony_ci		zgrp_ext_delete(zram->zgrp, eid, gid);
42962306a36Sopenharmony_ci		hyperhold_should_free_extent(eid);
43062306a36Sopenharmony_ci	}
43162306a36Sopenharmony_ci	move_obj_from_hpio(zram, index, hpio);
43262306a36Sopenharmony_ciout:
43362306a36Sopenharmony_ci	hyperhold_io_put(hpio);
43462306a36Sopenharmony_ci	zram_slot_lock(zram, index);
43562306a36Sopenharmony_ci	zram_clear_flag(zram, index, ZRAM_FAULT);
43662306a36Sopenharmony_ci	wake_up(&zram->zgrp->wbgrp.fault_wq);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	return ret;
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ciu64 read_group_objs(struct zram *zram, u16 gid, u64 req_size)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	u32 eid;
44462306a36Sopenharmony_ci	u64 read_size = 0;
44562306a36Sopenharmony_ci	u32 nr;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	if (!(zram->zgrp)) {
44862306a36Sopenharmony_ci		pr_debug("zram group is not enable!\n");
44962306a36Sopenharmony_ci		return 0;
45062306a36Sopenharmony_ci	}
45162306a36Sopenharmony_ci	if (!CHECK_BOUND(gid, 1, zram->zgrp->nr_grp - 1))
45262306a36Sopenharmony_ci		return 0;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	pr_debug("read %llu data of group %u.\n", req_size, gid);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	while (!req_size || req_size > read_size) {
45762306a36Sopenharmony_ci		nr = zgrp_isolate_exts(zram->zgrp, gid, &eid, 1, NULL);
45862306a36Sopenharmony_ci		if (!nr)
45962306a36Sopenharmony_ci			break;
46062306a36Sopenharmony_ci		read_size += read_one_extent(zram, eid, gid);
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	return read_size;
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ciu64 write_group_objs(struct zram *zram, u16 gid, u64 req_size)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	u64 write_size = 0;
46962306a36Sopenharmony_ci	u64 size = 0;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	if (!(zram->zgrp)) {
47262306a36Sopenharmony_ci		pr_debug("zram group is not enable!\n");
47362306a36Sopenharmony_ci		return 0;
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci	if (!CHECK(zram->zgrp->wbgrp.enable, "zram group writeback is not enable!\n"))
47662306a36Sopenharmony_ci		return 0;
47762306a36Sopenharmony_ci	if (!CHECK_BOUND(gid, 1, zram->zgrp->nr_grp - 1))
47862306a36Sopenharmony_ci		return 0;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	pr_debug("write %llu data of group %u.\n", req_size, gid);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	while (!req_size || req_size > write_size) {
48362306a36Sopenharmony_ci		size = write_one_extent(zram, gid);
48462306a36Sopenharmony_ci		if (!size)
48562306a36Sopenharmony_ci			break;
48662306a36Sopenharmony_ci		write_size += size;
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	atomic64_add(write_size, &zram->zgrp->stats[0].write_size);
49062306a36Sopenharmony_ci	atomic64_add(write_size, &zram->zgrp->stats[gid].write_size);
49162306a36Sopenharmony_ci	return write_size;
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci#endif
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP_DEBUG
49662306a36Sopenharmony_ci#include <linux/random.h>
49762306a36Sopenharmony_ci#define ZGRP_TEST_MAX_GRP 101
49862306a36Sopenharmony_ci#endif
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ciint zram_group_fault_obj(struct zram *zram, u32 index)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	u16 gid;
50362306a36Sopenharmony_ci	u32 size;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	if (!(zram->zgrp)) {
50662306a36Sopenharmony_ci		pr_debug("zram group is not enable!\n");
50762306a36Sopenharmony_ci		return 0;
50862306a36Sopenharmony_ci	}
50962306a36Sopenharmony_ci	if (!CHECK_BOUND(index, 0, zram->zgrp->nr_obj - 1))
51062306a36Sopenharmony_ci		return 0;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	gid = zram_get_memcg_id(zram, index);
51362306a36Sopenharmony_ci	size = zram_get_obj_size(zram, index);
51462306a36Sopenharmony_ci	zgrp_fault_stats_inc(zram->zgrp, gid, size);
51562306a36Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP_WRITEBACK
51662306a36Sopenharmony_ci	return read_one_obj_sync(zram, index);
51762306a36Sopenharmony_ci#else
51862306a36Sopenharmony_ci	return 0;
51962306a36Sopenharmony_ci#endif
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_civoid zram_group_track_obj(struct zram *zram, u32 index, struct mem_cgroup *memcg)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	u16 gid;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	if (!(zram->zgrp)) {
52762306a36Sopenharmony_ci		pr_debug("zram group is not enable!\n");
52862306a36Sopenharmony_ci		return;
52962306a36Sopenharmony_ci	}
53062306a36Sopenharmony_ci	if (!CHECK_BOUND(index, 0, zram->zgrp->nr_obj - 1))
53162306a36Sopenharmony_ci		return;
53262306a36Sopenharmony_ci	if (!CHECK(memcg || !memcg->id.id, "obj %u has no memcg!\n", index))
53362306a36Sopenharmony_ci		return;
53462306a36Sopenharmony_ci	gid = zram_get_memcg_id(zram, index);
53562306a36Sopenharmony_ci	if (!CHECK(!gid, "obj %u has gid %u.\n", index, gid))
53662306a36Sopenharmony_ci		BUG();
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	gid = memcg->id.id;
53962306a36Sopenharmony_ci	zram_set_memcg_id(zram, index, gid);
54062306a36Sopenharmony_ci	zgrp_obj_insert(zram->zgrp, index, gid);
54162306a36Sopenharmony_ci	zgrp_obj_stats_inc(zram->zgrp, gid, zram_get_obj_size(zram, index));
54262306a36Sopenharmony_ci}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_civoid zram_group_untrack_obj(struct zram *zram, u32 index)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	u16 gid;
54762306a36Sopenharmony_ci	u32 size;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	if (!(zram->zgrp)) {
55062306a36Sopenharmony_ci		pr_debug("zram group is not enable!\n");
55162306a36Sopenharmony_ci		return;
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci	if (!CHECK_BOUND(index, 0, zram->zgrp->nr_obj - 1))
55462306a36Sopenharmony_ci		return;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP_WRITEBACK
55762306a36Sopenharmony_cicheck:
55862306a36Sopenharmony_ci	if (!zram_test_flag(zram, index, ZRAM_FAULT))
55962306a36Sopenharmony_ci		goto clear;
56062306a36Sopenharmony_ci	zram_slot_unlock(zram, index);
56162306a36Sopenharmony_ci	wait_event(zram->zgrp->wbgrp.fault_wq, !zram_test_flag(zram, index, ZRAM_FAULT));
56262306a36Sopenharmony_ci	zram_slot_lock(zram, index);
56362306a36Sopenharmony_ci	goto check;
56462306a36Sopenharmony_ciclear:
56562306a36Sopenharmony_ci#endif
56662306a36Sopenharmony_ci	gid = zram_get_memcg_id(zram, index);
56762306a36Sopenharmony_ci	size = zram_get_obj_size(zram, index);
56862306a36Sopenharmony_ci	if (!gid)
56962306a36Sopenharmony_ci		return;
57062306a36Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP_WRITEBACK
57162306a36Sopenharmony_ci	if (zram_test_flag(zram, index, ZRAM_GWB)) {
57262306a36Sopenharmony_ci		u32 eid = hyperhold_addr_extent(zram_get_handle(zram, index));
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci		if (wbgrp_obj_delete(zram->zgrp, index, eid)) {
57562306a36Sopenharmony_ci			zgrp_ext_delete(zram->zgrp, eid, gid);
57662306a36Sopenharmony_ci			hyperhold_should_free_extent(eid);
57762306a36Sopenharmony_ci		}
57862306a36Sopenharmony_ci		zram_clear_flag(zram, index, ZRAM_GWB);
57962306a36Sopenharmony_ci		zram_set_memcg_id(zram, index, 0);
58062306a36Sopenharmony_ci		wbgrp_obj_stats_dec(zram->zgrp, gid, eid, size);
58162306a36Sopenharmony_ci		zram_set_handle(zram, index, 0);
58262306a36Sopenharmony_ci		return;
58362306a36Sopenharmony_ci	}
58462306a36Sopenharmony_ci#endif
58562306a36Sopenharmony_ci	zgrp_obj_delete(zram->zgrp, index, gid);
58662306a36Sopenharmony_ci	zram_set_memcg_id(zram, index, 0);
58762306a36Sopenharmony_ci	zgrp_obj_stats_dec(zram->zgrp, gid, size);
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP_DEBUG
59162306a36Sopenharmony_civoid group_debug(struct zram *zram, u32 op, u32 index, u32 gid)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	if (op == 0)
59462306a36Sopenharmony_ci		zram_group_dump(zram->zgrp, gid, index);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP_WRITEBACK
59762306a36Sopenharmony_ci	if (op == 22)
59862306a36Sopenharmony_ci		read_group_objs(zram, gid, index);
59962306a36Sopenharmony_ci	if (op == 23)
60062306a36Sopenharmony_ci		write_group_objs(zram, gid, index);
60162306a36Sopenharmony_ci	if (op == 20) {
60262306a36Sopenharmony_ci		if (index)
60362306a36Sopenharmony_ci			zram_group_apply_writeback(zram->zgrp, hyperhold_nr_extent());
60462306a36Sopenharmony_ci		else
60562306a36Sopenharmony_ci			zram_group_remove_writeback(zram->zgrp);
60662306a36Sopenharmony_ci	}
60762306a36Sopenharmony_ci#endif
60862306a36Sopenharmony_ci}
60962306a36Sopenharmony_ci#endif
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_cistatic u64 group_obj_stats(struct zram *zram, u16 gid, int type)
61262306a36Sopenharmony_ci{
61362306a36Sopenharmony_ci	if (!(zram->zgrp)) {
61462306a36Sopenharmony_ci		pr_debug("zram group is not enable!\n");
61562306a36Sopenharmony_ci		return 0;
61662306a36Sopenharmony_ci	}
61762306a36Sopenharmony_ci	if (!CHECK_BOUND(gid, 0, zram->zgrp->nr_grp - 1))
61862306a36Sopenharmony_ci		return 0;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	if (type == CACHE_SIZE)
62162306a36Sopenharmony_ci		return atomic64_read(&zram->zgrp->stats[gid].zram_size);
62262306a36Sopenharmony_ci	else if (type == CACHE_PAGE)
62362306a36Sopenharmony_ci		return atomic_read(&zram->zgrp->stats[gid].zram_pages);
62462306a36Sopenharmony_ci	else if (type == CACHE_FAULT)
62562306a36Sopenharmony_ci		return atomic64_read(&zram->zgrp->stats[gid].zram_fault);
62662306a36Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP_WRITEBACK
62762306a36Sopenharmony_ci	else if (type == SWAP_SIZE)
62862306a36Sopenharmony_ci		return atomic64_read(&zram->zgrp->stats[gid].wb_size);
62962306a36Sopenharmony_ci	else if (type == SWAP_PAGE)
63062306a36Sopenharmony_ci		return atomic_read(&zram->zgrp->stats[gid].wb_pages);
63162306a36Sopenharmony_ci	else if (type == READ_SIZE)
63262306a36Sopenharmony_ci		return atomic64_read(&zram->zgrp->stats[gid].read_size);
63362306a36Sopenharmony_ci	else if (type == WRITE_SIZE)
63462306a36Sopenharmony_ci		return atomic64_read(&zram->zgrp->stats[gid].write_size);
63562306a36Sopenharmony_ci	else if (type == SWAP_FAULT)
63662306a36Sopenharmony_ci		return atomic64_read(&zram->zgrp->stats[gid].wb_fault);
63762306a36Sopenharmony_ci	BUG();
63862306a36Sopenharmony_ci#endif
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	return 0;
64162306a36Sopenharmony_ci}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP_WRITEBACK
64462306a36Sopenharmony_cistatic u64 zram_group_read(u16 gid, u64 req_size, void *priv)
64562306a36Sopenharmony_ci{
64662306a36Sopenharmony_ci	if (!CHECK(priv, "priv is NULL!\n"))
64762306a36Sopenharmony_ci		return 0;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	return read_group_objs((struct zram *)priv, gid, req_size);
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_cistatic u64 zram_group_write(u16 gid, u64 req_size, void *priv)
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	if (!CHECK(priv, "priv is NULL!\n"))
65562306a36Sopenharmony_ci		return 0;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	return write_group_objs((struct zram *)priv, gid, req_size);
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ci#else
66062306a36Sopenharmony_cistatic u64 zram_group_read(u16 gid, u64 req_size, void *priv)
66162306a36Sopenharmony_ci{
66262306a36Sopenharmony_ci	return 0;
66362306a36Sopenharmony_ci}
66462306a36Sopenharmony_cistatic u64 zram_group_write(u16 gid, u64 req_size, void *priv)
66562306a36Sopenharmony_ci{
66662306a36Sopenharmony_ci	return 0;
66762306a36Sopenharmony_ci}
66862306a36Sopenharmony_ci#endif
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_cistatic u64 zram_group_data_size(u16 gid, int type, void *priv)
67262306a36Sopenharmony_ci{
67362306a36Sopenharmony_ci	if (!CHECK(priv, "priv is NULL!\n"))
67462306a36Sopenharmony_ci		return 0;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	return group_obj_stats((struct zram *)priv, gid, type);
67762306a36Sopenharmony_ci}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_cistruct group_swap_ops zram_group_ops = {
68062306a36Sopenharmony_ci	.group_read = zram_group_read,
68162306a36Sopenharmony_ci	.group_write = zram_group_write,
68262306a36Sopenharmony_ci	.group_data_size = zram_group_data_size,
68362306a36Sopenharmony_ci};
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_cistatic int register_zram_group(struct zram *zram)
68662306a36Sopenharmony_ci{
68762306a36Sopenharmony_ci	if (!CHECK(zram, "zram is NULL!\n"))
68862306a36Sopenharmony_ci		return -EINVAL;
68962306a36Sopenharmony_ci	if (!(zram->zgrp)) {
69062306a36Sopenharmony_ci		pr_debug("zram group is not enable!\n");
69162306a36Sopenharmony_ci		return -EINVAL;
69262306a36Sopenharmony_ci	}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	zram->zgrp->gsdev = register_group_swap(&zram_group_ops, zram);
69562306a36Sopenharmony_ci	if (!zram->zgrp->gsdev) {
69662306a36Sopenharmony_ci		pr_err("register zram group failed!\n");
69762306a36Sopenharmony_ci		return -ENOMEM;
69862306a36Sopenharmony_ci	}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	return 0;
70162306a36Sopenharmony_ci}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_cistatic void unregister_zram_group(struct zram *zram)
70462306a36Sopenharmony_ci{
70562306a36Sopenharmony_ci	if (!CHECK(zram, "zram is NULL!\n"))
70662306a36Sopenharmony_ci		return;
70762306a36Sopenharmony_ci	if (!(zram->zgrp)) {
70862306a36Sopenharmony_ci		pr_debug("zram group is not enable!\n");
70962306a36Sopenharmony_ci		return;
71062306a36Sopenharmony_ci	}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	unregister_group_swap(zram->zgrp->gsdev);
71362306a36Sopenharmony_ci	zram->zgrp->gsdev = NULL;
71462306a36Sopenharmony_ci}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_civoid zram_group_init(struct zram *zram, u32 nr_obj)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	unsigned int ctrl = zram->zgrp_ctrl;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	if (ctrl == ZGRP_NONE)
72162306a36Sopenharmony_ci		return;
72262306a36Sopenharmony_ci	zram->zgrp = zram_group_meta_alloc(nr_obj, ZGRP_MAX_GRP - 1);
72362306a36Sopenharmony_ci#ifdef CONFIG_ZRAM_GROUP_WRITEBACK
72462306a36Sopenharmony_ci	if (ctrl == ZGRP_WRITE)
72562306a36Sopenharmony_ci		zram_group_apply_writeback(zram->zgrp, hyperhold_nr_extent());
72662306a36Sopenharmony_ci#endif
72762306a36Sopenharmony_ci	register_zram_group(zram);
72862306a36Sopenharmony_ci}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_civoid zram_group_deinit(struct zram *zram)
73162306a36Sopenharmony_ci{
73262306a36Sopenharmony_ci	unregister_zram_group(zram);
73362306a36Sopenharmony_ci	zram_group_meta_free(zram->zgrp);
73462306a36Sopenharmony_ci	zram->zgrp = NULL;
73562306a36Sopenharmony_ci}
736