Commit e82592c4 authored by Minchan Kim's avatar Minchan Kim Committed by Linus Torvalds

zram: introduce ZRAM_IDLE flag

To support idle page writeback with upcoming patches, this patch
introduces a new ZRAM_IDLE flag.

Userspace can mark zram slots as "idle" via
	"echo all > /sys/block/zramX/idle"
which marks every allocated zram slot as ZRAM_IDLE.
User could see it by /sys/kernel/debug/zram/zram0/block_state.

          300    75.033841 ...i
          301    63.806904 s..i
          302    63.806919 ..hi

Once there is IO for the slot, the mark will be disappeared.

	  300    75.033841 ...
          301    63.806904 s..i
          302    63.806919 ..hi

Therefore, 300th block is idle zpage. With this feature,
user can how many zram has idle pages which are waste of memory.

Link: http://lkml.kernel.org/r/20181127055429.251614-5-minchan@kernel.orgSigned-off-by: default avatarMinchan Kim <minchan@kernel.org>
Reviewed-by: default avatarSergey Senozhatsky <sergey.senozhatsky@gmail.com>
Reviewed-by: default avatarJoey Pabalinas <joeypabalinas@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 7e529283
...@@ -98,3 +98,11 @@ Description: ...@@ -98,3 +98,11 @@ Description:
The backing_dev file is read-write and set up backing The backing_dev file is read-write and set up backing
device for zram to write incompressible pages. device for zram to write incompressible pages.
For using, user should enable CONFIG_ZRAM_WRITEBACK. For using, user should enable CONFIG_ZRAM_WRITEBACK.
What: /sys/block/zram<id>/idle
Date: November 2018
Contact: Minchan Kim <minchan@kernel.org>
Description:
idle file is write-only and mark zram slot as idle.
If system has mounted debugfs, user can see which slots
are idle via /sys/kernel/debug/zram/zram<id>/block_state
...@@ -169,6 +169,7 @@ comp_algorithm RW show and change the compression algorithm ...@@ -169,6 +169,7 @@ comp_algorithm RW show and change the compression algorithm
compact WO trigger memory compaction compact WO trigger memory compaction
debug_stat RO this file is used for zram debugging purposes debug_stat RO this file is used for zram debugging purposes
backing_dev RW set up backend storage for zram to write out backing_dev RW set up backend storage for zram to write out
idle WO mark allocated slot as idle
User space is advised to use the following files to read the device statistics. User space is advised to use the following files to read the device statistics.
...@@ -251,16 +252,17 @@ pages of the process with*pagemap. ...@@ -251,16 +252,17 @@ pages of the process with*pagemap.
If you enable the feature, you could see block state via If you enable the feature, you could see block state via
/sys/kernel/debug/zram/zram0/block_state". The output is as follows, /sys/kernel/debug/zram/zram0/block_state". The output is as follows,
300 75.033841 .wh 300 75.033841 .wh.
301 63.806904 s.. 301 63.806904 s...
302 63.806919 ..h 302 63.806919 ..hi
First column is zram's block index. First column is zram's block index.
Second column is access time since the system was booted Second column is access time since the system was booted
Third column is state of the block. Third column is state of the block.
(s: same page (s: same page
w: written page to backing store w: written page to backing store
h: huge page) h: huge page
i: idle page)
First line of above example says 300th block is accessed at 75.033841sec First line of above example says 300th block is accessed at 75.033841sec
and the block's state is huge so it is written back to the backing and the block's state is huge so it is written back to the backing
......
...@@ -281,6 +281,47 @@ static ssize_t mem_used_max_store(struct device *dev, ...@@ -281,6 +281,47 @@ static ssize_t mem_used_max_store(struct device *dev,
return len; return len;
} }
static ssize_t idle_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
struct zram *zram = dev_to_zram(dev);
unsigned long nr_pages = zram->disksize >> PAGE_SHIFT;
int index;
char mode_buf[8];
ssize_t sz;
sz = strscpy(mode_buf, buf, sizeof(mode_buf));
if (sz <= 0)
return -EINVAL;
/* ignore trailing new line */
if (mode_buf[sz - 1] == '\n')
mode_buf[sz - 1] = 0x00;
if (strcmp(mode_buf, "all"))
return -EINVAL;
down_read(&zram->init_lock);
if (!init_done(zram)) {
up_read(&zram->init_lock);
return -EINVAL;
}
for (index = 0; index < nr_pages; index++) {
zram_slot_lock(zram, index);
if (!zram_allocated(zram, index))
goto next;
zram_set_flag(zram, index, ZRAM_IDLE);
next:
zram_slot_unlock(zram, index);
}
up_read(&zram->init_lock);
return len;
}
#ifdef CONFIG_ZRAM_WRITEBACK #ifdef CONFIG_ZRAM_WRITEBACK
static void reset_bdev(struct zram *zram) static void reset_bdev(struct zram *zram)
{ {
...@@ -638,6 +679,7 @@ static void zram_debugfs_destroy(void) ...@@ -638,6 +679,7 @@ static void zram_debugfs_destroy(void)
static void zram_accessed(struct zram *zram, u32 index) static void zram_accessed(struct zram *zram, u32 index)
{ {
zram_clear_flag(zram, index, ZRAM_IDLE);
zram->table[index].ac_time = ktime_get_boottime(); zram->table[index].ac_time = ktime_get_boottime();
} }
...@@ -670,12 +712,13 @@ static ssize_t read_block_state(struct file *file, char __user *buf, ...@@ -670,12 +712,13 @@ static ssize_t read_block_state(struct file *file, char __user *buf,
ts = ktime_to_timespec64(zram->table[index].ac_time); ts = ktime_to_timespec64(zram->table[index].ac_time);
copied = snprintf(kbuf + written, count, copied = snprintf(kbuf + written, count,
"%12zd %12lld.%06lu %c%c%c\n", "%12zd %12lld.%06lu %c%c%c%c\n",
index, (s64)ts.tv_sec, index, (s64)ts.tv_sec,
ts.tv_nsec / NSEC_PER_USEC, ts.tv_nsec / NSEC_PER_USEC,
zram_test_flag(zram, index, ZRAM_SAME) ? 's' : '.', zram_test_flag(zram, index, ZRAM_SAME) ? 's' : '.',
zram_test_flag(zram, index, ZRAM_WB) ? 'w' : '.', zram_test_flag(zram, index, ZRAM_WB) ? 'w' : '.',
zram_test_flag(zram, index, ZRAM_HUGE) ? 'h' : '.'); zram_test_flag(zram, index, ZRAM_HUGE) ? 'h' : '.',
zram_test_flag(zram, index, ZRAM_IDLE) ? 'i' : '.');
if (count < copied) { if (count < copied) {
zram_slot_unlock(zram, index); zram_slot_unlock(zram, index);
...@@ -720,7 +763,10 @@ static void zram_debugfs_unregister(struct zram *zram) ...@@ -720,7 +763,10 @@ static void zram_debugfs_unregister(struct zram *zram)
#else #else
static void zram_debugfs_create(void) {}; static void zram_debugfs_create(void) {};
static void zram_debugfs_destroy(void) {}; static void zram_debugfs_destroy(void) {};
static void zram_accessed(struct zram *zram, u32 index) {}; static void zram_accessed(struct zram *zram, u32 index)
{
zram_clear_flag(zram, index, ZRAM_IDLE);
};
static void zram_debugfs_register(struct zram *zram) {}; static void zram_debugfs_register(struct zram *zram) {};
static void zram_debugfs_unregister(struct zram *zram) {}; static void zram_debugfs_unregister(struct zram *zram) {};
#endif #endif
...@@ -924,6 +970,9 @@ static void zram_free_page(struct zram *zram, size_t index) ...@@ -924,6 +970,9 @@ static void zram_free_page(struct zram *zram, size_t index)
#ifdef CONFIG_ZRAM_MEMORY_TRACKING #ifdef CONFIG_ZRAM_MEMORY_TRACKING
zram->table[index].ac_time = 0; zram->table[index].ac_time = 0;
#endif #endif
if (zram_test_flag(zram, index, ZRAM_IDLE))
zram_clear_flag(zram, index, ZRAM_IDLE);
if (zram_test_flag(zram, index, ZRAM_HUGE)) { if (zram_test_flag(zram, index, ZRAM_HUGE)) {
zram_clear_flag(zram, index, ZRAM_HUGE); zram_clear_flag(zram, index, ZRAM_HUGE);
atomic64_dec(&zram->stats.huge_pages); atomic64_dec(&zram->stats.huge_pages);
...@@ -1589,6 +1638,7 @@ static DEVICE_ATTR_RO(initstate); ...@@ -1589,6 +1638,7 @@ static DEVICE_ATTR_RO(initstate);
static DEVICE_ATTR_WO(reset); static DEVICE_ATTR_WO(reset);
static DEVICE_ATTR_WO(mem_limit); static DEVICE_ATTR_WO(mem_limit);
static DEVICE_ATTR_WO(mem_used_max); static DEVICE_ATTR_WO(mem_used_max);
static DEVICE_ATTR_WO(idle);
static DEVICE_ATTR_RW(max_comp_streams); static DEVICE_ATTR_RW(max_comp_streams);
static DEVICE_ATTR_RW(comp_algorithm); static DEVICE_ATTR_RW(comp_algorithm);
#ifdef CONFIG_ZRAM_WRITEBACK #ifdef CONFIG_ZRAM_WRITEBACK
...@@ -1602,6 +1652,7 @@ static struct attribute *zram_disk_attrs[] = { ...@@ -1602,6 +1652,7 @@ static struct attribute *zram_disk_attrs[] = {
&dev_attr_compact.attr, &dev_attr_compact.attr,
&dev_attr_mem_limit.attr, &dev_attr_mem_limit.attr,
&dev_attr_mem_used_max.attr, &dev_attr_mem_used_max.attr,
&dev_attr_idle.attr,
&dev_attr_max_comp_streams.attr, &dev_attr_max_comp_streams.attr,
&dev_attr_comp_algorithm.attr, &dev_attr_comp_algorithm.attr,
#ifdef CONFIG_ZRAM_WRITEBACK #ifdef CONFIG_ZRAM_WRITEBACK
......
...@@ -48,6 +48,7 @@ enum zram_pageflags { ...@@ -48,6 +48,7 @@ enum zram_pageflags {
ZRAM_SAME, /* Page consists the same element */ ZRAM_SAME, /* Page consists the same element */
ZRAM_WB, /* page is stored on backing_device */ ZRAM_WB, /* page is stored on backing_device */
ZRAM_HUGE, /* Incompressible page */ ZRAM_HUGE, /* Incompressible page */
ZRAM_IDLE, /* not accessed page since last idle marking */
__NR_ZRAM_PAGEFLAGS, __NR_ZRAM_PAGEFLAGS,
}; };
......
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