* [PATCH 1/2] zram: factor-out zram_decompress_page() function
@ 2012-10-27 16:00 Sergey Senozhatsky
2012-10-29 17:14 ` Nitin Gupta
0 siblings, 1 reply; 14+ messages in thread
From: Sergey Senozhatsky @ 2012-10-27 16:00 UTC (permalink / raw)
To: Nitin Gupta; +Cc: Greg Kroah-Hartman, linux-kernel
zram: factor-out zram_decompress_page() function
zram_bvec_read() shared decompress functionality with zram_read_before_write() function.
Factor-out and make commonly used zram_decompress_page() function, which also simplified
error handling in zram_bvec_read().
Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
---
drivers/staging/zram/zram_drv.c | 115 +++++++++++++++++-----------------------
1 file changed, 50 insertions(+), 65 deletions(-)
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
index 6edefde..7585467 100644
--- a/drivers/staging/zram/zram_drv.c
+++ b/drivers/staging/zram/zram_drv.c
@@ -183,62 +183,25 @@ static inline int is_partial_io(struct bio_vec *bvec)
return bvec->bv_len != PAGE_SIZE;
}
-static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
- u32 index, int offset, struct bio *bio)
+static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
{
- int ret;
- size_t clen;
- struct page *page;
- unsigned char *user_mem, *cmem, *uncmem = NULL;
-
- page = bvec->bv_page;
-
- if (zram_test_flag(zram, index, ZRAM_ZERO)) {
- handle_zero_page(bvec);
- return 0;
- }
+ int ret = LZO_E_OK;
+ size_t clen = PAGE_SIZE;
+ unsigned char *cmem;
+ unsigned long handle = zram->table[index].handle;
- /* Requested page is not present in compressed area */
- if (unlikely(!zram->table[index].handle)) {
- pr_debug("Read before write: sector=%lu, size=%u",
- (ulong)(bio->bi_sector), bio->bi_size);
- handle_zero_page(bvec);
+ if (!handle || zram_test_flag(zram, index, ZRAM_ZERO)) {
+ memset(mem, 0, PAGE_SIZE);
return 0;
}
- if (is_partial_io(bvec)) {
- /* Use a temporary buffer to decompress the page */
- uncmem = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!uncmem) {
- pr_info("Error allocating temp memory!\n");
- return -ENOMEM;
- }
- }
-
- user_mem = kmap_atomic(page);
- if (!is_partial_io(bvec))
- uncmem = user_mem;
- clen = PAGE_SIZE;
-
- cmem = zs_map_object(zram->mem_pool, zram->table[index].handle,
- ZS_MM_RO);
-
- if (zram->table[index].size == PAGE_SIZE) {
- memcpy(uncmem, cmem, PAGE_SIZE);
- ret = LZO_E_OK;
- } else {
+ cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_RO);
+ if (zram->table[index].size == PAGE_SIZE)
+ memcpy(mem, cmem, PAGE_SIZE);
+ else
ret = lzo1x_decompress_safe(cmem, zram->table[index].size,
- uncmem, &clen);
- }
-
- if (is_partial_io(bvec)) {
- memcpy(user_mem + bvec->bv_offset, uncmem + offset,
- bvec->bv_len);
- kfree(uncmem);
- }
-
- zs_unmap_object(zram->mem_pool, zram->table[index].handle);
- kunmap_atomic(user_mem);
+ mem, &clen);
+ zs_unmap_object(zram->mem_pool, handle);
/* Should NEVER happen. Return bio error if it does. */
if (unlikely(ret != LZO_E_OK)) {
@@ -247,36 +210,58 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
return ret;
}
- flush_dcache_page(page);
-
return 0;
}
-static int zram_read_before_write(struct zram *zram, char *mem, u32 index)
+static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
+ u32 index, int offset, struct bio *bio)
{
int ret;
- size_t clen = PAGE_SIZE;
- unsigned char *cmem;
- unsigned long handle = zram->table[index].handle;
+ struct page *page;
+ unsigned char *user_mem, *uncmem = NULL;
- if (zram_test_flag(zram, index, ZRAM_ZERO) || !handle) {
- memset(mem, 0, PAGE_SIZE);
+ page = bvec->bv_page;
+
+ if (unlikely(!zram->table[index].handle) ||
+ zram_test_flag(zram, index, ZRAM_ZERO)) {
+ pr_debug("Read before write: sector=%lu, size=%u",
+ (ulong)(bio->bi_sector), bio->bi_size);
+ handle_zero_page(bvec);
return 0;
}
- cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_RO);
- ret = lzo1x_decompress_safe(cmem, zram->table[index].size,
- mem, &clen);
- zs_unmap_object(zram->mem_pool, handle);
+ user_mem = kmap_atomic(page);
+ if (is_partial_io(bvec))
+ /* Use a temporary buffer to decompress the page */
+ uncmem = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ else
+ uncmem = user_mem;
+ if (!uncmem) {
+ pr_info("Unable to allocate temp memory\n");
+ ret = -ENOMEM;
+ goto out_cleanup;
+ }
+
+ ret = zram_decompress_page(zram, uncmem, index);
/* Should NEVER happen. Return bio error if it does. */
if (unlikely(ret != LZO_E_OK)) {
pr_err("Decompression failed! err=%d, page=%u\n", ret, index);
zram_stat64_inc(zram, &zram->stats.failed_reads);
- return ret;
+ goto out_cleanup;
}
- return 0;
+ if (is_partial_io(bvec))
+ memcpy(user_mem + bvec->bv_offset, uncmem + offset,
+ bvec->bv_len);
+
+ flush_dcache_page(page);
+ ret = 0;
+out_cleanup:
+ kunmap_atomic(user_mem);
+ if (is_partial_io(bvec))
+ kfree(uncmem);
+ return ret;
}
static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
@@ -302,7 +287,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
ret = -ENOMEM;
goto out;
}
- ret = zram_read_before_write(zram, uncmem, index);
+ ret = zram_decompress_page(zram, uncmem, index);
if (ret) {
kfree(uncmem);
goto out;
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] zram: factor-out zram_decompress_page() function
2012-10-27 16:00 [PATCH 1/2] zram: factor-out zram_decompress_page() function Sergey Senozhatsky
@ 2012-10-29 17:14 ` Nitin Gupta
2012-10-29 17:33 ` Sergey Senozhatsky
2012-10-30 21:04 ` Sergey Senozhatsky
0 siblings, 2 replies; 14+ messages in thread
From: Nitin Gupta @ 2012-10-29 17:14 UTC (permalink / raw)
To: Sergey Senozhatsky; +Cc: Greg Kroah-Hartman, Fengguang Wu, linux-kernel
On 10/27/2012 09:00 AM, Sergey Senozhatsky wrote:
> zram: factor-out zram_decompress_page() function
>
> zram_bvec_read() shared decompress functionality with zram_read_before_write() function.
> Factor-out and make commonly used zram_decompress_page() function, which also simplified
> error handling in zram_bvec_read().
>
> Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
>
> ---
>
> drivers/staging/zram/zram_drv.c | 115 +++++++++++++++++-----------------------
> 1 file changed, 50 insertions(+), 65 deletions(-)
>
> diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
> index 6edefde..7585467 100644
> --- a/drivers/staging/zram/zram_drv.c
> +++ b/drivers/staging/zram/zram_drv.c
> @@ -183,62 +183,25 @@ static inline int is_partial_io(struct bio_vec *bvec)
> return bvec->bv_len != PAGE_SIZE;
> }
>
> -static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
> - u32 index, int offset, struct bio *bio)
> +static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
> {
> - int ret;
> - size_t clen;
> - struct page *page;
> - unsigned char *user_mem, *cmem, *uncmem = NULL;
> -
> - page = bvec->bv_page;
> -
> - if (zram_test_flag(zram, index, ZRAM_ZERO)) {
> - handle_zero_page(bvec);
> - return 0;
> - }
> + int ret = LZO_E_OK;
> + size_t clen = PAGE_SIZE;
> + unsigned char *cmem;
> + unsigned long handle = zram->table[index].handle;
>
> - /* Requested page is not present in compressed area */
> - if (unlikely(!zram->table[index].handle)) {
> - pr_debug("Read before write: sector=%lu, size=%u",
> - (ulong)(bio->bi_sector), bio->bi_size);
> - handle_zero_page(bvec);
> + if (!handle || zram_test_flag(zram, index, ZRAM_ZERO)) {
> + memset(mem, 0, PAGE_SIZE);
> return 0;
> }
>
> - if (is_partial_io(bvec)) {
> - /* Use a temporary buffer to decompress the page */
> - uncmem = kmalloc(PAGE_SIZE, GFP_KERNEL);
> - if (!uncmem) {
> - pr_info("Error allocating temp memory!\n");
> - return -ENOMEM;
> - }
> - }
> -
> - user_mem = kmap_atomic(page);
> - if (!is_partial_io(bvec))
> - uncmem = user_mem;
> - clen = PAGE_SIZE;
> -
> - cmem = zs_map_object(zram->mem_pool, zram->table[index].handle,
> - ZS_MM_RO);
> -
> - if (zram->table[index].size == PAGE_SIZE) {
> - memcpy(uncmem, cmem, PAGE_SIZE);
> - ret = LZO_E_OK;
> - } else {
> + cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_RO);
> + if (zram->table[index].size == PAGE_SIZE)
> + memcpy(mem, cmem, PAGE_SIZE);
> + else
> ret = lzo1x_decompress_safe(cmem, zram->table[index].size,
> - uncmem, &clen);
> - }
> -
> - if (is_partial_io(bvec)) {
> - memcpy(user_mem + bvec->bv_offset, uncmem + offset,
> - bvec->bv_len);
> - kfree(uncmem);
> - }
> -
> - zs_unmap_object(zram->mem_pool, zram->table[index].handle);
> - kunmap_atomic(user_mem);
> + mem, &clen);
> + zs_unmap_object(zram->mem_pool, handle);
>
> /* Should NEVER happen. Return bio error if it does. */
> if (unlikely(ret != LZO_E_OK)) {
> @@ -247,36 +210,58 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
> return ret;
> }
>
> - flush_dcache_page(page);
> -
> return 0;
> }
>
> -static int zram_read_before_write(struct zram *zram, char *mem, u32 index)
> +static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
> + u32 index, int offset, struct bio *bio)
> {
> int ret;
> - size_t clen = PAGE_SIZE;
> - unsigned char *cmem;
> - unsigned long handle = zram->table[index].handle;
> + struct page *page;
> + unsigned char *user_mem, *uncmem = NULL;
>
> - if (zram_test_flag(zram, index, ZRAM_ZERO) || !handle) {
> - memset(mem, 0, PAGE_SIZE);
> + page = bvec->bv_page;
> +
> + if (unlikely(!zram->table[index].handle) ||
> + zram_test_flag(zram, index, ZRAM_ZERO)) {
> + pr_debug("Read before write: sector=%lu, size=%u",
> + (ulong)(bio->bi_sector), bio->bi_size);
"Read before write" message is not valid in case ZRAM_ZERO flag is set.
Its true only in !handle case.
Otherwise, the patch looks good to me.
On a side note, zram still contains a known use-after-free bug reported
by Fengguang Wu (CC'ed) which happens in the "partial I/O" i.e. non
PAGE_SIZE'ed I/O case which is fixed by the following patch.
Please let me know if you can include the following patch when you
resend this patch series, or I can do the same or will wait for this to
be merged and then send it later.
======
zram: Fix use-after-free in partial I/O case
When the compressed size of a page exceeds a threshold, the page is
stored as-is i.e. in uncompressed form. In the partial I/O i.e.
non-PAGE_SIZE'ed I/O case, however, the uncompressed memory was being
freed before it could be copied into the zsmalloc pool resulting in
use-after-free bug.
Signed-off-by: Nitin Gupta <ngupta@vflare.org>
---
diff --git a/drivers/staging/zram/zram_drv.c
b/drivers/staging/zram/zram_drv.c
index 7585467..635736b 100644
--- a/drivers/staging/zram/zram_drv.c
+++ b/drivers/staging/zram/zram_drv.c
@@ -288,10 +288,8 @@ static int zram_bvec_write(struct zram *zram,
struct bio_vec *bvec, u32 index,
goto out;
}
ret = zram_decompress_page(zram, uncmem, index);
- if (ret) {
- kfree(uncmem);
+ if (ret)
goto out;
- }
}
/*
@@ -312,8 +310,6 @@ static int zram_bvec_write(struct zram *zram, struct
bio_vec *bvec, u32 index,
if (page_zero_filled(uncmem)) {
kunmap_atomic(user_mem);
- if (is_partial_io(bvec))
- kfree(uncmem);
zram_stat_inc(&zram->stats.pages_zero);
zram_set_flag(zram, index, ZRAM_ZERO);
ret = 0;
@@ -324,8 +320,6 @@ static int zram_bvec_write(struct zram *zram, struct
bio_vec *bvec, u32 index,
zram->compress_workmem);
kunmap_atomic(user_mem);
- if (is_partial_io(bvec))
- kfree(uncmem);
if (unlikely(ret != LZO_E_OK)) {
pr_err("Compression failed! err=%d\n", ret);
@@ -360,11 +354,15 @@ static int zram_bvec_write(struct zram *zram,
struct bio_vec *bvec, u32 index,
if (clen <= PAGE_SIZE / 2)
zram_stat_inc(&zram->stats.good_compress);
- return 0;
+ ret = 0;
out:
if (ret)
zram_stat64_inc(zram, &zram->stats.failed_writes);
+
+ if (is_partial_io(bvec))
+ kfree(uncmem);
+
return ret;
}
BTW, I could not trigger this partial I/O case, so please let me know if
you hit any issue during your testing.
There is another sparse warning to be fixed: zram_reset_device should be
static.
Thanks,
Nitin
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] zram: factor-out zram_decompress_page() function
2012-10-29 17:14 ` Nitin Gupta
@ 2012-10-29 17:33 ` Sergey Senozhatsky
2012-10-30 21:04 ` Sergey Senozhatsky
1 sibling, 0 replies; 14+ messages in thread
From: Sergey Senozhatsky @ 2012-10-29 17:33 UTC (permalink / raw)
To: Nitin Gupta; +Cc: Greg Kroah-Hartman, Fengguang Wu, linux-kernel
On (10/29/12 10:14), Nitin Gupta wrote:
>
> "Read before write" message is not valid in case ZRAM_ZERO flag is
> set. Its true only in !handle case.
>
do we actually need this message?
> Otherwise, the patch looks good to me.
>
> On a side note, zram still contains a known use-after-free bug
> reported by Fengguang Wu (CC'ed) which happens in the "partial I/O"
> i.e. non PAGE_SIZE'ed I/O case which is fixed by the following patch.
>
> Please let me know if you can include the following patch when you
> resend this patch series, or I can do the same or will wait for this
> to be merged and then send it later.
>
Nitin, I think let's deal with one change at a time. I'll try to resend my patch
shortly, then we can continue with your fix (I didn't hit that problem, though
will be happy to help with testing).
-ss
> ======
> zram: Fix use-after-free in partial I/O case
>
> When the compressed size of a page exceeds a threshold, the page is
> stored as-is i.e. in uncompressed form. In the partial I/O i.e.
> non-PAGE_SIZE'ed I/O case, however, the uncompressed memory was being
> freed before it could be copied into the zsmalloc pool resulting in
> use-after-free bug.
>
> Signed-off-by: Nitin Gupta <ngupta@vflare.org>
> ---
>
> diff --git a/drivers/staging/zram/zram_drv.c
> b/drivers/staging/zram/zram_drv.c
> index 7585467..635736b 100644
> --- a/drivers/staging/zram/zram_drv.c
> +++ b/drivers/staging/zram/zram_drv.c
> @@ -288,10 +288,8 @@ static int zram_bvec_write(struct zram *zram,
> struct bio_vec *bvec, u32 index,
> goto out;
> }
> ret = zram_decompress_page(zram, uncmem, index);
> - if (ret) {
> - kfree(uncmem);
> + if (ret)
> goto out;
> - }
> }
>
> /*
> @@ -312,8 +310,6 @@ static int zram_bvec_write(struct zram *zram,
> struct bio_vec *bvec, u32 index,
>
> if (page_zero_filled(uncmem)) {
> kunmap_atomic(user_mem);
> - if (is_partial_io(bvec))
> - kfree(uncmem);
> zram_stat_inc(&zram->stats.pages_zero);
> zram_set_flag(zram, index, ZRAM_ZERO);
> ret = 0;
> @@ -324,8 +320,6 @@ static int zram_bvec_write(struct zram *zram,
> struct bio_vec *bvec, u32 index,
> zram->compress_workmem);
>
> kunmap_atomic(user_mem);
> - if (is_partial_io(bvec))
> - kfree(uncmem);
>
> if (unlikely(ret != LZO_E_OK)) {
> pr_err("Compression failed! err=%d\n", ret);
> @@ -360,11 +354,15 @@ static int zram_bvec_write(struct zram *zram,
> struct bio_vec *bvec, u32 index,
> if (clen <= PAGE_SIZE / 2)
> zram_stat_inc(&zram->stats.good_compress);
>
> - return 0;
> + ret = 0;
>
> out:
> if (ret)
> zram_stat64_inc(zram, &zram->stats.failed_writes);
> +
> + if (is_partial_io(bvec))
> + kfree(uncmem);
> +
> return ret;
> }
>
>
> BTW, I could not trigger this partial I/O case, so please let me know
> if you hit any issue during your testing.
>
> There is another sparse warning to be fixed: zram_reset_device should
> be static.
>
> Thanks,
> Nitin
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 2/2] zram: permit sleeping while in pool zs_malloc()
@ 2012-10-30 9:03 Sergey Senozhatsky
2012-10-30 18:04 ` Greg Kroah-Hartman
0 siblings, 1 reply; 14+ messages in thread
From: Sergey Senozhatsky @ 2012-10-30 9:03 UTC (permalink / raw)
To: Nitin Gupta; +Cc: Greg Kroah-Hartman, linux-kernel
zram: permit sleeping while in pool zs_malloc()
zram pool is created with GFP_NOIO flag, which may trigger errors because nested allocation
are able to sleep. set __GFP_WAIT pool flag in zram_init_device() to allow sleeping.
BUG: sleeping function called from invalid context at mm/page_alloc.c:2603
in_atomic(): 1, irqs_disabled(): 0, pid: 2555, name: mkfs.reiserfs
2 locks held by mkfs.reiserfs/2555:
#0: (&zram->init_lock){+++++.}, at: [<ffffffffa0127d18>] zram_make_request+0x48/0x270 [zram]
#1: (&zram->lock){++++..}, at: [<ffffffffa012742b>] zram_bvec_rw+0x3b/0x510 [zram]
Pid: 2555, comm: mkfs.reiserfs Tainted: G C 3.7.0-rc3-dbg-01664-gf2d9543-dirty #1401
Call Trace:
[<ffffffff8107984a>] __might_sleep+0x15a/0x250
[<ffffffff8111df9b>] __alloc_pages_nodemask+0x1bb/0x920
[<ffffffffa00f0b93>] ? zs_malloc+0x63/0x480 [zsmalloc]
[<ffffffff81320e2d>] ? do_raw_spin_unlock+0x5d/0xb0
[<ffffffffa00f0cf5>] zs_malloc+0x1c5/0x480 [zsmalloc]
[<ffffffffa0127574>] zram_bvec_rw+0x184/0x510 [zram]
[<ffffffffa0127e85>] zram_make_request+0x1b5/0x270 [zram]
[<ffffffff812ec0c2>] generic_make_request+0xc2/0x110
[<ffffffff812ec17a>] submit_bio+0x6a/0x140
[<ffffffff8119f27b>] submit_bh+0xfb/0x130
[<ffffffff811a2710>] __block_write_full_page+0x220/0x3d0
[<ffffffff810a7784>] ? __lock_is_held+0x54/0x80
[<ffffffff8119ffb0>] ? end_buffer_async_read+0x210/0x210
[<ffffffff811a7aa0>] ? blkdev_get_blocks+0xd0/0xd0
[<ffffffff811a7aa0>] ? blkdev_get_blocks+0xd0/0xd0
[<ffffffff8119ffb0>] ? end_buffer_async_read+0x210/0x210
[<ffffffff811a298f>] block_write_full_page_endio+0xcf/0x100
[<ffffffff8111f555>] ? clear_page_dirty_for_io+0x105/0x130
[<ffffffff811a29d5>] block_write_full_page+0x15/0x20
[<ffffffff811a7038>] blkdev_writepage+0x18/0x20
[<ffffffff8111f3aa>] __writepage+0x1a/0x50
[<ffffffff8111f8b0>] write_cache_pages+0x200/0x630
[<ffffffff8111e883>] ? free_hot_cold_page+0x113/0x1a0
[<ffffffff8111f390>] ? global_dirtyable_memory+0x40/0x40
[<ffffffff8111fd2d>] generic_writepages+0x4d/0x70
[<ffffffff81121071>] do_writepages+0x21/0x50
[<ffffffff81116939>] __filemap_fdatawrite_range+0x59/0x60
[<ffffffff81116a40>] filemap_write_and_wait_range+0x50/0x70
[<ffffffff811a73a4>] blkdev_fsync+0x24/0x50
[<ffffffff8119d5bd>] do_fsync+0x5d/0x90
[<ffffffff8119d990>] sys_fsync+0x10/0x20
[<ffffffff815dce06>] tracesys+0xd4/0xd9
Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
---
drivers/staging/zram/zram_drv.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
index d2e0a85..47f2e3a 100644
--- a/drivers/staging/zram/zram_drv.c
+++ b/drivers/staging/zram/zram_drv.c
@@ -576,7 +576,7 @@ int zram_init_device(struct zram *zram)
/* zram devices sort of resembles non-rotational disks */
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue);
- zram->mem_pool = zs_create_pool("zram", GFP_NOIO | __GFP_HIGHMEM);
+ zram->mem_pool = zs_create_pool("zram", GFP_NOIO | __GFP_WAIT | __GFP_HIGHMEM);
if (!zram->mem_pool) {
pr_err("Error creating memory pool\n");
ret = -ENOMEM;
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 2/2] zram: permit sleeping while in pool zs_malloc()
2012-10-30 9:03 [PATCH 2/2] zram: permit sleeping while in pool zs_malloc() Sergey Senozhatsky
@ 2012-10-30 18:04 ` Greg Kroah-Hartman
2012-10-30 18:49 ` Sergey Senozhatsky
` (3 more replies)
0 siblings, 4 replies; 14+ messages in thread
From: Greg Kroah-Hartman @ 2012-10-30 18:04 UTC (permalink / raw)
To: Sergey Senozhatsky; +Cc: Nitin Gupta, linux-kernel
On Tue, Oct 30, 2012 at 12:03:19PM +0300, Sergey Senozhatsky wrote:
> zram: permit sleeping while in pool zs_malloc()
2/2? Huh? Where is 1/2?
I have a raft of patches from you, all out of order, and full of
responses from Nitin, and so, I really have no idea what should and
should not be applied here.
So, I'm dropping them all. Please work with Nitin to get a series of
patches that are acceptable and resend them with the proper numbering.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 2/2] zram: permit sleeping while in pool zs_malloc()
2012-10-30 18:04 ` Greg Kroah-Hartman
@ 2012-10-30 18:49 ` Sergey Senozhatsky
2012-10-30 19:18 ` Greg Kroah-Hartman
2012-10-30 18:56 ` [PATCH 0/2] zram decompress_page and zram_sysfs patch seriess Sergey Senozhatsky
` (2 subsequent siblings)
3 siblings, 1 reply; 14+ messages in thread
From: Sergey Senozhatsky @ 2012-10-30 18:49 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: Nitin Gupta, linux-kernel
On (10/30/12 11:04), Greg Kroah-Hartman wrote:
> On Tue, Oct 30, 2012 at 12:03:19PM +0300, Sergey Senozhatsky wrote:
> > zram: permit sleeping while in pool zs_malloc()
>
> 2/2? Huh? Where is 1/2?
>
> I have a raft of patches from you, all out of order, and full of
> responses from Nitin, and so, I really have no idea what should and
> should not be applied here.
>
> So, I'm dropping them all. Please work with Nitin to get a series of
> patches that are acceptable and resend them with the proper numbering.
>
those were two separate series.
the first one:
[PATCH 1/2] zram: factor-out zram_decompress_page() function
[PATCH 2/2] zram: handle mem suffixes in disk size zram_sysfs parameter
ACKed by Nitin.
the second one
[PATCH 2/2] zram: permit sleeping while in pool zs_malloc()
[PATCH 1/2] zram: forbid IO operations from within zram_init_device() -- droppped by me.
I'll resend first two and next time will make sure not to spam your box. sorry.
-ss
> thanks,
>
> greg k-h
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 0/2] zram decompress_page and zram_sysfs patch seriess
2012-10-30 18:04 ` Greg Kroah-Hartman
2012-10-30 18:49 ` Sergey Senozhatsky
@ 2012-10-30 18:56 ` Sergey Senozhatsky
2012-10-30 18:58 ` [PATCH 1/2] zram: factor-out zram_decompress_page() function Sergey Senozhatsky
2012-10-30 19:00 ` [PATCH 2/2] zram: handle mem suffixes in disk size zram_sysfs parameter Sergey Senozhatsky
3 siblings, 0 replies; 14+ messages in thread
From: Sergey Senozhatsky @ 2012-10-30 18:56 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: Nitin Gupta, linux-kernel
Hello Greg,
I'm gonna send you 2 zram patches shortly, reviewed by Nitin.
[PATCH 1/2] zram: factor-out zram_decompress_page() function
[PATCH 2/2] zram: handle mem suffixes in disk size zram_sysfs parameter
Thanks,
-ss
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/2] zram: factor-out zram_decompress_page() function
2012-10-30 18:04 ` Greg Kroah-Hartman
2012-10-30 18:49 ` Sergey Senozhatsky
2012-10-30 18:56 ` [PATCH 0/2] zram decompress_page and zram_sysfs patch seriess Sergey Senozhatsky
@ 2012-10-30 18:58 ` Sergey Senozhatsky
2012-10-30 19:18 ` Greg Kroah-Hartman
2012-10-30 19:00 ` [PATCH 2/2] zram: handle mem suffixes in disk size zram_sysfs parameter Sergey Senozhatsky
3 siblings, 1 reply; 14+ messages in thread
From: Sergey Senozhatsky @ 2012-10-30 18:58 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: Nitin Gupta, linux-kernel
zram: factor-out zram_decompress_page() function
zram_bvec_read() shared decompress functionality with zram_read_before_write() function.
Factor-out and make commonly used zram_decompress_page() function, which also simplified
error handling in zram_bvec_read().
Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
---
drivers/staging/zram/zram_drv.c | 113 +++++++++++++++++-----------------------
1 file changed, 48 insertions(+), 65 deletions(-)
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
index 6edefde..fb4a7c9 100644
--- a/drivers/staging/zram/zram_drv.c
+++ b/drivers/staging/zram/zram_drv.c
@@ -183,62 +183,25 @@ static inline int is_partial_io(struct bio_vec *bvec)
return bvec->bv_len != PAGE_SIZE;
}
-static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
- u32 index, int offset, struct bio *bio)
+static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
{
- int ret;
- size_t clen;
- struct page *page;
- unsigned char *user_mem, *cmem, *uncmem = NULL;
-
- page = bvec->bv_page;
-
- if (zram_test_flag(zram, index, ZRAM_ZERO)) {
- handle_zero_page(bvec);
- return 0;
- }
+ int ret = LZO_E_OK;
+ size_t clen = PAGE_SIZE;
+ unsigned char *cmem;
+ unsigned long handle = zram->table[index].handle;
- /* Requested page is not present in compressed area */
- if (unlikely(!zram->table[index].handle)) {
- pr_debug("Read before write: sector=%lu, size=%u",
- (ulong)(bio->bi_sector), bio->bi_size);
- handle_zero_page(bvec);
+ if (!handle || zram_test_flag(zram, index, ZRAM_ZERO)) {
+ memset(mem, 0, PAGE_SIZE);
return 0;
}
- if (is_partial_io(bvec)) {
- /* Use a temporary buffer to decompress the page */
- uncmem = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!uncmem) {
- pr_info("Error allocating temp memory!\n");
- return -ENOMEM;
- }
- }
-
- user_mem = kmap_atomic(page);
- if (!is_partial_io(bvec))
- uncmem = user_mem;
- clen = PAGE_SIZE;
-
- cmem = zs_map_object(zram->mem_pool, zram->table[index].handle,
- ZS_MM_RO);
-
- if (zram->table[index].size == PAGE_SIZE) {
- memcpy(uncmem, cmem, PAGE_SIZE);
- ret = LZO_E_OK;
- } else {
+ cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_RO);
+ if (zram->table[index].size == PAGE_SIZE)
+ memcpy(mem, cmem, PAGE_SIZE);
+ else
ret = lzo1x_decompress_safe(cmem, zram->table[index].size,
- uncmem, &clen);
- }
-
- if (is_partial_io(bvec)) {
- memcpy(user_mem + bvec->bv_offset, uncmem + offset,
- bvec->bv_len);
- kfree(uncmem);
- }
-
- zs_unmap_object(zram->mem_pool, zram->table[index].handle);
- kunmap_atomic(user_mem);
+ mem, &clen);
+ zs_unmap_object(zram->mem_pool, handle);
/* Should NEVER happen. Return bio error if it does. */
if (unlikely(ret != LZO_E_OK)) {
@@ -247,36 +210,56 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
return ret;
}
- flush_dcache_page(page);
-
return 0;
}
-static int zram_read_before_write(struct zram *zram, char *mem, u32 index)
+static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
+ u32 index, int offset, struct bio *bio)
{
int ret;
- size_t clen = PAGE_SIZE;
- unsigned char *cmem;
- unsigned long handle = zram->table[index].handle;
+ struct page *page;
+ unsigned char *user_mem, *uncmem = NULL;
- if (zram_test_flag(zram, index, ZRAM_ZERO) || !handle) {
- memset(mem, 0, PAGE_SIZE);
+ page = bvec->bv_page;
+
+ if (unlikely(!zram->table[index].handle) ||
+ zram_test_flag(zram, index, ZRAM_ZERO)) {
+ handle_zero_page(bvec);
return 0;
}
- cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_RO);
- ret = lzo1x_decompress_safe(cmem, zram->table[index].size,
- mem, &clen);
- zs_unmap_object(zram->mem_pool, handle);
+ user_mem = kmap_atomic(page);
+ if (is_partial_io(bvec))
+ /* Use a temporary buffer to decompress the page */
+ uncmem = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ else
+ uncmem = user_mem;
+ if (!uncmem) {
+ pr_info("Unable to allocate temp memory\n");
+ ret = -ENOMEM;
+ goto out_cleanup;
+ }
+
+ ret = zram_decompress_page(zram, uncmem, index);
/* Should NEVER happen. Return bio error if it does. */
if (unlikely(ret != LZO_E_OK)) {
pr_err("Decompression failed! err=%d, page=%u\n", ret, index);
zram_stat64_inc(zram, &zram->stats.failed_reads);
- return ret;
+ goto out_cleanup;
}
- return 0;
+ if (is_partial_io(bvec))
+ memcpy(user_mem + bvec->bv_offset, uncmem + offset,
+ bvec->bv_len);
+
+ flush_dcache_page(page);
+ ret = 0;
+out_cleanup:
+ kunmap_atomic(user_mem);
+ if (is_partial_io(bvec))
+ kfree(uncmem);
+ return ret;
}
static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
@@ -302,7 +285,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
ret = -ENOMEM;
goto out;
}
- ret = zram_read_before_write(zram, uncmem, index);
+ ret = zram_decompress_page(zram, uncmem, index);
if (ret) {
kfree(uncmem);
goto out;
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 2/2] zram: handle mem suffixes in disk size zram_sysfs parameter
2012-10-30 18:04 ` Greg Kroah-Hartman
` (2 preceding siblings ...)
2012-10-30 18:58 ` [PATCH 1/2] zram: factor-out zram_decompress_page() function Sergey Senozhatsky
@ 2012-10-30 19:00 ` Sergey Senozhatsky
3 siblings, 0 replies; 14+ messages in thread
From: Sergey Senozhatsky @ 2012-10-30 19:00 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: Nitin Gupta, linux-kernel
zram: handle mem suffixes in disk size zram_sysfs parameter
Use memparse() to allow mem suffixes in disksize sysfs number.
Examples:
echo 256K > /sys/block/zram0/disksize
echo 512M > /sys/block/zram0/disksize
echo 1G > /sys/block/zram0/disksize
Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
---
drivers/staging/zram/zram_sysfs.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/staging/zram/zram_sysfs.c b/drivers/staging/zram/zram_sysfs.c
index edb0ed4..de1eacf 100644
--- a/drivers/staging/zram/zram_sysfs.c
+++ b/drivers/staging/zram/zram_sysfs.c
@@ -15,6 +15,7 @@
#include <linux/device.h>
#include <linux/genhd.h>
#include <linux/mm.h>
+#include <linux/kernel.h>
#include "zram_drv.h"
@@ -54,13 +55,12 @@ static ssize_t disksize_show(struct device *dev,
static ssize_t disksize_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- int ret;
u64 disksize;
struct zram *zram = dev_to_zram(dev);
- ret = kstrtoull(buf, 10, &disksize);
- if (ret)
- return ret;
+ disksize = memparse(buf, NULL);
+ if (!disksize)
+ return -EINVAL;
down_write(&zram->init_lock);
if (zram->init_done) {
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 2/2] zram: permit sleeping while in pool zs_malloc()
2012-10-30 18:49 ` Sergey Senozhatsky
@ 2012-10-30 19:18 ` Greg Kroah-Hartman
2012-10-30 19:35 ` Sergey Senozhatsky
0 siblings, 1 reply; 14+ messages in thread
From: Greg Kroah-Hartman @ 2012-10-30 19:18 UTC (permalink / raw)
To: Sergey Senozhatsky; +Cc: Nitin Gupta, linux-kernel
On Tue, Oct 30, 2012 at 09:49:11PM +0300, Sergey Senozhatsky wrote:
> On (10/30/12 11:04), Greg Kroah-Hartman wrote:
> > On Tue, Oct 30, 2012 at 12:03:19PM +0300, Sergey Senozhatsky wrote:
> > > zram: permit sleeping while in pool zs_malloc()
> >
> > 2/2? Huh? Where is 1/2?
> >
> > I have a raft of patches from you, all out of order, and full of
> > responses from Nitin, and so, I really have no idea what should and
> > should not be applied here.
> >
> > So, I'm dropping them all. Please work with Nitin to get a series of
> > patches that are acceptable and resend them with the proper numbering.
> >
>
> those were two separate series.
>
> the first one:
>
> [PATCH 1/2] zram: factor-out zram_decompress_page() function
> [PATCH 2/2] zram: handle mem suffixes in disk size zram_sysfs parameter
>
> ACKed by Nitin.
>
>
>
> the second one
>
> [PATCH 2/2] zram: permit sleeping while in pool zs_malloc()
> [PATCH 1/2] zram: forbid IO operations from within zram_init_device() -- droppped by me.
>
>
> I'll resend first two and next time will make sure not to spam your box. sorry.
Sending me lots of patches is fine, I don't mind that at all. It's what
I'm here for it seems :)
But when there is responses, and follow-up patches, and second versions
and lots of other stuff, it gets hard to follow, so I ask for them all
to be resent, like this.
But, what happened with your second series? As you didn't resend them,
I'll just ignore them for now, please resend if you ever get them worked
out.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] zram: factor-out zram_decompress_page() function
2012-10-30 18:58 ` [PATCH 1/2] zram: factor-out zram_decompress_page() function Sergey Senozhatsky
@ 2012-10-30 19:18 ` Greg Kroah-Hartman
0 siblings, 0 replies; 14+ messages in thread
From: Greg Kroah-Hartman @ 2012-10-30 19:18 UTC (permalink / raw)
To: Sergey Senozhatsky; +Cc: Nitin Gupta, linux-kernel
On Tue, Oct 30, 2012 at 09:58:42PM +0300, Sergey Senozhatsky wrote:
> zram: factor-out zram_decompress_page() function
What's with the indentation?
And including the Subject: again here?
>
> zram_bvec_read() shared decompress functionality with zram_read_before_write() function.
> Factor-out and make commonly used zram_decompress_page() function, which also simplified
> error handling in zram_bvec_read().
>
> Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Where did Nitin's ack go?
I would have to edit these by hand to apply them, which isn't ok.
Please fix this up, add Nitin's acks, and resend properly.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 2/2] zram: permit sleeping while in pool zs_malloc()
2012-10-30 19:18 ` Greg Kroah-Hartman
@ 2012-10-30 19:35 ` Sergey Senozhatsky
0 siblings, 0 replies; 14+ messages in thread
From: Sergey Senozhatsky @ 2012-10-30 19:35 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: linux-kernel
On (10/30/12 12:18), Greg Kroah-Hartman wrote:
> > the first one:
> >
> > [PATCH 1/2] zram: factor-out zram_decompress_page() function
> > [PATCH 2/2] zram: handle mem suffixes in disk size zram_sysfs parameter
> >
> > ACKed by Nitin.
> >
> > the second one
> >
> > [PATCH 2/2] zram: permit sleeping while in pool zs_malloc()
> > [PATCH 1/2] zram: forbid IO operations from within zram_init_device() -- droppped by me.
> >
> >
> > I'll resend first two and next time will make sure not to spam your box. sorry.
>
> Sending me lots of patches is fine, I don't mind that at all. It's what
> I'm here for it seems :)
>
> But when there is responses, and follow-up patches, and second versions
> and lots of other stuff, it gets hard to follow, so I ask for them all
> to be resent, like this.
>
I'll Cc you next time only when we land the final versions.
> But, what happened with your second series? As you didn't resend them,
> I'll just ignore them for now, please resend if you ever get them worked
> out.
>
please ignore as I didn't have any response from Nitin yet on them.
-ss
> thanks,
>
> greg k-h
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] zram: factor-out zram_decompress_page() function
2012-10-29 17:14 ` Nitin Gupta
2012-10-29 17:33 ` Sergey Senozhatsky
@ 2012-10-30 21:04 ` Sergey Senozhatsky
2012-10-31 3:55 ` Nitin Gupta
1 sibling, 1 reply; 14+ messages in thread
From: Sergey Senozhatsky @ 2012-10-30 21:04 UTC (permalink / raw)
To: Nitin Gupta; +Cc: linux-kernel
On (10/29/12 10:14), Nitin Gupta wrote:
> ======
> zram: Fix use-after-free in partial I/O case
>
> When the compressed size of a page exceeds a threshold, the page is
> stored as-is i.e. in uncompressed form. In the partial I/O i.e.
> non-PAGE_SIZE'ed I/O case, however, the uncompressed memory was being
> freed before it could be copied into the zsmalloc pool resulting in
> use-after-free bug.
>
Hello Nitin,
hope you are fine.
how about the following one? I moved some of the code to zram_compress_page()
(very similar to zram_decompress_page()), so errors are easier to care in
zram_bvec_write(). now we handle both use after-kfree (as you did in your patch),
and use after-kunmap.
please review.
Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
---
drivers/staging/zram/zram_drv.c | 91 +++++++++++++++++++++--------------------
1 file changed, 46 insertions(+), 45 deletions(-)
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
index 47f2e3a..5f37be1 100644
--- a/drivers/staging/zram/zram_drv.c
+++ b/drivers/staging/zram/zram_drv.c
@@ -213,6 +213,44 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
return 0;
}
+static int zram_compress_page(struct zram *zram, char *uncmem, u32 index)
+{
+ int ret;
+ size_t clen;
+ unsigned long handle;
+ unsigned char *cmem, *src;
+
+ src = zram->compress_buffer;
+ ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen,
+ zram->compress_workmem);
+ if (unlikely(ret != LZO_E_OK)) {
+ pr_err("Page compression failed: err=%d\n", ret);
+ return ret;
+ }
+
+ if (unlikely(clen > max_zpage_size)) {
+ zram_stat_inc(&zram->stats.bad_compress);
+ src = uncmem;
+ clen = PAGE_SIZE;
+ }
+
+ handle = zs_malloc(zram->mem_pool, clen);
+ if (!handle) {
+ pr_info("Error allocating memory for compressed "
+ "page: %u, size=%zu\n", index, clen);
+ return -ENOMEM;
+ }
+
+ cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_WO);
+ memcpy(cmem, src, clen);
+ zs_unmap_object(zram->mem_pool, handle);
+
+ zram->table[index].handle = handle;
+ zram->table[index].size = clen;
+
+ return 0;
+}
+
static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
u32 index, int offset, struct bio *bio)
{
@@ -267,13 +305,10 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
{
int ret;
size_t clen;
- unsigned long handle;
struct page *page;
- unsigned char *user_mem, *cmem, *src, *uncmem = NULL;
+ unsigned char *user_mem, *uncmem = NULL;
page = bvec->bv_page;
- src = zram->compress_buffer;
-
if (is_partial_io(bvec)) {
/*
* This is a partial IO. We need to read the full page
@@ -286,10 +321,8 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
goto out;
}
ret = zram_decompress_page(zram, uncmem, index);
- if (ret) {
- kfree(uncmem);
+ if (ret)
goto out;
- }
}
/*
@@ -309,58 +342,26 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
uncmem = user_mem;
if (page_zero_filled(uncmem)) {
- kunmap_atomic(user_mem);
- if (is_partial_io(bvec))
- kfree(uncmem);
zram_stat_inc(&zram->stats.pages_zero);
zram_set_flag(zram, index, ZRAM_ZERO);
ret = 0;
goto out;
}
- ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen,
- zram->compress_workmem);
-
- kunmap_atomic(user_mem);
- if (is_partial_io(bvec))
- kfree(uncmem);
-
- if (unlikely(ret != LZO_E_OK)) {
- pr_err("Compression failed! err=%d\n", ret);
- goto out;
- }
-
- if (unlikely(clen > max_zpage_size)) {
- zram_stat_inc(&zram->stats.bad_compress);
- src = uncmem;
- clen = PAGE_SIZE;
- }
-
- handle = zs_malloc(zram->mem_pool, clen);
- if (!handle) {
- pr_info("Error allocating memory for compressed "
- "page: %u, size=%zu\n", index, clen);
- ret = -ENOMEM;
+ ret = zram_compress_page(zram, uncmem, index);
+ if (ret)
goto out;
- }
- cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_WO);
-
- memcpy(cmem, src, clen);
-
- zs_unmap_object(zram->mem_pool, handle);
-
- zram->table[index].handle = handle;
- zram->table[index].size = clen;
+ clen = zram->table[index].size;
/* Update stats */
zram_stat64_add(zram, &zram->stats.compr_size, clen);
zram_stat_inc(&zram->stats.pages_stored);
if (clen <= PAGE_SIZE / 2)
zram_stat_inc(&zram->stats.good_compress);
-
- return 0;
-
out:
+ kunmap_atomic(user_mem);
+ if (is_partial_io(bvec))
+ kfree(uncmem);
if (ret)
zram_stat64_inc(zram, &zram->stats.failed_writes);
return ret;
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 1/2] zram: factor-out zram_decompress_page() function
2012-10-30 21:04 ` Sergey Senozhatsky
@ 2012-10-31 3:55 ` Nitin Gupta
0 siblings, 0 replies; 14+ messages in thread
From: Nitin Gupta @ 2012-10-31 3:55 UTC (permalink / raw)
To: Sergey Senozhatsky; +Cc: linux-kernel
On 10/30/2012 02:04 PM, Sergey Senozhatsky wrote:
> On (10/29/12 10:14), Nitin Gupta wrote:
>> ======
>> zram: Fix use-after-free in partial I/O case
>>
>> When the compressed size of a page exceeds a threshold, the page is
>> stored as-is i.e. in uncompressed form. In the partial I/O i.e.
>> non-PAGE_SIZE'ed I/O case, however, the uncompressed memory was being
>> freed before it could be copied into the zsmalloc pool resulting in
>> use-after-free bug.
>>
>
> Hello Nitin,
> hope you are fine.
>
> how about the following one? I moved some of the code to zram_compress_page()
> (very similar to zram_decompress_page()), so errors are easier to care in
> zram_bvec_write(). now we handle both use after-kfree (as you did in your patch),
> and use after-kunmap.
>
> please review.
>
> Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
>
> ---
>
> drivers/staging/zram/zram_drv.c | 91 +++++++++++++++++++++--------------------
> 1 file changed, 46 insertions(+), 45 deletions(-)
>
> diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
> index 47f2e3a..5f37be1 100644
> --- a/drivers/staging/zram/zram_drv.c
> +++ b/drivers/staging/zram/zram_drv.c
> @@ -213,6 +213,44 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
> return 0;
> }
>
> +static int zram_compress_page(struct zram *zram, char *uncmem, u32 index)
> +{
> + int ret;
> + size_t clen;
> + unsigned long handle;
> + unsigned char *cmem, *src;
> +
> + src = zram->compress_buffer;
> + ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen,
> + zram->compress_workmem);
> + if (unlikely(ret != LZO_E_OK)) {
> + pr_err("Page compression failed: err=%d\n", ret);
> + return ret;
> + }
> +
> + if (unlikely(clen > max_zpage_size)) {
> + zram_stat_inc(&zram->stats.bad_compress);
> + src = uncmem;
> + clen = PAGE_SIZE;
> + }
> +
> + handle = zs_malloc(zram->mem_pool, clen);
> + if (!handle) {
> + pr_info("Error allocating memory for compressed "
> + "page: %u, size=%zu\n", index, clen);
> + return -ENOMEM;
> + }
> +
> + cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_WO);
> + memcpy(cmem, src, clen);
> + zs_unmap_object(zram->mem_pool, handle);
> +
> + zram->table[index].handle = handle;
> + zram->table[index].size = clen;
> +
> + return 0;
> +}
> +
> static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
> u32 index, int offset, struct bio *bio)
> {
> @@ -267,13 +305,10 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
> {
> int ret;
> size_t clen;
> - unsigned long handle;
> struct page *page;
> - unsigned char *user_mem, *cmem, *src, *uncmem = NULL;
> + unsigned char *user_mem, *uncmem = NULL;
>
> page = bvec->bv_page;
> - src = zram->compress_buffer;
> -
> if (is_partial_io(bvec)) {
> /*
> * This is a partial IO. We need to read the full page
> @@ -286,10 +321,8 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
> goto out;
> }
> ret = zram_decompress_page(zram, uncmem, index);
> - if (ret) {
> - kfree(uncmem);
> + if (ret)
> goto out;
> - }
> }
>
> /*
> @@ -309,58 +342,26 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
> uncmem = user_mem;
>
> if (page_zero_filled(uncmem)) {
> - kunmap_atomic(user_mem);
> - if (is_partial_io(bvec))
> - kfree(uncmem);
> zram_stat_inc(&zram->stats.pages_zero);
> zram_set_flag(zram, index, ZRAM_ZERO);
> ret = 0;
> goto out;
> }
>
> - ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen,
> - zram->compress_workmem);
> -
> - kunmap_atomic(user_mem);
> - if (is_partial_io(bvec))
> - kfree(uncmem);
> -
> - if (unlikely(ret != LZO_E_OK)) {
> - pr_err("Compression failed! err=%d\n", ret);
> - goto out;
> - }
> -
> - if (unlikely(clen > max_zpage_size)) {
> - zram_stat_inc(&zram->stats.bad_compress);
> - src = uncmem;
> - clen = PAGE_SIZE;
> - }
> -
> - handle = zs_malloc(zram->mem_pool, clen);
> - if (!handle) {
> - pr_info("Error allocating memory for compressed "
> - "page: %u, size=%zu\n", index, clen);
> - ret = -ENOMEM;
> + ret = zram_compress_page(zram, uncmem, index);
> + if (ret)
> goto out;
> - }
> - cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_WO);
> -
> - memcpy(cmem, src, clen);
> -
> - zs_unmap_object(zram->mem_pool, handle);
> -
> - zram->table[index].handle = handle;
> - zram->table[index].size = clen;
>
> + clen = zram->table[index].size;
> /* Update stats */
> zram_stat64_add(zram, &zram->stats.compr_size, clen);
> zram_stat_inc(&zram->stats.pages_stored);
> if (clen <= PAGE_SIZE / 2)
> zram_stat_inc(&zram->stats.good_compress);
> -
> - return 0;
> -
> out:
> + kunmap_atomic(user_mem);
We are doing zs_malloc + zs_map/unmap + memcpy while keeping a page
kmap'ed. We must really release it as soon as possible, so
zs_compress_page() should just do compression and return with results,
or just keep direct can to lzo_compress in bvec_write() since we are not
gaining anything by this refactoring, unlike the decompress case.
Do we have a way to generate these partial I/Os so we can exercise these
code paths?
Thanks,
Nitin
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2012-10-31 3:56 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-10-30 9:03 [PATCH 2/2] zram: permit sleeping while in pool zs_malloc() Sergey Senozhatsky
2012-10-30 18:04 ` Greg Kroah-Hartman
2012-10-30 18:49 ` Sergey Senozhatsky
2012-10-30 19:18 ` Greg Kroah-Hartman
2012-10-30 19:35 ` Sergey Senozhatsky
2012-10-30 18:56 ` [PATCH 0/2] zram decompress_page and zram_sysfs patch seriess Sergey Senozhatsky
2012-10-30 18:58 ` [PATCH 1/2] zram: factor-out zram_decompress_page() function Sergey Senozhatsky
2012-10-30 19:18 ` Greg Kroah-Hartman
2012-10-30 19:00 ` [PATCH 2/2] zram: handle mem suffixes in disk size zram_sysfs parameter Sergey Senozhatsky
-- strict thread matches above, loose matches on Subject: below --
2012-10-27 16:00 [PATCH 1/2] zram: factor-out zram_decompress_page() function Sergey Senozhatsky
2012-10-29 17:14 ` Nitin Gupta
2012-10-29 17:33 ` Sergey Senozhatsky
2012-10-30 21:04 ` Sergey Senozhatsky
2012-10-31 3:55 ` Nitin Gupta
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox