| From: Mike Galbraith <umgwanakikbuti@gmail.com> |
| Date: Thu, 20 Oct 2016 11:15:22 +0200 |
| Subject: [PATCH] drivers/zram: Don't disable preemption in |
| zcomp_stream_get/put() |
| |
| In v4.7, the driver switched to percpu compression streams, disabling |
| preemption via get/put_cpu_ptr(). Use a per-zcomp_strm lock here. We |
| also have to fix an lock order issue in zram_decompress_page() such |
| that zs_map_object() nests inside of zcomp_stream_put() as it does in |
| zram_bvec_write(). |
| |
| Signed-off-by: Mike Galbraith <umgwanakikbuti@gmail.com> |
| [bigeasy: get_locked_var() -> per zcomp_strm lock] |
| Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| --- |
| drivers/block/zram/zcomp.c | 12 ++++++++++-- |
| drivers/block/zram/zcomp.h | 1 + |
| drivers/block/zram/zram_drv.c | 5 +++-- |
| 3 files changed, 14 insertions(+), 4 deletions(-) |
| |
| --- a/drivers/block/zram/zcomp.c |
| +++ b/drivers/block/zram/zcomp.c |
| @@ -116,12 +116,19 @@ ssize_t zcomp_available_show(const char |
| |
| struct zcomp_strm *zcomp_stream_get(struct zcomp *comp) |
| { |
| - return *get_cpu_ptr(comp->stream); |
| + struct zcomp_strm *zstrm; |
| + |
| + zstrm = *this_cpu_ptr(comp->stream); |
| + spin_lock(&zstrm->zcomp_lock); |
| + return zstrm; |
| } |
| |
| void zcomp_stream_put(struct zcomp *comp) |
| { |
| - put_cpu_ptr(comp->stream); |
| + struct zcomp_strm *zstrm; |
| + |
| + zstrm = *this_cpu_ptr(comp->stream); |
| + spin_unlock(&zstrm->zcomp_lock); |
| } |
| |
| int zcomp_compress(struct zcomp_strm *zstrm, |
| @@ -171,6 +178,7 @@ int zcomp_cpu_up_prepare(unsigned int cp |
| pr_err("Can't allocate a compression stream\n"); |
| return -ENOMEM; |
| } |
| + spin_lock_init(&zstrm->zcomp_lock); |
| *per_cpu_ptr(comp->stream, cpu) = zstrm; |
| return 0; |
| } |
| --- a/drivers/block/zram/zcomp.h |
| +++ b/drivers/block/zram/zcomp.h |
| @@ -14,6 +14,7 @@ struct zcomp_strm { |
| /* compression/decompression buffer */ |
| void *buffer; |
| struct crypto_comp *tfm; |
| + spinlock_t zcomp_lock; |
| }; |
| |
| /* dynamic per-device compression frontend */ |
| --- a/drivers/block/zram/zram_drv.c |
| +++ b/drivers/block/zram/zram_drv.c |
| @@ -863,6 +863,7 @@ static int __zram_bvec_read(struct zram |
| unsigned long handle; |
| unsigned int size; |
| void *src, *dst; |
| + struct zcomp_strm *zstrm; |
| |
| if (zram_wb_enabled(zram)) { |
| zram_slot_lock(zram, index); |
| @@ -897,6 +898,7 @@ static int __zram_bvec_read(struct zram |
| |
| size = zram_get_obj_size(zram, index); |
| |
| + zstrm = zcomp_stream_get(zram->comp); |
| src = zs_map_object(zram->mem_pool, handle, ZS_MM_RO); |
| if (size == PAGE_SIZE) { |
| dst = kmap_atomic(page); |
| @@ -904,14 +906,13 @@ static int __zram_bvec_read(struct zram |
| kunmap_atomic(dst); |
| ret = 0; |
| } else { |
| - struct zcomp_strm *zstrm = zcomp_stream_get(zram->comp); |
| |
| dst = kmap_atomic(page); |
| ret = zcomp_decompress(zstrm, src, size, dst); |
| kunmap_atomic(dst); |
| - zcomp_stream_put(zram->comp); |
| } |
| zs_unmap_object(zram->mem_pool, handle); |
| + zcomp_stream_put(zram->comp); |
| zram_slot_unlock(zram, index); |
| |
| /* Should NEVER happen. Return bio error if it does. */ |