diff options
| author | Weijie Yang <weijie.yang@samsung.com> | 2014-10-29 17:50:57 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-29 19:33:15 -0400 |
| commit | 5a99e95b8d1cd47f6feddcdca6c71d22060df8a2 (patch) | |
| tree | 51384759dcfdc6e189139a5a58a5df7f6e16f56b /drivers/block/zram | |
| parent | 8aba7e0a2c02355f9a7dec629635cb7093fe0508 (diff) | |
zram: avoid NULL pointer access in concurrent situation
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>
Diffstat (limited to 'drivers/block/zram')
| -rw-r--r-- | drivers/block/zram/zram_drv.c | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 0e63e8aa8279..2ad0b5bce44b 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c | |||
| @@ -99,11 +99,12 @@ static ssize_t mem_used_total_show(struct device *dev, | |||
| 99 | { | 99 | { |
| 100 | u64 val = 0; | 100 | u64 val = 0; |
| 101 | struct zram *zram = dev_to_zram(dev); | 101 | struct zram *zram = dev_to_zram(dev); |
| 102 | struct zram_meta *meta = zram->meta; | ||
| 103 | 102 | ||
| 104 | down_read(&zram->init_lock); | 103 | down_read(&zram->init_lock); |
| 105 | if (init_done(zram)) | 104 | if (init_done(zram)) { |
| 105 | struct zram_meta *meta = zram->meta; | ||
| 106 | val = zs_get_total_pages(meta->mem_pool); | 106 | val = zs_get_total_pages(meta->mem_pool); |
| 107 | } | ||
| 107 | up_read(&zram->init_lock); | 108 | up_read(&zram->init_lock); |
| 108 | 109 | ||
| 109 | return scnprintf(buf, PAGE_SIZE, "%llu\n", val << PAGE_SHIFT); | 110 | return scnprintf(buf, PAGE_SIZE, "%llu\n", val << PAGE_SHIFT); |
| @@ -173,16 +174,17 @@ static ssize_t mem_used_max_store(struct device *dev, | |||
| 173 | int err; | 174 | int err; |
| 174 | unsigned long val; | 175 | unsigned long val; |
| 175 | struct zram *zram = dev_to_zram(dev); | 176 | struct zram *zram = dev_to_zram(dev); |
| 176 | struct zram_meta *meta = zram->meta; | ||
| 177 | 177 | ||
| 178 | err = kstrtoul(buf, 10, &val); | 178 | err = kstrtoul(buf, 10, &val); |
| 179 | if (err || val != 0) | 179 | if (err || val != 0) |
| 180 | return -EINVAL; | 180 | return -EINVAL; |
| 181 | 181 | ||
| 182 | down_read(&zram->init_lock); | 182 | down_read(&zram->init_lock); |
| 183 | if (init_done(zram)) | 183 | if (init_done(zram)) { |
| 184 | struct zram_meta *meta = zram->meta; | ||
| 184 | atomic_long_set(&zram->stats.max_used_pages, | 185 | atomic_long_set(&zram->stats.max_used_pages, |
| 185 | zs_get_total_pages(meta->mem_pool)); | 186 | zs_get_total_pages(meta->mem_pool)); |
| 187 | } | ||
| 186 | up_read(&zram->init_lock); | 188 | up_read(&zram->init_lock); |
| 187 | 189 | ||
| 188 | return len; | 190 | return len; |
