zram_can_store_page() is called after zs_malloc(), so once we reach mem_limit every write that doesn't fit into a partial zspage allocates a new zspage only to free it right away. Check mem_limit in zram_write_page() before compressing the page and allocating from zsmalloc, and update max_used_pages after zs_malloc() succeeds. mem_limit was never a hard limit, the allocation that crosses it happens before the check anyway, so now we can go over the limit by up to one zspage per concurrent writer, and writes fail early until enough slots are freed. Signed-off-by: Sergey Senozhatsky --- Documentation/admin-guide/blockdev/zram.rst | 4 +++- drivers/block/zram/zram_drv.c | 25 +++++++++------------ 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/Documentation/admin-guide/blockdev/zram.rst b/Documentation/admin-guide/blockdev/zram.rst index 148b7cf3b924..db256c53b127 100644 --- a/Documentation/admin-guide/blockdev/zram.rst +++ b/Documentation/admin-guide/blockdev/zram.rst @@ -181,7 +181,9 @@ Set memory limit: Optional Set memory limit by writing the value to sysfs node 'mem_limit'. The value can be either in bytes or you can use mem suffixes. -In addition, you could change the value in runtime. +In addition, you could change the value in runtime. The limit is +checked before zsmalloc allocation, so memory usage may slightly +exceed it (by up to one zspage per concurrent writer). Examples:: # limit /dev/zram0 with 50MB memory diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 2c2e11b2b663..d38b20a22595 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -177,8 +177,9 @@ static void mark_slot_accessed(struct zram *zram, unsigned long index) #endif } -static inline void update_used_max(struct zram *zram, const unsigned long pages) +static inline void update_used_max(struct zram *zram) { + unsigned long pages = zs_get_total_pages(zram->mem_pool); unsigned long cur_max = atomic_long_read(&zram->stats.max_used_pages); do { @@ -190,12 +191,10 @@ static inline void update_used_max(struct zram *zram, const unsigned long pages) static bool zram_can_store_page(struct zram *zram) { - unsigned long alloced_pages; - - alloced_pages = zs_get_total_pages(zram->mem_pool); - update_used_max(zram, alloced_pages); + if (!zram->limit_pages) + return true; - return !zram->limit_pages || alloced_pages <= zram->limit_pages; + return zs_get_total_pages(zram->mem_pool) <= zram->limit_pages; } #if PAGE_SIZE != 4096 @@ -2266,10 +2265,7 @@ static int write_incompressible_page(struct zram *zram, struct page *page, if (IS_ERR(handle)) return PTR_ERR(handle); - if (!zram_can_store_page(zram)) { - zs_free(zram->mem_pool, handle); - return -ENOMEM; - } + update_used_max(zram); src = kmap_local_page(page); zs_obj_write(zram->mem_pool, handle, src, PAGE_SIZE); @@ -2308,6 +2304,9 @@ static int zram_write_page(struct zram *zram, struct page *page, if (same_filled) return write_same_filled_page(zram, element, index); + if (!zram_can_store_page(zram)) + return -ENOMEM; + zstrm = zcomp_cstrm_get(zram->comps[ZRAM_PRIMARY_COMP]); mem = kmap_local_page(page); ret = zcomp_compress(zram->comps[ZRAM_PRIMARY_COMP], zstrm, @@ -2333,11 +2332,7 @@ static int zram_write_page(struct zram *zram, struct page *page, return PTR_ERR(handle); } - if (!zram_can_store_page(zram)) { - zcomp_cstrm_put(zstrm); - zs_free(zram->mem_pool, handle); - return -ENOMEM; - } + update_used_max(zram); zs_obj_write(zram->mem_pool, handle, zstrm->buffer, comp_len); zcomp_cstrm_put(zstrm); -- 2.56.0.506.g506a7eabc5-goog