Commit 8f35126d authored by Kyeongdon Kim's avatar Kyeongdon Kim Committed by Kamal Mostafa

zram: try vmalloc() after kmalloc()

commit d913897a upstream.

When we're using LZ4 multi compression streams for zram swap, we found
out page allocation failure message in system running test.  That was
not only once, but a few(2 - 5 times per test).  Also, some failure
cases were continually occurring to try allocation order 3.

In order to make parallel compression private data, we should call
kzalloc() with order 2/3 in runtime(lzo/lz4).  But if there is no order
2/3 size memory to allocate in that time, page allocation fails.  This
patch makes to use vmalloc() as fallback of kmalloc(), this prevents
page alloc failure warning.

After using this, we never found warning message in running test, also
It could reduce process startup latency about 60-120ms in each case.

For reference a call trace :

    Binder_1: page allocation failure: order:3, mode:0x10c0d0
    CPU: 0 PID: 424 Comm: Binder_1 Tainted: GW 3.10.49-perf-g991d02b-dirty #20
    Call trace:
      dump_backtrace+0x0/0x270
      show_stack+0x10/0x1c
      dump_stack+0x1c/0x28
      warn_alloc_failed+0xfc/0x11c
      __alloc_pages_nodemask+0x724/0x7f0
      __get_free_pages+0x14/0x5c
      kmalloc_order_trace+0x38/0xd8
      zcomp_lz4_create+0x2c/0x38
      zcomp_strm_alloc+0x34/0x78
      zcomp_strm_multi_find+0x124/0x1ec
      zcomp_strm_find+0xc/0x18
      zram_bvec_rw+0x2fc/0x780
      zram_make_request+0x25c/0x2d4
      generic_make_request+0x80/0xbc
      submit_bio+0xa4/0x15c
      __swap_writepage+0x218/0x230
      swap_writepage+0x3c/0x4c
      shrink_page_list+0x51c/0x8d0
      shrink_inactive_list+0x3f8/0x60c
      shrink_lruvec+0x33c/0x4cc
      shrink_zone+0x3c/0x100
      try_to_free_pages+0x2b8/0x54c
      __alloc_pages_nodemask+0x514/0x7f0
      __get_free_pages+0x14/0x5c
      proc_info_read+0x50/0xe4
      vfs_read+0xa0/0x12c
      SyS_read+0x44/0x74
    DMA: 3397*4kB (MC) 26*8kB (RC) 0*16kB 0*32kB 0*64kB 0*128kB 0*256kB
         0*512kB 0*1024kB 0*2048kB 0*4096kB = 13796kB

[minchan@kernel.org: change vmalloc gfp and adding comment about gfp]
[sergey.senozhatsky@gmail.com: tweak comments and styles]
Signed-off-by: default avatarKyeongdon Kim <kyeongdon.kim@lge.com>
Signed-off-by: default avatarMinchan Kim <minchan@kernel.org>
Acked-by: default avatarSergey Senozhatsky <sergey.senozhatsky@gmail.com>
Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarKamal Mostafa <kamal@canonical.com>
parent 5ff3781e
...@@ -10,17 +10,36 @@ ...@@ -10,17 +10,36 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/lz4.h> #include <linux/lz4.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include "zcomp_lz4.h" #include "zcomp_lz4.h"
static void *zcomp_lz4_create(void) static void *zcomp_lz4_create(void)
{ {
return kzalloc(LZ4_MEM_COMPRESS, GFP_NOIO); void *ret;
/*
* This function can be called in swapout/fs write path
* so we can't use GFP_FS|IO. And it assumes we already
* have at least one stream in zram initialization so we
* don't do best effort to allocate more stream in here.
* A default stream will work well without further multiple
* streams. That's why we use NORETRY | NOWARN.
*/
ret = kzalloc(LZ4_MEM_COMPRESS, GFP_NOIO | __GFP_NORETRY |
__GFP_NOWARN);
if (!ret)
ret = __vmalloc(LZ4_MEM_COMPRESS,
GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN |
__GFP_ZERO | __GFP_HIGHMEM,
PAGE_KERNEL);
return ret;
} }
static void zcomp_lz4_destroy(void *private) static void zcomp_lz4_destroy(void *private)
{ {
kfree(private); kvfree(private);
} }
static int zcomp_lz4_compress(const unsigned char *src, unsigned char *dst, static int zcomp_lz4_compress(const unsigned char *src, unsigned char *dst,
......
...@@ -10,17 +10,36 @@ ...@@ -10,17 +10,36 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/lzo.h> #include <linux/lzo.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include "zcomp_lzo.h" #include "zcomp_lzo.h"
static void *lzo_create(void) static void *lzo_create(void)
{ {
return kzalloc(LZO1X_MEM_COMPRESS, GFP_NOIO); void *ret;
/*
* This function can be called in swapout/fs write path
* so we can't use GFP_FS|IO. And it assumes we already
* have at least one stream in zram initialization so we
* don't do best effort to allocate more stream in here.
* A default stream will work well without further multiple
* streams. That's why we use NORETRY | NOWARN.
*/
ret = kzalloc(LZO1X_MEM_COMPRESS, GFP_NOIO | __GFP_NORETRY |
__GFP_NOWARN);
if (!ret)
ret = __vmalloc(LZO1X_MEM_COMPRESS,
GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN |
__GFP_ZERO | __GFP_HIGHMEM,
PAGE_KERNEL);
return ret;
} }
static void lzo_destroy(void *private) static void lzo_destroy(void *private)
{ {
kfree(private); kvfree(private);
} }
static int lzo_compress(const unsigned char *src, unsigned char *dst, static int lzo_compress(const unsigned char *src, unsigned char *dst,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment