Skip to content

Commit 7ac07a2

Browse files
sergey-senozhatskyakpm00
authored andcommitted
zram: preparation for multi-zcomp support
Patch series "zram: Support multiple compression streams", v5. This series adds support for multiple compression streams. The main idea is that different compression algorithms have different characteristics and zram may benefit when it uses a combination of algorithms: a default algorithm that is faster but have lower compression rate and a secondary algorithm that can use higher compression rate at a price of slower compression/decompression. There are several use-case for this functionality: - huge pages re-compression: zstd or deflate can successfully compress huge pages (~50% of huge pages on my synthetic ChromeOS tests), IOW pages that lzo was not able to compress. - idle pages re-compression: idle/cold pages sit in the memory and we may reduce zsmalloc memory usage if we recompress those idle pages. Userspace has a number of ways to control the behavior and impact of zram recompression: what type of pages should be recompressed, size watermarks, etc. Please refer to documentation patch. This patch (of 13): The patch turns compression streams and compressor algorithm name struct zram members into arrays, so that we can have multiple compression streams support (in the next patches). The patch uses a rather explicit API for compressor selection: - Get primary (default) compression stream zcomp_stream_get(zram->comps[ZRAM_PRIMARY_COMP]) - Get secondary compression stream zcomp_stream_get(zram->comps[ZRAM_SECONDARY_COMP]) We use similar API for compression streams put(). At this point we always have just one compression stream, since CONFIG_ZRAM_MULTI_COMP is not yet defined. Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Sergey Senozhatsky <[email protected]> Acked-by: Minchan Kim <[email protected]> Cc: Minchan Kim <[email protected]> Cc: Nitin Gupta <[email protected]> Cc: Suleiman Souhlal <[email protected]> Cc: Nhat Pham <[email protected]> Cc: Alexey Romanov <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent f036c81 commit 7ac07a2

File tree

4 files changed

+80
-32
lines changed

4 files changed

+80
-32
lines changed

drivers/block/zram/zcomp.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ void zcomp_destroy(struct zcomp *comp)
206206
* case of allocation error, or any other error potentially
207207
* returned by zcomp_init().
208208
*/
209-
struct zcomp *zcomp_create(const char *compress)
209+
struct zcomp *zcomp_create(const char *alg)
210210
{
211211
struct zcomp *comp;
212212
int error;
@@ -216,14 +216,14 @@ struct zcomp *zcomp_create(const char *compress)
216216
* is not loaded yet. We must do it here, otherwise we are about to
217217
* call /sbin/modprobe under CPU hot-plug lock.
218218
*/
219-
if (!zcomp_available_algorithm(compress))
219+
if (!zcomp_available_algorithm(alg))
220220
return ERR_PTR(-EINVAL);
221221

222222
comp = kzalloc(sizeof(struct zcomp), GFP_KERNEL);
223223
if (!comp)
224224
return ERR_PTR(-ENOMEM);
225225

226-
comp->name = compress;
226+
comp->name = alg;
227227
error = zcomp_init(comp);
228228
if (error) {
229229
kfree(comp);

drivers/block/zram/zcomp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ int zcomp_cpu_dead(unsigned int cpu, struct hlist_node *node);
2727
ssize_t zcomp_available_show(const char *comp, char *buf);
2828
bool zcomp_available_algorithm(const char *comp);
2929

30-
struct zcomp *zcomp_create(const char *comp);
30+
struct zcomp *zcomp_create(const char *alg);
3131
void zcomp_destroy(struct zcomp *comp);
3232

3333
struct zcomp_strm *zcomp_stream_get(struct zcomp *comp);

drivers/block/zram/zram_drv.c

Lines changed: 64 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,36 +1004,53 @@ static ssize_t comp_algorithm_show(struct device *dev,
10041004
struct zram *zram = dev_to_zram(dev);
10051005

10061006
down_read(&zram->init_lock);
1007-
sz = zcomp_available_show(zram->compressor, buf);
1007+
sz = zcomp_available_show(zram->comp_algs[ZRAM_PRIMARY_COMP], buf);
10081008
up_read(&zram->init_lock);
10091009

10101010
return sz;
10111011
}
10121012

1013+
static void comp_algorithm_set(struct zram *zram, u32 prio, const char *alg)
1014+
{
1015+
/* Do not kfree() algs that we didn't allocate, IOW the default ones */
1016+
if (zram->comp_algs[prio] != default_compressor)
1017+
kfree(zram->comp_algs[prio]);
1018+
zram->comp_algs[prio] = alg;
1019+
}
1020+
10131021
static ssize_t comp_algorithm_store(struct device *dev,
10141022
struct device_attribute *attr, const char *buf, size_t len)
10151023
{
10161024
struct zram *zram = dev_to_zram(dev);
1017-
char compressor[ARRAY_SIZE(zram->compressor)];
1025+
char *compressor;
10181026
size_t sz;
10191027

1020-
strscpy(compressor, buf, sizeof(compressor));
1028+
sz = strlen(buf);
1029+
if (sz >= CRYPTO_MAX_ALG_NAME)
1030+
return -E2BIG;
1031+
1032+
compressor = kstrdup(buf, GFP_KERNEL);
1033+
if (!compressor)
1034+
return -ENOMEM;
1035+
10211036
/* ignore trailing newline */
1022-
sz = strlen(compressor);
10231037
if (sz > 0 && compressor[sz - 1] == '\n')
10241038
compressor[sz - 1] = 0x00;
10251039

1026-
if (!zcomp_available_algorithm(compressor))
1040+
if (!zcomp_available_algorithm(compressor)) {
1041+
kfree(compressor);
10271042
return -EINVAL;
1043+
}
10281044

10291045
down_write(&zram->init_lock);
10301046
if (init_done(zram)) {
10311047
up_write(&zram->init_lock);
1048+
kfree(compressor);
10321049
pr_info("Can't change algorithm for initialized device\n");
10331050
return -EBUSY;
10341051
}
10351052

1036-
strcpy(zram->compressor, compressor);
1053+
comp_algorithm_set(zram, ZRAM_PRIMARY_COMP, compressor);
10371054
up_write(&zram->init_lock);
10381055
return len;
10391056
}
@@ -1281,7 +1298,7 @@ static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index,
12811298
size = zram_get_obj_size(zram, index);
12821299

12831300
if (size != PAGE_SIZE)
1284-
zstrm = zcomp_stream_get(zram->comp);
1301+
zstrm = zcomp_stream_get(zram->comps[ZRAM_PRIMARY_COMP]);
12851302

12861303
src = zs_map_object(zram->mem_pool, handle, ZS_MM_RO);
12871304
if (size == PAGE_SIZE) {
@@ -1293,7 +1310,7 @@ static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index,
12931310
dst = kmap_atomic(page);
12941311
ret = zcomp_decompress(zstrm, src, size, dst);
12951312
kunmap_atomic(dst);
1296-
zcomp_stream_put(zram->comp);
1313+
zcomp_stream_put(zram->comps[ZRAM_PRIMARY_COMP]);
12971314
}
12981315
zs_unmap_object(zram->mem_pool, handle);
12991316
zram_slot_unlock(zram, index);
@@ -1360,13 +1377,13 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec,
13601377
kunmap_atomic(mem);
13611378

13621379
compress_again:
1363-
zstrm = zcomp_stream_get(zram->comp);
1380+
zstrm = zcomp_stream_get(zram->comps[ZRAM_PRIMARY_COMP]);
13641381
src = kmap_atomic(page);
13651382
ret = zcomp_compress(zstrm, src, &comp_len);
13661383
kunmap_atomic(src);
13671384

13681385
if (unlikely(ret)) {
1369-
zcomp_stream_put(zram->comp);
1386+
zcomp_stream_put(zram->comps[ZRAM_PRIMARY_COMP]);
13701387
pr_err("Compression failed! err=%d\n", ret);
13711388
zs_free(zram->mem_pool, handle);
13721389
return ret;
@@ -1394,7 +1411,7 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec,
13941411
__GFP_HIGHMEM |
13951412
__GFP_MOVABLE);
13961413
if (IS_ERR((void *)handle)) {
1397-
zcomp_stream_put(zram->comp);
1414+
zcomp_stream_put(zram->comps[ZRAM_PRIMARY_COMP]);
13981415
atomic64_inc(&zram->stats.writestall);
13991416
handle = zs_malloc(zram->mem_pool, comp_len,
14001417
GFP_NOIO | __GFP_HIGHMEM |
@@ -1411,14 +1428,14 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec,
14111428
* zstrm buffer back. It is necessary that the dereferencing
14121429
* of the zstrm variable below occurs correctly.
14131430
*/
1414-
zstrm = zcomp_stream_get(zram->comp);
1431+
zstrm = zcomp_stream_get(zram->comps[ZRAM_PRIMARY_COMP]);
14151432
}
14161433

14171434
alloced_pages = zs_get_total_pages(zram->mem_pool);
14181435
update_used_max(zram, alloced_pages);
14191436

14201437
if (zram->limit_pages && alloced_pages > zram->limit_pages) {
1421-
zcomp_stream_put(zram->comp);
1438+
zcomp_stream_put(zram->comps[ZRAM_PRIMARY_COMP]);
14221439
zs_free(zram->mem_pool, handle);
14231440
return -ENOMEM;
14241441
}
@@ -1432,7 +1449,7 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec,
14321449
if (comp_len == PAGE_SIZE)
14331450
kunmap_atomic(src);
14341451

1435-
zcomp_stream_put(zram->comp);
1452+
zcomp_stream_put(zram->comps[ZRAM_PRIMARY_COMP]);
14361453
zs_unmap_object(zram->mem_pool, handle);
14371454
atomic64_add(comp_len, &zram->stats.compr_data_size);
14381455
out:
@@ -1707,6 +1724,20 @@ static int zram_rw_page(struct block_device *bdev, sector_t sector,
17071724
return ret;
17081725
}
17091726

1727+
static void zram_destroy_comps(struct zram *zram)
1728+
{
1729+
u32 prio;
1730+
1731+
for (prio = 0; prio < ZRAM_MAX_COMPS; prio++) {
1732+
struct zcomp *comp = zram->comps[prio];
1733+
1734+
zram->comps[prio] = NULL;
1735+
if (!comp)
1736+
continue;
1737+
zcomp_destroy(comp);
1738+
}
1739+
}
1740+
17101741
static void zram_reset_device(struct zram *zram)
17111742
{
17121743
down_write(&zram->init_lock);
@@ -1724,11 +1755,11 @@ static void zram_reset_device(struct zram *zram)
17241755
/* I/O operation under all of CPU are done so let's free */
17251756
zram_meta_free(zram, zram->disksize);
17261757
zram->disksize = 0;
1758+
zram_destroy_comps(zram);
17271759
memset(&zram->stats, 0, sizeof(zram->stats));
1728-
zcomp_destroy(zram->comp);
1729-
zram->comp = NULL;
17301760
reset_bdev(zram);
17311761

1762+
comp_algorithm_set(zram, ZRAM_PRIMARY_COMP, default_compressor);
17321763
up_write(&zram->init_lock);
17331764
}
17341765

@@ -1739,6 +1770,7 @@ static ssize_t disksize_store(struct device *dev,
17391770
struct zcomp *comp;
17401771
struct zram *zram = dev_to_zram(dev);
17411772
int err;
1773+
u32 prio;
17421774

17431775
disksize = memparse(buf, NULL);
17441776
if (!disksize)
@@ -1757,22 +1789,28 @@ static ssize_t disksize_store(struct device *dev,
17571789
goto out_unlock;
17581790
}
17591791

1760-
comp = zcomp_create(zram->compressor);
1761-
if (IS_ERR(comp)) {
1762-
pr_err("Cannot initialise %s compressing backend\n",
1763-
zram->compressor);
1764-
err = PTR_ERR(comp);
1765-
goto out_free_meta;
1766-
}
1792+
for (prio = 0; prio < ZRAM_MAX_COMPS; prio++) {
1793+
if (!zram->comp_algs[prio])
1794+
continue;
1795+
1796+
comp = zcomp_create(zram->comp_algs[prio]);
1797+
if (IS_ERR(comp)) {
1798+
pr_err("Cannot initialise %s compressing backend\n",
1799+
zram->comp_algs[prio]);
1800+
err = PTR_ERR(comp);
1801+
goto out_free_comps;
1802+
}
17671803

1768-
zram->comp = comp;
1804+
zram->comps[prio] = comp;
1805+
}
17691806
zram->disksize = disksize;
17701807
set_capacity_and_notify(zram->disk, zram->disksize >> SECTOR_SHIFT);
17711808
up_write(&zram->init_lock);
17721809

17731810
return len;
17741811

1775-
out_free_meta:
1812+
out_free_comps:
1813+
zram_destroy_comps(zram);
17761814
zram_meta_free(zram, disksize);
17771815
out_unlock:
17781816
up_write(&zram->init_lock);
@@ -1959,7 +1997,7 @@ static int zram_add(void)
19591997
if (ret)
19601998
goto out_cleanup_disk;
19611999

1962-
strscpy(zram->compressor, default_compressor, sizeof(zram->compressor));
2000+
zram->comp_algs[ZRAM_PRIMARY_COMP] = default_compressor;
19632001

19642002
zram_debugfs_register(zram);
19652003
pr_info("Added device: %s\n", zram->disk->disk_name);

drivers/block/zram/zram_drv.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,20 @@ struct zram_stats {
8989
#endif
9090
};
9191

92+
#ifdef CONFIG_ZRAM_MULTI_COMP
93+
#define ZRAM_PRIMARY_COMP 0U
94+
#define ZRAM_SECONDARY_COMP 1U
95+
#define ZRAM_MAX_COMPS 4U
96+
#else
97+
#define ZRAM_PRIMARY_COMP 0U
98+
#define ZRAM_SECONDARY_COMP 0U
99+
#define ZRAM_MAX_COMPS 1U
100+
#endif
101+
92102
struct zram {
93103
struct zram_table_entry *table;
94104
struct zs_pool *mem_pool;
95-
struct zcomp *comp;
105+
struct zcomp *comps[ZRAM_MAX_COMPS];
96106
struct gendisk *disk;
97107
/* Prevent concurrent execution of device init */
98108
struct rw_semaphore init_lock;
@@ -107,7 +117,7 @@ struct zram {
107117
* we can store in a disk.
108118
*/
109119
u64 disksize; /* bytes */
110-
char compressor[CRYPTO_MAX_ALG_NAME];
120+
const char *comp_algs[ZRAM_MAX_COMPS];
111121
/*
112122
* zram is claimed so open request will be failed
113123
*/

0 commit comments

Comments
 (0)