Parallel concurrent writes to the same zram index result in leaked zsmalloc handles. Schematically we can have something like this:
CPU0 CPU1 zram_slot_lock() zs_free(handle) zram_slot_lock() zram_slot_lock() zs_free(handle) zram_slot_lock()
compress compress handle = zs_malloc() handle = zs_malloc() zram_slot_lock zram_set_handle(handle) zram_slot_lock zram_slot_lock zram_set_handle(handle) zram_slot_lock
Either CPU0 or CPU1 zsmalloc handle will leak because zs_free() is done too early. In fact, we need to reset zram entry right before we set its new handle, all under the same slot lock scope.
Cc: stable@vger.kernel.org Reported-by: Changhui Zhong czhong@redhat.com Closes: https://lore.kernel.org/all/CAGVVp+UtpGoW5WEdEU7uVTtsSCjPN=ksN6EcvyypAtFDOUf... Fixes: 71268035f5d73 ("zram: free slot memory early during write") Signed-off-by: Sergey Senozhatsky senozhatsky@chromium.org --- drivers/block/zram/zram_drv.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 9ac271b82780..dc4a1cdfaf98 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -1788,6 +1788,7 @@ static int write_same_filled_page(struct zram *zram, unsigned long fill, u32 index) { zram_slot_lock(zram, index); + zram_free_page(zram, index); zram_set_flag(zram, index, ZRAM_SAME); zram_set_handle(zram, index, fill); zram_slot_unlock(zram, index); @@ -1820,11 +1821,13 @@ static int write_incompressible_page(struct zram *zram, struct page *page, return -ENOMEM; }
+ zram_slot_lock(zram, index); + zram_free_page(zram, index); + src = kmap_local_page(page); zs_obj_write(zram->mem_pool, handle, src, PAGE_SIZE); kunmap_local(src);
- zram_slot_lock(zram, index); zram_set_flag(zram, index, ZRAM_HUGE); zram_set_handle(zram, index, handle); zram_set_obj_size(zram, index, PAGE_SIZE); @@ -1848,11 +1851,6 @@ static int zram_write_page(struct zram *zram, struct page *page, u32 index) unsigned long element; bool same_filled;
- /* First, free memory allocated to this slot (if any) */ - zram_slot_lock(zram, index); - zram_free_page(zram, index); - zram_slot_unlock(zram, index); - mem = kmap_local_page(page); same_filled = page_same_filled(mem, &element); kunmap_local(mem); @@ -1890,10 +1888,11 @@ static int zram_write_page(struct zram *zram, struct page *page, u32 index) return -ENOMEM; }
+ zram_slot_lock(zram, index); + zram_free_page(zram, index); zs_obj_write(zram->mem_pool, handle, zstrm->buffer, comp_len); zcomp_stream_put(zstrm);
- zram_slot_lock(zram, index); zram_set_handle(zram, index, handle); zram_set_obj_size(zram, index, comp_len); zram_slot_unlock(zram, index);
On (25/09/09 13:30), Sergey Senozhatsky wrote:
@@ -1848,11 +1851,6 @@ static int zram_write_page(struct zram *zram, struct page *page, u32 index) unsigned long element; bool same_filled;
- /* First, free memory allocated to this slot (if any) */
- zram_slot_lock(zram, index);
- zram_free_page(zram, index);
- zram_slot_unlock(zram, index);
- mem = kmap_local_page(page); same_filled = page_same_filled(mem, &element); kunmap_local(mem);
@@ -1890,10 +1888,11 @@ static int zram_write_page(struct zram *zram, struct page *page, u32 index) return -ENOMEM; }
- zram_slot_lock(zram, index);
- zram_free_page(zram, index); zs_obj_write(zram->mem_pool, handle, zstrm->buffer, comp_len); zcomp_stream_put(zstrm);
- zram_slot_lock(zram, index); zram_set_handle(zram, index, handle); zram_set_obj_size(zram, index, comp_len); zram_slot_unlock(zram, index);
Let me send v2 shortly. I don't think I like overlapping of slot-lock and stream-lock scopes.
linux-stable-mirror@lists.linaro.org