[PATCH 2/2] zram: protect zram->stat race with init_lock

Minchan Kim
2015-01-23T05:58:30Z

The zram->stat handling should be procted by init_lock.
Otherwise, user could see stale value from the stat.

Signed-off-by: Minchan Kim <minchan@kernel.org>
---

I don't think it's stable material. The race is rare in real practice
and this stale stat value read is not a critical.

drivers/block/zram/zram_drv.c | 37 ++++++++++++++++++++++++++++---------
1 file changed, 28 insertions(+), 9 deletions(-)

diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 0299d82275e7..53f176f590b0 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -48,8 +48,13 @@ static ssize_t name##_show(struct device *d, \
struct device_attribute *attr, char *b) \
{ \
struct zram *zram = dev_to_zram(d); \
- return scnprintf(b, PAGE_SIZE, "%llu\n", \
- (u64)atomic64_read(&zram->stats.name)); \
+ u64 val = 0; \
+ \
+ down_read(&zram->init_lock); \
+ if (init_done(zram)) \
+ val = atomic64_read(&zram->stats.name); \
+ up_read(&zram->init_lock); \
+ return scnprintf(b, PAGE_SIZE, "%llu\n", val); \
} \
static DEVICE_ATTR_RO(name);

@@ -67,8 +72,14 @@ static ssize_t disksize_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct zram *zram = dev_to_zram(dev);
+ u64 val = 0;
+
+ down_read(&zram->init_lock);
+ if (init_done(zram))
+ val = zram->disksize;
+ up_read(&zram->init_lock);

- return scnprintf(buf, PAGE_SIZE, "%llu\n", zram->disksize);
+ return scnprintf(buf, PAGE_SIZE, "%llu\n", val);
}

static ssize_t initstate_show(struct device *dev,
@@ -88,9 +99,14 @@ static ssize_t orig_data_size_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct zram *zram = dev_to_zram(dev);
+ u64 val = 0;
+
+ down_read(&zram->init_lock);
+ if (init_done(zram))
+ val = atomic64_read(&zram->stats.pages_stored) << PAGE_SHIFT;
+ up_read(&zram->init_lock);

- return scnprintf(buf, PAGE_SIZE, "%llu\n",
- (u64)(atomic64_read(&zram->stats.pages_stored)) << PAGE_SHIFT);
+ return scnprintf(buf, PAGE_SIZE, "%llu\n", val);
}

static ssize_t mem_used_total_show(struct device *dev,
@@ -957,10 +973,6 @@ static int zram_rw_page(struct block_device *bdev, sector_t sector,
struct bio_vec bv;

zram = bdev->bd_disk->private_data;
- if (!valid_io_request(zram, sector, PAGE_SIZE)) {
- atomic64_inc(&zram->stats.invalid_io);
- return -EINVAL;
- }

down_read(&zram->init_lock);
if (unlikely(!init_done(zram))) {
@@ -968,6 +980,13 @@ static int zram_rw_page(struct block_device *bdev, sector_t sector,
goto out_unlock;
}

+ if (!valid_io_request(zram, sector, PAGE_SIZE)) {
+ atomic64_inc(&zram->stats.invalid_io);
+ err = -EINVAL;
+ goto out_unlock;
+ }
+
+
index = sector >> SECTORS_PER_PAGE_SHIFT;
offset = sector & (SECTORS_PER_PAGE - 1) << SECTOR_SHIFT;

--
1.9.1