zram: introduce ZRAM_IDLE flag
authorMinchan Kim <minchan@kernel.org>
Fri, 28 Dec 2018 08:36:44 +0000 (00:36 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 28 Dec 2018 20:11:49 +0000 (12:11 -0800)
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.org
Signed-off-by: Minchan Kim <minchan@kernel.org>
Reviewed-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Reviewed-by: Joey Pabalinas <joeypabalinas@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Documentation/ABI/testing/sysfs-block-zram
Documentation/blockdev/zram.txt
drivers/block/zram/zram_drv.c
drivers/block/zram/zram_drv.h

index c1513c756af125ce5adb76ee8e4522e25572a099..04c9a5980bc78975c6616276db7ad05d16d7944d 100644 (file)
@@ -98,3 +98,11 @@ Description:
                The backing_dev file is read-write and set up backing
                device for zram to write incompressible pages.
                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
index 3c1b5ab54bc07a487517c1441adc408b170cf5fa..f3bcd716d8a94c34340d75e21be35baf73fdb774 100644 (file)
@@ -169,6 +169,7 @@ comp_algorithm    RW    show and change the compression algorithm
 compact           WO    trigger memory compaction
 debug_stat        RO    this file is used for zram debugging purposes
 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.
@@ -251,16 +252,17 @@ pages of the process with*pagemap.
 If you enable the feature, you could see block state via
 /sys/kernel/debug/zram/zram0/block_state". The output is as follows,
 
-         300    75.033841 .wh
-         301    63.806904 s..
-         302    63.806919 ..h
+         300    75.033841 .wh.
+         301    63.806904 s...
+         302    63.806919 ..hi
 
 First column is zram's block index.
 Second column is access time since the system was booted
 Third column is state of the block.
 (s: same page
 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
 and the block's state is huge so it is written back to the backing
index 4457d0395bfbe91244a33d0cbb4c8e35c2ce10a3..180613b478a676d0ac1bb799700b48ce1077eab0 100644 (file)
@@ -281,6 +281,47 @@ static ssize_t mem_used_max_store(struct device *dev,
        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
 static void reset_bdev(struct zram *zram)
 {
@@ -638,6 +679,7 @@ static void zram_debugfs_destroy(void)
 
 static void zram_accessed(struct zram *zram, u32 index)
 {
+       zram_clear_flag(zram, index, ZRAM_IDLE);
        zram->table[index].ac_time = ktime_get_boottime();
 }
 
@@ -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);
                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,
                        ts.tv_nsec / NSEC_PER_USEC,
                        zram_test_flag(zram, index, ZRAM_SAME) ? 's' : '.',
                        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) {
                        zram_slot_unlock(zram, index);
@@ -720,7 +763,10 @@ static void zram_debugfs_unregister(struct zram *zram)
 #else
 static void zram_debugfs_create(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_unregister(struct zram *zram) {};
 #endif
@@ -924,6 +970,9 @@ static void zram_free_page(struct zram *zram, size_t index)
 #ifdef CONFIG_ZRAM_MEMORY_TRACKING
        zram->table[index].ac_time = 0;
 #endif
+       if (zram_test_flag(zram, index, ZRAM_IDLE))
+               zram_clear_flag(zram, index, ZRAM_IDLE);
+
        if (zram_test_flag(zram, index, ZRAM_HUGE)) {
                zram_clear_flag(zram, index, ZRAM_HUGE);
                atomic64_dec(&zram->stats.huge_pages);
@@ -1589,6 +1638,7 @@ static DEVICE_ATTR_RO(initstate);
 static DEVICE_ATTR_WO(reset);
 static DEVICE_ATTR_WO(mem_limit);
 static DEVICE_ATTR_WO(mem_used_max);
+static DEVICE_ATTR_WO(idle);
 static DEVICE_ATTR_RW(max_comp_streams);
 static DEVICE_ATTR_RW(comp_algorithm);
 #ifdef CONFIG_ZRAM_WRITEBACK
@@ -1602,6 +1652,7 @@ static struct attribute *zram_disk_attrs[] = {
        &dev_attr_compact.attr,
        &dev_attr_mem_limit.attr,
        &dev_attr_mem_used_max.attr,
+       &dev_attr_idle.attr,
        &dev_attr_max_comp_streams.attr,
        &dev_attr_comp_algorithm.attr,
 #ifdef CONFIG_ZRAM_WRITEBACK
index 4f83f1f14b0afb0dbe6e420b0c252c77af9c2b10..a84611b97867820f003117988251af425c8ebde3 100644 (file)
@@ -48,6 +48,7 @@ enum zram_pageflags {
        ZRAM_SAME,      /* Page consists the same element */
        ZRAM_WB,        /* page is stored on backing_device */
        ZRAM_HUGE,      /* Incompressible page */
+       ZRAM_IDLE,      /* not accessed page since last idle marking */
 
        __NR_ZRAM_PAGEFLAGS,
 };