diff options
author | Minchan Kim <minchan@kernel.org> | 2018-12-28 03:36:54 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-12-28 15:11:49 -0500 |
commit | bb416d18b850faaa44bd3bb67c9728922c3cce98 (patch) | |
tree | 112f74c2842e9e2565911546cb0ff69c407ad393 /drivers/block/zram | |
parent | 23eddf39b2c28c05cb8f8203d38e61807d701b38 (diff) |
zram: writeback throttle
If there are lots of write IO with flash device, it could have a
wearout problem of storage. To overcome the problem, admin needs
to design write limitation to guarantee flash health
for entire product life.
This patch creates a new knob "writeback_limit" for zram.
writeback_limit's default value is 0 so that it doesn't limit
any writeback. If admin want to measure writeback count in a
certain period, he could know it via /sys/block/zram0/bd_stat's
3rd column.
If admin want to limit writeback as per-day 400M, he could do it
like below.
MB_SHIFT=20
4K_SHIFT=12
echo $((400<<MB_SHIFT>>4K_SHIFT)) > \
/sys/block/zram0/writeback_limit.
If admin want to allow further write again, he could do it like below
echo 0 > /sys/block/zram0/writeback_limit
If admin want to see remaining writeback budget,
cat /sys/block/zram0/writeback_limit
The writeback_limit count will reset whenever you reset zram (e.g., system
reboot, echo 1 > /sys/block/zramX/reset) so keeping how many of writeback
happened until you reset the zram to allocate extra writeback budget in
next setting is user's job.
[minchan@kernel.org: v4]
Link: http://lkml.kernel.org/r/20181203024045.153534-8-minchan@kernel.org
Link: http://lkml.kernel.org/r/20181127055429.251614-8-minchan@kernel.org
Signed-off-by: Minchan Kim <minchan@kernel.org>
Reviewed-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Cc: Joey Pabalinas <joeypabalinas@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 | 52 | ||||
-rw-r--r-- | drivers/block/zram/zram_drv.h | 2 |
2 files changed, 51 insertions, 3 deletions
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index f1832fa3ba41..33c5cc879f24 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c | |||
@@ -330,6 +330,39 @@ next: | |||
330 | } | 330 | } |
331 | 331 | ||
332 | #ifdef CONFIG_ZRAM_WRITEBACK | 332 | #ifdef CONFIG_ZRAM_WRITEBACK |
333 | static ssize_t writeback_limit_store(struct device *dev, | ||
334 | struct device_attribute *attr, const char *buf, size_t len) | ||
335 | { | ||
336 | struct zram *zram = dev_to_zram(dev); | ||
337 | u64 val; | ||
338 | ssize_t ret = -EINVAL; | ||
339 | |||
340 | if (kstrtoull(buf, 10, &val)) | ||
341 | return ret; | ||
342 | |||
343 | down_read(&zram->init_lock); | ||
344 | atomic64_set(&zram->stats.bd_wb_limit, val); | ||
345 | if (val == 0) | ||
346 | zram->stop_writeback = false; | ||
347 | up_read(&zram->init_lock); | ||
348 | ret = len; | ||
349 | |||
350 | return ret; | ||
351 | } | ||
352 | |||
353 | static ssize_t writeback_limit_show(struct device *dev, | ||
354 | struct device_attribute *attr, char *buf) | ||
355 | { | ||
356 | u64 val; | ||
357 | struct zram *zram = dev_to_zram(dev); | ||
358 | |||
359 | down_read(&zram->init_lock); | ||
360 | val = atomic64_read(&zram->stats.bd_wb_limit); | ||
361 | up_read(&zram->init_lock); | ||
362 | |||
363 | return scnprintf(buf, PAGE_SIZE, "%llu\n", val); | ||
364 | } | ||
365 | |||
333 | static void reset_bdev(struct zram *zram) | 366 | static void reset_bdev(struct zram *zram) |
334 | { | 367 | { |
335 | struct block_device *bdev; | 368 | struct block_device *bdev; |
@@ -612,6 +645,11 @@ static ssize_t writeback_store(struct device *dev, | |||
612 | bvec.bv_len = PAGE_SIZE; | 645 | bvec.bv_len = PAGE_SIZE; |
613 | bvec.bv_offset = 0; | 646 | bvec.bv_offset = 0; |
614 | 647 | ||
648 | if (zram->stop_writeback) { | ||
649 | ret = -EIO; | ||
650 | break; | ||
651 | } | ||
652 | |||
615 | if (!blk_idx) { | 653 | if (!blk_idx) { |
616 | blk_idx = alloc_block_bdev(zram); | 654 | blk_idx = alloc_block_bdev(zram); |
617 | if (!blk_idx) { | 655 | if (!blk_idx) { |
@@ -694,6 +732,11 @@ static ssize_t writeback_store(struct device *dev, | |||
694 | zram_set_element(zram, index, blk_idx); | 732 | zram_set_element(zram, index, blk_idx); |
695 | blk_idx = 0; | 733 | blk_idx = 0; |
696 | atomic64_inc(&zram->stats.pages_stored); | 734 | atomic64_inc(&zram->stats.pages_stored); |
735 | if (atomic64_add_unless(&zram->stats.bd_wb_limit, | ||
736 | -1 << (PAGE_SHIFT - 12), 0)) { | ||
737 | if (atomic64_read(&zram->stats.bd_wb_limit) == 0) | ||
738 | zram->stop_writeback = true; | ||
739 | } | ||
697 | next: | 740 | next: |
698 | zram_slot_unlock(zram, index); | 741 | zram_slot_unlock(zram, index); |
699 | } | 742 | } |
@@ -1018,6 +1061,7 @@ static ssize_t mm_stat_show(struct device *dev, | |||
1018 | } | 1061 | } |
1019 | 1062 | ||
1020 | #ifdef CONFIG_ZRAM_WRITEBACK | 1063 | #ifdef CONFIG_ZRAM_WRITEBACK |
1064 | #define FOUR_K(x) ((x) * (1 << (PAGE_SHIFT - 12))) | ||
1021 | static ssize_t bd_stat_show(struct device *dev, | 1065 | static ssize_t bd_stat_show(struct device *dev, |
1022 | struct device_attribute *attr, char *buf) | 1066 | struct device_attribute *attr, char *buf) |
1023 | { | 1067 | { |
@@ -1027,9 +1071,9 @@ static ssize_t bd_stat_show(struct device *dev, | |||
1027 | down_read(&zram->init_lock); | 1071 | down_read(&zram->init_lock); |
1028 | ret = scnprintf(buf, PAGE_SIZE, | 1072 | ret = scnprintf(buf, PAGE_SIZE, |
1029 | "%8llu %8llu %8llu\n", | 1073 | "%8llu %8llu %8llu\n", |
1030 | (u64)atomic64_read(&zram->stats.bd_count) * (PAGE_SHIFT - 12), | 1074 | FOUR_K((u64)atomic64_read(&zram->stats.bd_count)), |
1031 | (u64)atomic64_read(&zram->stats.bd_reads) * (PAGE_SHIFT - 12), | 1075 | FOUR_K((u64)atomic64_read(&zram->stats.bd_reads)), |
1032 | (u64)atomic64_read(&zram->stats.bd_writes) * (PAGE_SHIFT - 12)); | 1076 | FOUR_K((u64)atomic64_read(&zram->stats.bd_writes))); |
1033 | up_read(&zram->init_lock); | 1077 | up_read(&zram->init_lock); |
1034 | 1078 | ||
1035 | return ret; | 1079 | return ret; |
@@ -1767,6 +1811,7 @@ static DEVICE_ATTR_RW(comp_algorithm); | |||
1767 | #ifdef CONFIG_ZRAM_WRITEBACK | 1811 | #ifdef CONFIG_ZRAM_WRITEBACK |
1768 | static DEVICE_ATTR_RW(backing_dev); | 1812 | static DEVICE_ATTR_RW(backing_dev); |
1769 | static DEVICE_ATTR_WO(writeback); | 1813 | static DEVICE_ATTR_WO(writeback); |
1814 | static DEVICE_ATTR_RW(writeback_limit); | ||
1770 | #endif | 1815 | #endif |
1771 | 1816 | ||
1772 | static struct attribute *zram_disk_attrs[] = { | 1817 | static struct attribute *zram_disk_attrs[] = { |
@@ -1782,6 +1827,7 @@ static struct attribute *zram_disk_attrs[] = { | |||
1782 | #ifdef CONFIG_ZRAM_WRITEBACK | 1827 | #ifdef CONFIG_ZRAM_WRITEBACK |
1783 | &dev_attr_backing_dev.attr, | 1828 | &dev_attr_backing_dev.attr, |
1784 | &dev_attr_writeback.attr, | 1829 | &dev_attr_writeback.attr, |
1830 | &dev_attr_writeback_limit.attr, | ||
1785 | #endif | 1831 | #endif |
1786 | &dev_attr_io_stat.attr, | 1832 | &dev_attr_io_stat.attr, |
1787 | &dev_attr_mm_stat.attr, | 1833 | &dev_attr_mm_stat.attr, |
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h index bc477803530d..4bd3afd15e83 100644 --- a/drivers/block/zram/zram_drv.h +++ b/drivers/block/zram/zram_drv.h | |||
@@ -86,6 +86,7 @@ struct zram_stats { | |||
86 | atomic64_t bd_count; /* no. of pages in backing device */ | 86 | atomic64_t bd_count; /* no. of pages in backing device */ |
87 | atomic64_t bd_reads; /* no. of reads from backing device */ | 87 | atomic64_t bd_reads; /* no. of reads from backing device */ |
88 | atomic64_t bd_writes; /* no. of writes from backing device */ | 88 | atomic64_t bd_writes; /* no. of writes from backing device */ |
89 | atomic64_t bd_wb_limit; /* writeback limit of backing device */ | ||
89 | #endif | 90 | #endif |
90 | }; | 91 | }; |
91 | 92 | ||
@@ -113,6 +114,7 @@ struct zram { | |||
113 | */ | 114 | */ |
114 | bool claim; /* Protected by bdev->bd_mutex */ | 115 | bool claim; /* Protected by bdev->bd_mutex */ |
115 | struct file *backing_dev; | 116 | struct file *backing_dev; |
117 | bool stop_writeback; | ||
116 | #ifdef CONFIG_ZRAM_WRITEBACK | 118 | #ifdef CONFIG_ZRAM_WRITEBACK |
117 | struct block_device *bdev; | 119 | struct block_device *bdev; |
118 | unsigned int old_block_size; | 120 | unsigned int old_block_size; |