zram: avoid NULL pointer access in concurrent situation
authorWeijie Yang <weijie.yang@samsung.com>
Wed, 29 Oct 2014 21:50:57 +0000 (14:50 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 29 Oct 2014 23:33:15 +0000 (16:33 -0700)
There is a rare NULL pointer bug in mem_used_total_show() and
mem_used_max_store() in concurrent situation, like this:

zram is not initialized, process A is a mem_used_total reader which runs
periodically, while process B try to init zram.

process A  process B
  access meta, get a NULL value
init zram, done
  init_done() is true
  access meta->mem_pool, get a NULL pointer BUG

This patch fixes this issue.

Signed-off-by: Weijie Yang <weijie.yang@samsung.com>
Acked-by: Minchan Kim <minchan@kernel.org>
Acked-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/block/zram/zram_drv.c

index 0e63e8a..2ad0b5b 100644 (file)
@@ -99,11 +99,12 @@ static ssize_t mem_used_total_show(struct device *dev,
 {
        u64 val = 0;
        struct zram *zram = dev_to_zram(dev);
-       struct zram_meta *meta = zram->meta;
 
        down_read(&zram->init_lock);
-       if (init_done(zram))
+       if (init_done(zram)) {
+               struct zram_meta *meta = zram->meta;
                val = zs_get_total_pages(meta->mem_pool);
+       }
        up_read(&zram->init_lock);
 
        return scnprintf(buf, PAGE_SIZE, "%llu\n", val << PAGE_SHIFT);
@@ -173,16 +174,17 @@ static ssize_t mem_used_max_store(struct device *dev,
        int err;
        unsigned long val;
        struct zram *zram = dev_to_zram(dev);
-       struct zram_meta *meta = zram->meta;
 
        err = kstrtoul(buf, 10, &val);
        if (err || val != 0)
                return -EINVAL;
 
        down_read(&zram->init_lock);
-       if (init_done(zram))
+       if (init_done(zram)) {
+               struct zram_meta *meta = zram->meta;
                atomic_long_set(&zram->stats.max_used_pages,
                                zs_get_total_pages(meta->mem_pool));
+       }
        up_read(&zram->init_lock);
 
        return len;