Skip to contentSkip to conversation

zram idle page writeback

PATCH Superseded Minchan Kim 3 participants 20 messages Nov 26, 2018 – Nov 29, 2018

Subsystems (4)

v2 of 4 Superseded Latest is v4 →

lore
Share & tools
lore

Minchan Kim

author maintainer
#0 lore raw

v2 cover zram idle page writeback

Inherently, swap device has many idle pages which are rare touched since it was allocated. It is never problem if we use storage device as swap. However, it's just waste for zram-swap.

This patchset supports zram idle page writeback feature.

* Admin can define what is idle page "no access since X time ago"
* Admin can define when zram should writeback them
* Admin can define when zram should stop writeback to prevent wearout

Detail is on each patch's description.

Below first two patches are -stable material so it could go first separately with others in this series.

zram: fix lockdep warning of free block handling
zram: fix double free backing device

* from v1
- add fix dobule free backing device - minchan
- change writeback/idle interface - minchan
- remove direct incompressible page writeback - sergey

Minchan Kim (7):
zram: fix lockdep warning of free block handling
zram: fix double free backing device
zram: refactoring flags and writeback stuff
zram: introduce ZRAM_IDLE flag
zram: support idle/huge page writeback
zram: add bd_stat statistics
zram: writeback throttle

 Documentation/ABI/testing/sysfs-block-zram |  32 ++
 Documentation/blockdev/zram.txt            |  51 +-
 drivers/block/zram/Kconfig                 |   5 +-
 drivers/block/zram/zram_drv.c              | 516 +++++++++++++++------
 drivers/block/zram/zram_drv.h              |  18 +-
 5 files changed, 463 insertions(+), 159 deletions(-)
Signature · 1 line
2.20.0.rc0.387.gc7a69e6b6c-goog
author maintainer
#1 lore raw

PATCH v2 1/7 zram: fix lockdep warning of free block handling

[  254.519728] ================================
[  254.520311] WARNING: inconsistent lock state
[  254.520898] 4.19.0+ #390 Not tainted
[  254.521387] --------------------------------
[  254.521732] inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage.
[  254.521732] zram_verify/2095 [HC0[0]:SC1[1]:HE1:SE0] takes:
[  254.521732] 00000000b1828693 (&(&zram->bitmap_lock)->rlock){+.?.}, at: put_entry_bdev+0x1e/0x50
[  254.521732] {SOFTIRQ-ON-W} state was registered at:
[  254.521732]   _raw_spin_lock+0x2c/0x40
[  254.521732]   zram_make_request+0x755/0xdc9
[  254.521732]   generic_make_request+0x373/0x6a0
[  254.521732]   submit_bio+0x6c/0x140
[  254.521732]   __swap_writepage+0x3a8/0x480
[  254.521732]   shrink_page_list+0x1102/0x1a60
[  254.521732]   shrink_inactive_list+0x21b/0x3f0
[  254.521732]   shrink_node_memcg.constprop.99+0x4f8/0x7e0
[  254.521732]   shrink_node+0x7d/0x2f0
[  254.521732]   do_try_to_free_pages+0xe0/0x300
[  254.521732]   try_to_free_pages+0x116/0x2b0
[  254.521732]   __alloc_pages_slowpath+0x3f4/0xf80
[  254.521732]   __alloc_pages_nodemask+0x2a2/0x2f0
[  254.521732]   __handle_mm_fault+0x42e/0xb50
[  254.521732]   handle_mm_fault+0x55/0xb0
[  254.521732]   __do_page_fault+0x235/0x4b0
[  254.521732]   page_fault+0x1e/0x30
[  254.521732] irq event stamp: 228412
[  254.521732] hardirqs last  enabled at (228412): [<ffffffff98245846>] __slab_free+0x3e6/0x600
[  254.521732] hardirqs last disabled at (228411): [<ffffffff98245625>] __slab_free+0x1c5/0x600
[  254.521732] softirqs last  enabled at (228396): [<ffffffff98e0031e>] __do_softirq+0x31e/0x427
[  254.521732] softirqs last disabled at (228403): [<ffffffff98072051>] irq_exit+0xd1/0xe0
[  254.521732]
[  254.521732] other info that might help us debug this:
[  254.521732]  Possible unsafe locking scenario:
[  254.521732]
[  254.521732]        CPU0
[  254.521732]        ----
[  254.521732]   lock(&(&zram->bitmap_lock)->rlock);
[  254.521732]   <Interrupt>
[  254.521732]     lock(&(&zram->bitmap_lock)->rlock);
[  254.521732]
[  254.521732]  *** DEADLOCK ***
[  254.521732]
[  254.521732] no locks held by zram_verify/2095.
[  254.521732]
[  254.521732] stack backtrace:
[  254.521732] CPU: 5 PID: 2095 Comm: zram_verify Not tainted 4.19.0+ #390
[  254.521732] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
[  254.521732] Call Trace:
[  254.521732]  <IRQ>
[  254.521732]  dump_stack+0x67/0x9b
[  254.521732]  print_usage_bug+0x1bd/0x1d3
[  254.521732]  mark_lock+0x4aa/0x540
[  254.521732]  ? check_usage_backwards+0x160/0x160
[  254.521732]  __lock_acquire+0x51d/0x1300
[  254.521732]  ? free_debug_processing+0x24e/0x400
[  254.521732]  ? bio_endio+0x6d/0x1a0
[  254.521732]  ? lockdep_hardirqs_on+0x9b/0x180
[  254.521732]  ? lock_acquire+0x90/0x180
[  254.521732]  lock_acquire+0x90/0x180
[  254.521732]  ? put_entry_bdev+0x1e/0x50
[  254.521732]  _raw_spin_lock+0x2c/0x40
[  254.521732]  ? put_entry_bdev+0x1e/0x50
[  254.521732]  put_entry_bdev+0x1e/0x50
[  254.521732]  zram_free_page+0xf6/0x110
[  254.521732]  zram_slot_free_notify+0x42/0xa0
[  254.521732]  end_swap_bio_read+0x5b/0x170
[  254.521732]  blk_update_request+0x8f/0x340
[  254.521732]  scsi_end_request+0x2c/0x1e0
[  254.521732]  scsi_io_completion+0x98/0x650
[  254.521732]  blk_done_softirq+0x9e/0xd0
[  254.521732]  __do_softirq+0xcc/0x427
[  254.521732]  irq_exit+0xd1/0xe0
[  254.521732]  do_IRQ+0x93/0x120
[  254.521732]  common_interrupt+0xf/0xf
[  254.521732]  </IRQ>

With writeback feature, zram_slot_free_notify could be called in softirq context by end_swap_bio_read. However, bitmap_lock is not aware of that so lockdep yell out. Thanks.

The problem is not only bitmap_lock but it is also zram_slot_lock so straightforward solution would disable irq on zram_slot_lock which covers every bitmap_lock, too.
Although duration disabling the irq is short in many places zram_slot_lock is used, a place(ie, decompress) is not fast enough to hold irqlock on relying on compression algorithm so it's not a option.

The approach in this patch is just "best effort", not guarantee "freeing orphan zpage". If the zram_slot_lock contention may happen, kernel couldn't free the zpage until it recycles the block. However, such contention between zram_slot_free_notify and other places to hold zram_slot_lock should be very rare in real practice. To see how often it happens, this patch adds new debug stat "miss_free".

It also adds irq lock in get/put_block_bdev to prevent deadlock lockdep reported. The reason I used irq disable rather than bottom half is swap_slot_free_notify could be called with irq disabled so it breaks local_bh_enable's rule. The irqlock works on only writebacked zram slot entry so it should be not frequent lock.

---
 drivers/block/zram/zram_drv.c | 56 +++++++++++++++++++++++++----------
 drivers/block/zram/zram_drv.h |  1 +
 2 files changed, 42 insertions(+), 15 deletions(-)
drivers/block/zram/zram_drv.c +41 -15
index 4879595200e1..472027eaed60 100644
@@ -53,6 +53,11 @@ static size_t huge_class_size;
 
 static void zram_free_page(struct zram *zram, size_t index);
 
+static int zram_slot_trylock(struct zram *zram, u32 index)
+{
+	return bit_spin_trylock(ZRAM_LOCK, &zram->table[index].value);
+}
+
 static void zram_slot_lock(struct zram *zram, u32 index)
 {
 	bit_spin_lock(ZRAM_LOCK, &zram->table[index].value);
@@ -443,29 +448,45 @@ static ssize_t backing_dev_store(struct device *dev,
 
 static unsigned long get_entry_bdev(struct zram *zram)
 {
-	unsigned long entry;
+	unsigned long blk_idx;
+	unsigned long ret = 0;
 
-	spin_lock(&zram->bitmap_lock);
 	/* skip 0 bit to confuse zram.handle = 0 */
-	entry = find_next_zero_bit(zram->bitmap, zram->nr_pages, 1);
-	if (entry == zram->nr_pages) {
-		spin_unlock(&zram->bitmap_lock);
-		return 0;
+	blk_idx = find_next_zero_bit(zram->bitmap, zram->nr_pages, 1);
+	if (blk_idx == zram->nr_pages)
+		goto retry;
+
+	spin_lock_irq(&zram->bitmap_lock);
+	if (test_bit(blk_idx, zram->bitmap)) {
+		spin_unlock_irq(&zram->bitmap_lock);
+		goto retry;
 	}
 
-	set_bit(entry, zram->bitmap);
-	spin_unlock(&zram->bitmap_lock);
+	set_bit(blk_idx, zram->bitmap);
+	ret = blk_idx;
+	goto out;
+retry:
+	spin_lock_irq(&zram->bitmap_lock);
+	blk_idx = find_next_zero_bit(zram->bitmap, zram->nr_pages, 1);
+	if (blk_idx == zram->nr_pages)
+		goto out;
+
+	set_bit(blk_idx, zram->bitmap);
+	ret = blk_idx;
+out:
+	spin_unlock_irq(&zram->bitmap_lock);
 
-	return entry;
+	return ret;
 }
 
 static void put_entry_bdev(struct zram *zram, unsigned long entry)
 {
 	int was_set;
+	unsigned long flags;
 
-	spin_lock(&zram->bitmap_lock);
+	spin_lock_irqsave(&zram->bitmap_lock, flags);
 	was_set = test_and_clear_bit(entry, zram->bitmap);
-	spin_unlock(&zram->bitmap_lock);
+	spin_unlock_irqrestore(&zram->bitmap_lock, flags);
 	WARN_ON_ONCE(!was_set);
 }
 
@@ -886,9 +907,10 @@ static ssize_t debug_stat_show(struct device *dev,
 
 	down_read(&zram->init_lock);
 	ret = scnprintf(buf, PAGE_SIZE,
-			"version: %d\n%8llu\n",
+			"version: %d\n%8llu %8llu\n",
 			version,
-			(u64)atomic64_read(&zram->stats.writestall));
+			(u64)atomic64_read(&zram->stats.writestall),
+			(u64)atomic64_read(&zram->stats.miss_free));
 	up_read(&zram->init_lock);
 
 	return ret;
@@ -1400,10 +1422,14 @@ static void zram_slot_free_notify(struct block_device *bdev,
 
 	zram = bdev->bd_disk->private_data;
 
-	zram_slot_lock(zram, index);
+	atomic64_inc(&zram->stats.notify_free);
+	if (!zram_slot_trylock(zram, index)) {
+		atomic64_inc(&zram->stats.miss_free);
+		return;
+	}
+
 	zram_free_page(zram, index);
 	zram_slot_unlock(zram, index);
-	atomic64_inc(&zram->stats.notify_free);
 }
 
 static int zram_rw_page(struct block_device *bdev, sector_t sector,
drivers/block/zram/zram_drv.h +1 -0
index 72c8584b6dff..89da501292ff 100644
@@ -79,6 +79,7 @@ struct zram_stats {
 	atomic64_t pages_stored;	/* no. of pages currently stored */
 	atomic_long_t max_used_pages;	/* no. of maximum pages stored */
 	atomic64_t writestall;		/* no. of write slow paths */
+	atomic64_t miss_free;		/* no. of missed free */
 };
 
 struct zram {
Signature · 1 line
2.20.0.rc0.387.gc7a69e6b6c-goog
#2 lore raw

Re: [PATCH v2 1/7] zram: fix lockdep warning of free block handling

Quoted 69 lines · On Mon, 26 Nov 2018 17:28:07 +0900 Minchan Kim <[email protected]> wrote:

...

With writeback feature, zram_slot_free_notify could be called in softirq context by end_swap_bio_read. However, bitmap_lock is not aware of that so lockdep yell out. Thanks.

The problem is not only bitmap_lock but it is also zram_slot_lock so straightforward solution would disable irq on zram_slot_lock which covers every bitmap_lock, too.
Although duration disabling the irq is short in many places zram_slot_lock is used, a place(ie, decompress) is not fast enough to hold irqlock on relying on compression algorithm so it's not a option.

The approach in this patch is just "best effort", not guarantee "freeing orphan zpage". If the zram_slot_lock contention may happen, kernel couldn't free the zpage until it recycles the block. However, such contention between zram_slot_free_notify and other places to hold zram_slot_lock should be very rare in real practice. To see how often it happens, this patch adds new debug stat "miss_free".

It also adds irq lock in get/put_block_bdev to prevent deadlock lockdep reported. The reason I used irq disable rather than bottom half is swap_slot_free_notify could be called with irq disabled so it breaks local_bh_enable's rule. The irqlock works on only writebacked zram slot entry so it should be not frequent lock.

---
 drivers/block/zram/zram_drv.c | 56 +++++++++++++++++++++++++----------
 drivers/block/zram/zram_drv.h |  1 +
 2 files changed, 42 insertions(+), 15 deletions(-)
drivers/block/zram/zram_drv.c +10 -6
index 4879595200e1..472027eaed60 100644
@@ -53,6 +53,11 @@ static size_t huge_class_size;
 
 static void zram_free_page(struct zram *zram, size_t index);
 
+static int zram_slot_trylock(struct zram *zram, u32 index)
+{
+	return bit_spin_trylock(ZRAM_LOCK, &zram->table[index].value);
+}
+
 static void zram_slot_lock(struct zram *zram, u32 index)
 {
 	bit_spin_lock(ZRAM_LOCK, &zram->table[index].value);
@@ -443,29 +448,45 @@ static ssize_t backing_dev_store(struct device *dev,
 
 static unsigned long get_entry_bdev(struct zram *zram)
 {
-	unsigned long entry;
+	unsigned long blk_idx;
+	unsigned long ret = 0;
 
-	spin_lock(&zram->bitmap_lock);
 	/* skip 0 bit to confuse zram.handle = 0 */
-	entry = find_next_zero_bit(zram->bitmap, zram->nr_pages, 1);
-	if (entry == zram->nr_pages) {
-		spin_unlock(&zram->bitmap_lock);
-		return 0;
+	blk_idx = find_next_zero_bit(zram->bitmap, zram->nr_pages, 1);
+	if (blk_idx == zram->nr_pages)
+		goto retry;

drivers/block/zram/zram_drv.c static ssize_t backing_dev_store(struct device *dev, · line 465

Quoted 10 lines
drivers/block/zram/zram_drv.c +6 -2
+
+	spin_lock_irq(&zram->bitmap_lock);
+	if (test_bit(blk_idx, zram->bitmap)) {
+		spin_unlock_irq(&zram->bitmap_lock);
+		goto retry;
 	}
 
-	set_bit(entry, zram->bitmap);
-	spin_unlock(&zram->bitmap_lock);
+	set_bit(blk_idx, zram->bitmap);

Here we could do

	if (test_and_set_bit(...)) {
		spin_unlock(...);
		goto retry;

But it's weird to take the spinlock on behalf of bitops which are already atomic!

It seems rather suspicious to me. Why are we doing this?

Quoted 17 lines
drivers/block/zram/zram_drv.c +13 -1
+	ret = blk_idx;
+	goto out;
+retry:
+	spin_lock_irq(&zram->bitmap_lock);
+	blk_idx = find_next_zero_bit(zram->bitmap, zram->nr_pages, 1);
+	if (blk_idx == zram->nr_pages)
+		goto out;
+
+	set_bit(blk_idx, zram->bitmap);
+	ret = blk_idx;
+out:
+	spin_unlock_irq(&zram->bitmap_lock);
 
-	return entry;
+	return ret;
 }
 

drivers/block/zram/zram_drv.c static ssize_t backing_dev_store(struct device *dev, · line 489

Quoted 10 lines
drivers/block/zram/zram_drv.c +3 -2
 static void put_entry_bdev(struct zram *zram, unsigned long entry)
 {
 	int was_set;
+	unsigned long flags;
 
-	spin_lock(&zram->bitmap_lock);
+	spin_lock_irqsave(&zram->bitmap_lock, flags);
 	was_set = test_and_clear_bit(entry, zram->bitmap);
-	spin_unlock(&zram->bitmap_lock);
+	spin_unlock_irqrestore(&zram->bitmap_lock, flags);

Here's another one. Surely that locking is unnecessary.

Quoted 3 lines
drivers/block/zram/zram_drv.c +0 -0
 	WARN_ON_ONCE(!was_set);
 }
 
author maintainer
#3 lore raw

Re: [PATCH v2 1/7] zram: fix lockdep warning of free block handling

Quoted 84 lines · Andrew Morton
Quoted 69 lines · On Mon, 26 Nov 2018 17:28:07 +0900 Minchan Kim <[email protected]> wrote:

...

With writeback feature, zram_slot_free_notify could be called in softirq context by end_swap_bio_read. However, bitmap_lock is not aware of that so lockdep yell out. Thanks.

The problem is not only bitmap_lock but it is also zram_slot_lock so straightforward solution would disable irq on zram_slot_lock which covers every bitmap_lock, too.
Although duration disabling the irq is short in many places zram_slot_lock is used, a place(ie, decompress) is not fast enough to hold irqlock on relying on compression algorithm so it's not a option.

The approach in this patch is just "best effort", not guarantee "freeing orphan zpage". If the zram_slot_lock contention may happen, kernel couldn't free the zpage until it recycles the block. However, such contention between zram_slot_free_notify and other places to hold zram_slot_lock should be very rare in real practice. To see how often it happens, this patch adds new debug stat "miss_free".

It also adds irq lock in get/put_block_bdev to prevent deadlock lockdep reported. The reason I used irq disable rather than bottom half is swap_slot_free_notify could be called with irq disabled so it breaks local_bh_enable's rule. The irqlock works on only writebacked zram slot entry so it should be not frequent lock.

---
 drivers/block/zram/zram_drv.c | 56 +++++++++++++++++++++++++----------
 drivers/block/zram/zram_drv.h |  1 +
 2 files changed, 42 insertions(+), 15 deletions(-)
drivers/block/zram/zram_drv.c +10 -6
index 4879595200e1..472027eaed60 100644
@@ -53,6 +53,11 @@ static size_t huge_class_size;
 
 static void zram_free_page(struct zram *zram, size_t index);
 
+static int zram_slot_trylock(struct zram *zram, u32 index)
+{
+	return bit_spin_trylock(ZRAM_LOCK, &zram->table[index].value);
+}
+
 static void zram_slot_lock(struct zram *zram, u32 index)
 {
 	bit_spin_lock(ZRAM_LOCK, &zram->table[index].value);
@@ -443,29 +448,45 @@ static ssize_t backing_dev_store(struct device *dev,
 
 static unsigned long get_entry_bdev(struct zram *zram)
 {
-	unsigned long entry;
+	unsigned long blk_idx;
+	unsigned long ret = 0;
 
-	spin_lock(&zram->bitmap_lock);
 	/* skip 0 bit to confuse zram.handle = 0 */
-	entry = find_next_zero_bit(zram->bitmap, zram->nr_pages, 1);
-	if (entry == zram->nr_pages) {
-		spin_unlock(&zram->bitmap_lock);
-		return 0;
+	blk_idx = find_next_zero_bit(zram->bitmap, zram->nr_pages, 1);
+	if (blk_idx == zram->nr_pages)
+		goto retry;

drivers/block/zram/zram_drv.c static ssize_t backing_dev_store(struct device *dev, · line 465

Quoted 10 lines
drivers/block/zram/zram_drv.c +6 -2
+
+	spin_lock_irq(&zram->bitmap_lock);
+	if (test_bit(blk_idx, zram->bitmap)) {
+		spin_unlock_irq(&zram->bitmap_lock);
+		goto retry;
 	}
 
-	set_bit(entry, zram->bitmap);
-	spin_unlock(&zram->bitmap_lock);
+	set_bit(blk_idx, zram->bitmap);

Here we could do

Quoted 8 lines
	if (test_and_set_bit(...)) {
		spin_unlock(...);
		goto retry;

But it's weird to take the spinlock on behalf of bitops which are already atomic!

It seems rather suspicious to me. Why are we doing this?

What I need is look_up_and_set operation. I don't see there is an atomic operation for that. But I want to minimize irq disabled area so first, it scans the bit lockless and if race happens, i can try under the lock.

It seems __set_bit is enough under the lock.

Quoted 23 lines
Quoted 23 lines
drivers/block/zram/zram_drv.c +14 -1
+	ret = blk_idx;
+	goto out;
+retry:
+	spin_lock_irq(&zram->bitmap_lock);
+	blk_idx = find_next_zero_bit(zram->bitmap, zram->nr_pages, 1);
+	if (blk_idx == zram->nr_pages)
+		goto out;
+
+	set_bit(blk_idx, zram->bitmap);
+	ret = blk_idx;
+out:
+	spin_unlock_irq(&zram->bitmap_lock);
 
-	return entry;
+	return ret;
 }
 
 static void put_entry_bdev(struct zram *zram, unsigned long entry)
 {
 	int was_set;
+	unsigned long flags;
 
Quoted 7 lines

drivers/block/zram/zram_drv.c static ssize_t backing_dev_store(struct device *dev, · line 489

Quoted 5 lines
drivers/block/zram/zram_drv.c +2 -2
-	spin_lock(&zram->bitmap_lock);
+	spin_lock_irqsave(&zram->bitmap_lock, flags);
 	was_set = test_and_clear_bit(entry, zram->bitmap);
-	spin_unlock(&zram->bitmap_lock);
+	spin_unlock_irqrestore(&zram->bitmap_lock, flags);

Here's another one. Surely that locking is unnecessary.

Indeed! although get_entry_bdev side can miss some bits, it's not a critical problem. Benefit is we might remove irq disable for the lockdep problem.
Yes, I will cook and test.

Thanks, Andrew.

author maintainer
#4 lore raw

PATCH v2 2/7 zram: fix double free backing device

In reply to Minchan Kim

If blkdev_get fails, we shouldn't do blkdev_put. Otherwise, kernel emits below log. This patch fixes it.

[   31.073006] WARNING: CPU: 0 PID: 1893 at fs/block_dev.c:1828 blkdev_put+0x105/0x120
[   31.075104] Modules linked in:
[   31.075898] CPU: 0 PID: 1893 Comm: swapoff Not tainted 4.19.0+ #453
[   31.077484] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
[   31.079589] RIP: 0010:blkdev_put+0x105/0x120
[   31.080606] Code: 48 c7 80 a0 00 00 00 00 00 00 00 48 c7 c7 40 e7 40 96 e8 6e 47 73 00 48 8b bb e0 00 00 00 e9 2c ff ff ff 0f 0b e9 75 ff ff ff <0f> 0b e9 5a ff ff ff 48 c7 80 a0 00 00 00 00 00 00 00 eb 87 0f 1f
[   31.085080] RSP: 0018:ffffb409005c7ed0 EFLAGS: 00010297
[   31.086383] RAX: ffff9779fe5a8040 RBX: ffff9779fbc17300 RCX: 00000000b9fc37a4
[   31.088105] RDX: 0000000000000001 RSI: 0000000000000000 RDI: ffffffff9640e740
[   31.089850] RBP: ffff9779fbc17318 R08: ffffffff95499a89 R09: 0000000000000004
[   31.091201] R10: ffffb409005c7e50 R11: 7a9ef6088ff4d4a1 R12: 0000000000000083
[   31.092276] R13: ffff9779fe607b98 R14: 0000000000000000 R15: ffff9779fe607a38
[   31.093355] FS:  00007fc118d9b840(0000) GS:ffff9779fc600000(0000) knlGS:0000000000000000
[   31.094582] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   31.095541] CR2: 00007fc11894b8dc CR3: 00000000339f6001 CR4: 0000000000160ef0
[   31.096781] Call Trace:
[   31.097212]  __x64_sys_swapoff+0x46d/0x490
[   31.097914]  do_syscall_64+0x5a/0x190
[   31.098550]  entry_SYSCALL_64_after_hwframe+0x49/0xbe
[   31.099402] RIP: 0033:0x7fc11843ec27
[   31.100013] Code: 73 01 c3 48 8b 0d 71 62 2c 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 b8 a8 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 41 62 2c 00 f7 d8 64 89 01 48
[   31.103149] RSP: 002b:00007ffdf69be648 EFLAGS: 00000206 ORIG_RAX: 00000000000000a8
[   31.104425] RAX: ffffffffffffffda RBX: 00000000011d98c0 RCX: 00007fc11843ec27
[   31.105627] RDX: 0000000000000001 RSI: 0000000000000001 RDI: 00000000011d98c0
[   31.106847] RBP: 0000000000000001 R08: 00007ffdf69be690 R09: 0000000000000001
[   31.108038] R10: 00000000000002b1 R11: 0000000000000206 R12: 0000000000000001
[   31.109231] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
[   31.110433] irq event stamp: 4466
[   31.111001] hardirqs last  enabled at (4465): [<ffffffff953ebd43>] __free_pages_ok+0x1e3/0x490
[   31.112437] hardirqs last disabled at (4466): [<ffffffff95201b7a>] trace_hardirqs_off_thunk+0x1a/0x1c
[   31.113973] softirqs last  enabled at (3420): [<ffffffff95e00333>] __do_softirq+0x333/0x446
[   31.115364] softirqs last disabled at (3407): [<ffffffff9527aee1>] irq_exit+0xd1/0xe0
---
 drivers/block/zram/zram_drv.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/block/zram/zram_drv.c +3 -1
index 472027eaed60..514f5aaf6eff 100644
@@ -387,8 +387,10 @@ static ssize_t backing_dev_store(struct device *dev,
 
 	bdev = bdgrab(I_BDEV(inode));
 	err = blkdev_get(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL, zram);
-	if (err < 0)
+	if (err < 0) {
+		bdev = NULL;
 		goto out;
+	}
 
 	nr_pages = i_size_read(inode) >> PAGE_SHIFT;
 	bitmap_sz = BITS_TO_LONGS(nr_pages) * sizeof(long);
Signature · 1 line
2.20.0.rc0.387.gc7a69e6b6c-goog
author maintainer
#5 lore raw

PATCH v2 3/7 zram: refactoring flags and writeback stuff

In reply to Minchan Kim

This patch does renaming some variables and restructuring some codes for better redability in writeback and zs_free_page.

---
 drivers/block/zram/zram_drv.c | 105 +++++++++++++---------------------
 drivers/block/zram/zram_drv.h |   8 +--
 2 files changed, 44 insertions(+), 69 deletions(-)
drivers/block/zram/zram_drv.c +40 -65
index 514f5aaf6eff..fee7e67c750d 100644
@@ -55,17 +55,17 @@ static void zram_free_page(struct zram *zram, size_t index);
 
 static int zram_slot_trylock(struct zram *zram, u32 index)
 {
-	return bit_spin_trylock(ZRAM_LOCK, &zram->table[index].value);
+	return bit_spin_trylock(ZRAM_LOCK, &zram->table[index].flags);
 }
 
 static void zram_slot_lock(struct zram *zram, u32 index)
 {
-	bit_spin_lock(ZRAM_LOCK, &zram->table[index].value);
+	bit_spin_lock(ZRAM_LOCK, &zram->table[index].flags);
 }
 
 static void zram_slot_unlock(struct zram *zram, u32 index)
 {
-	bit_spin_unlock(ZRAM_LOCK, &zram->table[index].value);
+	bit_spin_unlock(ZRAM_LOCK, &zram->table[index].flags);
 }
 
 static inline bool init_done(struct zram *zram)
@@ -76,7 +76,7 @@ static inline bool init_done(struct zram *zram)
 static inline bool zram_allocated(struct zram *zram, u32 index)
 {
 
-	return (zram->table[index].value >> (ZRAM_FLAG_SHIFT + 1)) ||
+	return (zram->table[index].flags >> (ZRAM_FLAG_SHIFT + 1)) ||
 					zram->table[index].handle;
 }
 
@@ -99,19 +99,19 @@ static void zram_set_handle(struct zram *zram, u32 index, unsigned long handle)
 static bool zram_test_flag(struct zram *zram, u32 index,
 			enum zram_pageflags flag)
 {
-	return zram->table[index].value & BIT(flag);
+	return zram->table[index].flags & BIT(flag);
 }
 
 static void zram_set_flag(struct zram *zram, u32 index,
 			enum zram_pageflags flag)
 {
-	zram->table[index].value |= BIT(flag);
+	zram->table[index].flags |= BIT(flag);
 }
 
 static void zram_clear_flag(struct zram *zram, u32 index,
 			enum zram_pageflags flag)
 {
-	zram->table[index].value &= ~BIT(flag);
+	zram->table[index].flags &= ~BIT(flag);
 }
 
 static inline void zram_set_element(struct zram *zram, u32 index,
@@ -127,15 +127,15 @@ static unsigned long zram_get_element(struct zram *zram, u32 index)
 
 static size_t zram_get_obj_size(struct zram *zram, u32 index)
 {
-	return zram->table[index].value & (BIT(ZRAM_FLAG_SHIFT) - 1);
+	return zram->table[index].flags & (BIT(ZRAM_FLAG_SHIFT) - 1);
 }
 
 static void zram_set_obj_size(struct zram *zram,
 					u32 index, size_t size)
 {
-	unsigned long flags = zram->table[index].value >> ZRAM_FLAG_SHIFT;
+	unsigned long flags = zram->table[index].flags >> ZRAM_FLAG_SHIFT;
 
-	zram->table[index].value = (flags << ZRAM_FLAG_SHIFT) | size;
+	zram->table[index].flags = (flags << ZRAM_FLAG_SHIFT) | size;
 }
 
 #if PAGE_SIZE != 4096
@@ -282,16 +282,11 @@ static ssize_t mem_used_max_store(struct device *dev,
 }
 
 #ifdef CONFIG_ZRAM_WRITEBACK
-static bool zram_wb_enabled(struct zram *zram)
-{
-	return zram->backing_dev;
-}
-
 static void reset_bdev(struct zram *zram)
 {
 	struct block_device *bdev;
 
-	if (!zram_wb_enabled(zram))
+	if (!zram->backing_dev)
 		return;
 
 	bdev = zram->bdev;
@@ -318,7 +313,7 @@ static ssize_t backing_dev_show(struct device *dev,
 	ssize_t ret;
 
 	down_read(&zram->init_lock);
-	if (!zram_wb_enabled(zram)) {
+	if (!zram->backing_dev) {
 		memcpy(buf, "none\n", 5);
 		up_read(&zram->init_lock);
 		return 5;
@@ -448,7 +443,7 @@ static ssize_t backing_dev_store(struct device *dev,
 	return err;
 }
 
-static unsigned long get_entry_bdev(struct zram *zram)
+static unsigned long alloc_block_bdev(struct zram *zram)
 {
 	unsigned long blk_idx;
 	unsigned long ret = 0;
@@ -481,13 +476,13 @@ static unsigned long get_entry_bdev(struct zram *zram)
 	return ret;
 }
 
-static void put_entry_bdev(struct zram *zram, unsigned long entry)
+static void free_block_bdev(struct zram *zram, unsigned long blk_idx)
 {
 	int was_set;
 	unsigned long flags;
 
 	spin_lock_irqsave(&zram->bitmap_lock, flags);
-	was_set = test_and_clear_bit(entry, zram->bitmap);
+	was_set = test_and_clear_bit(blk_idx, zram->bitmap);
 	spin_unlock_irqrestore(&zram->bitmap_lock, flags);
 	WARN_ON_ONCE(!was_set);
 }
@@ -601,7 +596,7 @@ static int write_to_bdev(struct zram *zram, struct bio_vec *bvec,
 	if (!bio)
 		return -ENOMEM;
 
-	entry = get_entry_bdev(zram);
+	entry = alloc_block_bdev(zram);
 	if (!entry) {
 		bio_put(bio);
 		return -ENOSPC;
@@ -612,7 +607,7 @@ static int write_to_bdev(struct zram *zram, struct bio_vec *bvec,
 	if (!bio_add_page(bio, bvec->bv_page, bvec->bv_len,
 					bvec->bv_offset)) {
 		bio_put(bio);
-		put_entry_bdev(zram, entry);
+		free_block_bdev(zram, entry);
 		return -EIO;
 	}
 
@@ -630,18 +625,7 @@ static int write_to_bdev(struct zram *zram, struct bio_vec *bvec,
 	return 0;
 }
 
-static void zram_wb_clear(struct zram *zram, u32 index)
-{
-	unsigned long entry;
-
-	zram_clear_flag(zram, index, ZRAM_WB);
-	entry = zram_get_element(zram, index);
-	zram_set_element(zram, index, 0);
-	put_entry_bdev(zram, entry);
-}
-
 #else
-static bool zram_wb_enabled(struct zram *zram) { return false; }
 static inline void reset_bdev(struct zram *zram) {};
 static int write_to_bdev(struct zram *zram, struct bio_vec *bvec,
 					u32 index, struct bio *parent,
@@ -656,7 +640,8 @@ static int read_from_bdev(struct zram *zram, struct bio_vec *bvec,
 {
 	return -EIO;
 }
-static void zram_wb_clear(struct zram *zram, u32 index) {}
+
+static void free_block_bdev(struct zram *zram, unsigned long blk_idx) {};
 #endif
 
 #ifdef CONFIG_ZRAM_MEMORY_TRACKING
@@ -678,11 +663,6 @@ static void zram_accessed(struct zram *zram, u32 index)
 	zram->table[index].ac_time = ktime_get_boottime();
 }
 
-static void zram_reset_access(struct zram *zram, u32 index)
-{
-	zram->table[index].ac_time = 0;
-}
-
 static ssize_t read_block_state(struct file *file, char __user *buf,
 				size_t count, loff_t *ppos)
 {
@@ -763,7 +743,6 @@ static void zram_debugfs_unregister(struct zram *zram)
 static void zram_debugfs_create(void) {};
 static void zram_debugfs_destroy(void) {};
 static void zram_accessed(struct zram *zram, u32 index) {};
-static void zram_reset_access(struct zram *zram, u32 index) {};
 static void zram_debugfs_register(struct zram *zram) {};
 static void zram_debugfs_unregister(struct zram *zram) {};
 #endif
@@ -964,17 +943,18 @@ static void zram_free_page(struct zram *zram, size_t index)
 {
 	unsigned long handle;
 
-	zram_reset_access(zram, index);
-
+#ifdef CONFIG_ZRAM_MEMORY_TRACKING
+	zram->table[index].ac_time = 0;
+#endif
 	if (zram_test_flag(zram, index, ZRAM_HUGE)) {
 		zram_clear_flag(zram, index, ZRAM_HUGE);
 		atomic64_dec(&zram->stats.huge_pages);
 	}
 
-	if (zram_wb_enabled(zram) && zram_test_flag(zram, index, ZRAM_WB)) {
-		zram_wb_clear(zram, index);
-		atomic64_dec(&zram->stats.pages_stored);
-		return;
+	if (zram_test_flag(zram, index, ZRAM_WB)) {
+		zram_clear_flag(zram, index, ZRAM_WB);
+		free_block_bdev(zram, zram_get_element(zram, index));
+		goto out;
 	}
 
 	/*
@@ -983,10 +963,8 @@ static void zram_free_page(struct zram *zram, size_t index)
 	 */
 	if (zram_test_flag(zram, index, ZRAM_SAME)) {
 		zram_clear_flag(zram, index, ZRAM_SAME);
-		zram_set_element(zram, index, 0);
 		atomic64_dec(&zram->stats.same_pages);
-		atomic64_dec(&zram->stats.pages_stored);
-		return;
+		goto out;
 	}
 
 	handle = zram_get_handle(zram, index);
@@ -997,10 +975,11 @@ static void zram_free_page(struct zram *zram, size_t index)
 
 	atomic64_sub(zram_get_obj_size(zram, index),
 			&zram->stats.compr_data_size);
+out:
 	atomic64_dec(&zram->stats.pages_stored);
-
 	zram_set_handle(zram, index, 0);
 	zram_set_obj_size(zram, index, 0);
+	WARN_ON_ONCE(zram->table[index].flags & ~(1UL << ZRAM_LOCK));
 }
 
 static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index,
@@ -1011,24 +990,20 @@ static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index,
 	unsigned int size;
 	void *src, *dst;
 
-	if (zram_wb_enabled(zram)) {
-		zram_slot_lock(zram, index);
-		if (zram_test_flag(zram, index, ZRAM_WB)) {
-			struct bio_vec bvec;
-
-			zram_slot_unlock(zram, index);
+	zram_slot_lock(zram, index);
+	if (zram_test_flag(zram, index, ZRAM_WB)) {
+		struct bio_vec bvec;
 
-			bvec.bv_page = page;
-			bvec.bv_len = PAGE_SIZE;
-			bvec.bv_offset = 0;
-			return read_from_bdev(zram, &bvec,
-					zram_get_element(zram, index),
-					bio, partial_io);
-		}
 		zram_slot_unlock(zram, index);
+
+		bvec.bv_page = page;
+		bvec.bv_len = PAGE_SIZE;
+		bvec.bv_offset = 0;
+		return read_from_bdev(zram, &bvec,
+				zram_get_element(zram, index),
+				bio, partial_io);
 	}
 
-	zram_slot_lock(zram, index);
 	handle = zram_get_handle(zram, index);
 	if (!handle || zram_test_flag(zram, index, ZRAM_SAME)) {
 		unsigned long value;
@@ -1140,7 +1115,7 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec,
 
 	if (unlikely(comp_len >= huge_class_size)) {
 		comp_len = PAGE_SIZE;
-		if (zram_wb_enabled(zram) && allow_wb) {
+		if (zram->backing_dev && allow_wb) {
 			zcomp_stream_put(zram->comp);
 			ret = write_to_bdev(zram, bvec, index, bio, &element);
 			if (!ret) {
drivers/block/zram/zram_drv.h +4 -4
index 89da501292ff..d75bf190f262 100644
@@ -30,7 +30,7 @@
 
 
 /*
- * The lower ZRAM_FLAG_SHIFT bits of table.value is for
+ * The lower ZRAM_FLAG_SHIFT bits of table.flags is for
  * object size (excluding header), the higher bits is for
  * zram_pageflags.
  *
@@ -41,7 +41,7 @@
  */
 #define ZRAM_FLAG_SHIFT 24
 
-/* Flags for zram pages (table[page_no].value) */
+/* Flags for zram pages (table[page_no].flags) */
 enum zram_pageflags {
 	/* zram slot is locked */
 	ZRAM_LOCK = ZRAM_FLAG_SHIFT,
@@ -60,7 +60,7 @@ struct zram_table_entry {
 		unsigned long handle;
 		unsigned long element;
 	};
-	unsigned long value;
+	unsigned long flags;
 #ifdef CONFIG_ZRAM_MEMORY_TRACKING
 	ktime_t ac_time;
 #endif
@@ -105,8 +105,8 @@ struct zram {
 	 * zram is claimed so open request will be failed
 	 */
 	bool claim; /* Protected by bdev->bd_mutex */
-#ifdef CONFIG_ZRAM_WRITEBACK
 	struct file *backing_dev;
+#ifdef CONFIG_ZRAM_WRITEBACK
 	struct block_device *bdev;
 	unsigned int old_block_size;
 	unsigned long *bitmap;
Signature · 1 line
2.20.0.rc0.387.gc7a69e6b6c-goog
author maintainer
#6 lore raw

PATCH v2 4/7 zram: introduce ZRAM_IDLE flag

In reply to Minchan Kim

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.

---
 Documentation/ABI/testing/sysfs-block-zram |  8 ++++
 Documentation/blockdev/zram.txt            | 10 ++--
 drivers/block/zram/zram_drv.c              | 55 ++++++++++++++++++++--
 drivers/block/zram/zram_drv.h              |  1 +
 4 files changed, 67 insertions(+), 7 deletions(-)
Documentation/ABI/testing/sysfs-block-zram +8 -0
index c1513c756af1..04c9a5980bc7 100644
@@ -98,3 +98,11 @@ Contact:	Minchan Kim <[email protected]>
 		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 <[email protected]>
+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
Documentation/blockdev/zram.txt +6 -4
index 3c1b5ab54bc0..f3bcd716d8a9 100644
@@ -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
drivers/block/zram/zram_drv.c +52 -3

101 lines not on this page · raw message

drivers/block/zram/zram_drv.h +1 -0
index d75bf190f262..214fa4bb46b9 100644
@@ -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,
 };
Signature · 1 line
2.20.0.rc0.387.gc7a69e6b6c-goog
author maintainer
#7 lore raw

PATCH v2 5/7 zram: support idle/huge page writeback

In reply to Minchan Kim

This patch supports new feature "zram idle/huge page writeback". On zram-swap usecase, zram has usually many idle/huge swap pages. It's pointless to keep in memory(ie, zram).

To solve the problem, this feature introduces idle/huge page writeback to backing device so the goal is to save more memory space on embedded system.

Normal sequence to use idle/huge page writeback feature is as follows,

while (1) {

        # mark allocated zram slot to idle
        echo all > /sys/block/zram0/idle
        # leave system working for several hours
        # Unless there is no access for some blocks on zram,
	# they are still IDLE marked pages.

echo "idle" > /sys/block/zram0/writeback
or/and
echo "huge" > /sys/block/zram0/writeback
# write the IDLE or/and huge marked slot into backing device # and free the memory.
}

By per discussion:
https://lore.kernel.org/lkml/20181122065926.GG3441@jagdpanzerIV/T/#u,

This patch removes direct incommpressibe page writeback feature (d2afd25114f4, zram: write incompressible pages to backing device) so we could regard it as regression because incompressible pages doesn't go to backing storage automatically. Instead, usre should do it via "echo huge" > /sys/block/zram/writeback" manually.

If we hear some regression, we could restore the function.

---
 Documentation/ABI/testing/sysfs-block-zram |   7 +
 Documentation/blockdev/zram.txt            |  28 ++-
 drivers/block/zram/Kconfig                 |   5 +-
 drivers/block/zram/zram_drv.c              | 245 ++++++++++++++-------
 drivers/block/zram/zram_drv.h              |   1 +
 5 files changed, 207 insertions(+), 79 deletions(-)
Documentation/ABI/testing/sysfs-block-zram +7 -0
index 04c9a5980bc7..d1f80b077885 100644
@@ -106,3 +106,10 @@ Contact:	Minchan Kim <[email protected]>
 		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
+
+What:		/sys/block/zram<id>/writeback
+Date:		November 2018
+Contact:	Minchan Kim <[email protected]>
+Description:
+		The writeback file is write-only and trigger idle and/or
+		huge page writeback to backing device.
Documentation/blockdev/zram.txt +24 -4
index f3bcd716d8a9..806cdaabac83 100644
@@ -238,11 +238,31 @@ The stat file represents device's mm statistics. It consists of a single
 
 = writeback
 
-With incompressible pages, there is no memory saving with zram.
-Instead, with CONFIG_ZRAM_WRITEBACK, zram can write incompressible page
+With CONFIG_ZRAM_WRITEBACK, zram can write idle/incompressible page
 to backing storage rather than keeping it in memory.
-User should set up backing device via /sys/block/zramX/backing_dev
-before disksize setting.
+To use the feature, admin should set up backing device via
+
+	"echo /dev/sda5 > /sys/block/zramX/backing_dev"
+
+before disksize setting. It supports only partition at this moment.
+If admin want to use incompressible page writeback, they could do via
+
+	"echo huge > /sys/block/zramX/write"
+
+To use idle page writeback, first, user need to declare zram pages
+as idle.
+
+	"echo all > /sys/block/zramX/idle"
+
+From now on, any pages on zram are idle pages. The idle mark
+will be removed until someone request access of the block.
+IOW, unless there is access request, those pages are still idle pages.
+
+Admin can request writeback of those idle pages at right timing via
+
+	"echo idle > /sys/block/zramX/writeback"
+
+With the command, zram writeback idle pages from memory to the storage.
 
 = memory tracking
 
drivers/block/zram/Kconfig +4 -1
index fcd055457364..1ffc64770643 100644
@@ -15,7 +15,7 @@ config ZRAM
 	  See Documentation/blockdev/zram.txt for more information.
 
 config ZRAM_WRITEBACK
-       bool "Write back incompressible page to backing device"
+       bool "Write back incompressible or idle page to backing device"
        depends on ZRAM
        help
 	 With incompressible page, there is no memory saving to keep it
@@ -23,6 +23,9 @@ config ZRAM_WRITEBACK
 	 For this feature, admin should set up backing device via
 	 /sys/block/zramX/backing_dev.
 
+	 With /sys/block/zramX/{idle,writeback}, application could ask
+	 idle page's writeback to the backing device to save in memory.
+
 	 See Documentation/blockdev/zram.txt for more information.
 
 config ZRAM_MEMORY_TRACKING
drivers/block/zram/zram_drv.c +171 -74

316 lines not on this page · raw message

drivers/block/zram/zram_drv.h +1 -0
index 214fa4bb46b9..07695fe70e17 100644
@@ -47,6 +47,7 @@ enum zram_pageflags {
 	ZRAM_LOCK = ZRAM_FLAG_SHIFT,
 	ZRAM_SAME,	/* Page consists the same element */
 	ZRAM_WB,	/* page is stored on backing_device */
+	ZRAM_UNDER_WB,	/* page is under writeback */
 	ZRAM_HUGE,	/* Incompressible page */
 	ZRAM_IDLE,	/* not accessed page since last idle marking */
 
Signature · 1 line
2.20.0.rc0.387.gc7a69e6b6c-goog
#8 lore raw

Re: [PATCH v2 5/7] zram: support idle/huge page writeback

drivers/block/zram/zram_drv.c static int read_from_bdev_async(struct zram *zram, struct bio_vec *bvec, · line 595

Quoted 3 lines · Minchan Kim
drivers/block/zram/zram_drv.c +3 -0
+	strlcpy(mode_buf, buf, sizeof(mode_buf));
+	/* ignore trailing newline */
+	sz = strlen(mode_buf);

One possible idea would be to use strscpy() instead and directly assign the return value to sz, avoiding an extra strlen() call (though you would have to check if sz == -E2BIG and do sz = sizeof(mode_buf) - 1 in that case).

drivers/block/zram/zram_drv.c static int read_from_bdev_async(struct zram *zram, struct bio_vec *bvec, · line 602

Quoted 4 lines
drivers/block/zram/zram_drv.c +4 -0
+	if (!strcmp(mode_buf, "idle"))
+		mode = IDLE_WRITEBACK;
+	if (!strcmp(mode_buf, "huge"))
+		mode = HUGE_WRITEBACK;

Maybe using else if (!strcmp(mode_buf, "huge")) would be slightly better here, avoiding a second strcmp() if mode_buf has already matched "idle".

drivers/block/zram/zram_drv.c static int read_from_bdev_async(struct zram *zram, struct bio_vec *bvec, · line 652

Quoted 5 lines
drivers/block/zram/zram_drv.c +5 -0
+		if ((mode & IDLE_WRITEBACK &&
+			  !zram_test_flag(zram, index, ZRAM_IDLE)) &&
+		    (mode & HUGE_WRITEBACK &&
+			  !zram_test_flag(zram, index, ZRAM_HUGE)))
+			goto next;

Wouldn't writing this as mode & (IDLE_WRITEBACK | HUGE_WRITEBACK) be a bit easier to read as well as slightly more compact?

drivers/block/zram/zram_drv.c static int read_from_bdev_async(struct zram *zram, struct bio_vec *bvec, · line 723

Quoted 5 lines
drivers/block/zram/zram_drv.c +5 -0
+	ret = len;
+	 __free_page(page);
+release_init_lock:
+	up_read(&zram->init_lock);
+	return ret;

Hm, I noticed that this function either returns an error or just the passed in len on success, and I'm left wondering if there might be other useful information which could be passed back to the caller instead. I can't immediately think of any such information, though, so it's possible I'm just daydreaming :)

Signature · 2 lines
Cheers,
Joey Pabalinas
#9 lore raw

Re: [PATCH v2 5/7] zram: support idle/huge page writeback

Quoted 8 lines · Joey Pabalinas

drivers/block/zram/zram_drv.c static int read_from_bdev_async(struct zram *zram, struct bio_vec *bvec, · line 652

Quoted 5 lines
drivers/block/zram/zram_drv.c +5 -0
+		if ((mode & IDLE_WRITEBACK &&
+			  !zram_test_flag(zram, index, ZRAM_IDLE)) &&
+		    (mode & HUGE_WRITEBACK &&
+			  !zram_test_flag(zram, index, ZRAM_HUGE)))
+			goto next;

Wouldn't writing this as mode & (IDLE_WRITEBACK | HUGE_WRITEBACK) be a bit easier to read as well as slightly more compact?

Scratch this comment, it just dawned on me that this is not an equivalent expression, heh.

Signature · 2 lines
Cheers,
Joey Pabalinas
author maintainer
#10 lore raw

Re: [PATCH v2 5/7] zram: support idle/huge page writeback

In reply to Joey Pabalinas
Quoted 9 lines · Joey Pabalinas

drivers/block/zram/zram_drv.c static int read_from_bdev_async(struct zram *zram, struct bio_vec *bvec, · line 595

Quoted 3 lines · Minchan Kim
drivers/block/zram/zram_drv.c +3 -0
+	strlcpy(mode_buf, buf, sizeof(mode_buf));
+	/* ignore trailing newline */
+	sz = strlen(mode_buf);

One possible idea would be to use strscpy() instead and directly assign the return value to sz, avoiding an extra strlen() call (though you would have to check if sz == -E2BIG and do sz = sizeof(mode_buf) - 1 in that case).

Thanks for the suggstion.
If I limit destination buffer smaller, I couldn't meet -E2BIG?

Quoted 9 lines

drivers/block/zram/zram_drv.c static int read_from_bdev_async(struct zram *zram, struct bio_vec *bvec, · line 602

Quoted 5 lines
drivers/block/zram/zram_drv.c +4 -0
+	if (!strcmp(mode_buf, "idle"))
+		mode = IDLE_WRITEBACK;
+	if (!strcmp(mode_buf, "huge"))
+		mode = HUGE_WRITEBACK;

Maybe using else if (!strcmp(mode_buf, "huge")) would be slightly better here, avoiding a second strcmp() if mode_buf has already matched "idle".

I considered "huge|idle" as an option. Anyway, in that case, mode should "mode |= ". At this moment, yes, lets use "else if" since I don't have strong opinion to support "idle|huge".

Quoted 10 lines

drivers/block/zram/zram_drv.c static int read_from_bdev_async(struct zram *zram, struct bio_vec *bvec, · line 652

Quoted 6 lines
drivers/block/zram/zram_drv.c +5 -0
+		if ((mode & IDLE_WRITEBACK &&
+			  !zram_test_flag(zram, index, ZRAM_IDLE)) &&
+		    (mode & HUGE_WRITEBACK &&
+			  !zram_test_flag(zram, index, ZRAM_HUGE)))
+			goto next;

Wouldn't writing this as mode & (IDLE_WRITEBACK | HUGE_WRITEBACK) be a bit easier to read as well as slightly more compact?

Quoted 11 lines

drivers/block/zram/zram_drv.c static int read_from_bdev_async(struct zram *zram, struct bio_vec *bvec, · line 723

Quoted 5 lines
drivers/block/zram/zram_drv.c +5 -0
+	ret = len;
+	 __free_page(page);
+release_init_lock:
+	up_read(&zram->init_lock);
+	return ret;

Hm, I noticed that this function either returns an error or just the passed in len on success, and I'm left wondering if there might be other useful information which could be passed back to the caller instead. I can't immediately think of any such information, though, so it's possible I'm just daydreaming :)

It is write syscall semantic of sysfs so not sure it's doable to pass other value to user.

Quoted 4 lines
Signature · 3 lines
-- 
Cheers,
Joey Pabalinas
Reviewed-by
#11 lore raw

Re: [PATCH v2 5/7] zram: support idle/huge page writeback

Quoted 11 lines · Minchan Kim
Quoted 9 lines · Joey Pabalinas

drivers/block/zram/zram_drv.c static int read_from_bdev_async(struct zram *zram, struct bio_vec *bvec, · line 595

Quoted 3 lines · Minchan Kim
drivers/block/zram/zram_drv.c +3 -0
+	strlcpy(mode_buf, buf, sizeof(mode_buf));
+	/* ignore trailing newline */
+	sz = strlen(mode_buf);

One possible idea would be to use strscpy() instead and directly assign the return value to sz, avoiding an extra strlen() call (though you would have to check if sz == -E2BIG and do sz = sizeof(mode_buf) - 1 in that case).

Quoted 2 lines

Thanks for the suggstion.
If I limit destination buffer smaller, I couldn't meet -E2BIG?

-E2BIG return from strscpy() just means the string was longer than would fit in the length passed as the third argument. This means only sizeof(mode_buf) - 1 bytes were copied into the dest, with the last byte being the \0 terminator.

You can find the function source in lib/string.c.

Quoted 12 lines
Quoted 11 lines

drivers/block/zram/zram_drv.c static int read_from_bdev_async(struct zram *zram, struct bio_vec *bvec, · line 723

Quoted 5 lines
drivers/block/zram/zram_drv.c +5 -0
+	ret = len;
+	 __free_page(page);
+release_init_lock:
+	up_read(&zram->init_lock);
+	return ret;

Hm, I noticed that this function either returns an error or just the passed in len on success, and I'm left wondering if there might be other useful information which could be passed back to the caller instead. I can't immediately think of any such information, though, so it's possible I'm just daydreaming :)

Quoted 2 lines

It is write syscall semantic of sysfs so not sure it's doable to pass other value to user.

Well, with the write system call you can have partial writes, in which case it would return the (short) number of bytes written. But in this function, even if there was some sort of partial write possible, this function still only every returns len or error.

Neither of these are that important though, so Ack from me with or without these two suggestions.

Signature · 2 lines
Cheers,
Joey Pabalinas
author maintainer
#12 lore raw

PATCH v2 6/7 zram: add bd_stat statistics

In reply to Minchan Kim

bd_stat represents things happened in backing device. Currently, it supports bd_counts, bd_reads and bd_writes which are helpful to understand wearout of flash and memory saving.

---
 Documentation/ABI/testing/sysfs-block-zram |  8 ++++++
 Documentation/blockdev/zram.txt            | 11 ++++++++
 drivers/block/zram/zram_drv.c              | 30 ++++++++++++++++++++++
 drivers/block/zram/zram_drv.h              |  5 ++++
 4 files changed, 54 insertions(+)
Documentation/ABI/testing/sysfs-block-zram +8 -0
index d1f80b077885..65fc33b2f53b 100644
@@ -113,3 +113,11 @@ Contact:	Minchan Kim <[email protected]>
 Description:
 		The writeback file is write-only and trigger idle and/or
 		huge page writeback to backing device.
+
+What:		/sys/block/zram<id>/bd_stat
+Date:		November 2018
+Contact:	Minchan Kim <[email protected]>
+Description:
+		The bd_stat file is read-only and represents backing device's
+		statistics (bd_count, bd_reads, bd_writes) in a format
+		similar to block layer statistics file format.
Documentation/blockdev/zram.txt +11 -0
index 806cdaabac83..550bca77d322 100644
@@ -221,6 +221,17 @@ The stat file represents device's mm statistics. It consists of a single
  pages_compacted  the number of pages freed during compaction
  huge_pages	  the number of incompressible pages
 
+File /sys/block/zram<id>/bd_stat
+
+The stat file represents device's backing device statistics. It consists of
+a single line of text and contains the following stats separated by whitespace:
+ bd_count	size of data written in backing device.
+		Unit: pages
+ bd_reads	the number of reads from backing device
+		Unit: pages
+ bd_writes	the number of writes to backing device
+		Unit: pages
+
 9) Deactivate:
 	swapoff /dev/zram0
 	umount /dev/zram1
drivers/block/zram/zram_drv.c +30 -0
index 3d069b2328f8..cceaa10301e8 100644
@@ -518,6 +518,8 @@ static unsigned long alloc_block_bdev(struct zram *zram)
 	ret = blk_idx;
 out:
 	spin_unlock_irq(&zram->bitmap_lock);
+	if (ret != 0)
+		atomic64_inc(&zram->stats.bd_count);
 
 	return ret;
 }
@@ -531,6 +533,7 @@ static void free_block_bdev(struct zram *zram, unsigned long blk_idx)
 	was_set = test_and_clear_bit(blk_idx, zram->bitmap);
 	spin_unlock_irqrestore(&zram->bitmap_lock, flags);
 	WARN_ON_ONCE(!was_set);
+	atomic64_dec(&zram->stats.bd_count);
 }
 
 static void zram_page_end_io(struct bio *bio)
@@ -686,6 +689,7 @@ static ssize_t writeback_store(struct device *dev,
 			continue;
 		}
 
+		atomic64_inc(&zram->stats.bd_writes);
 		/*
 		 * We released zram_slot_lock so need to check if the slot was
 		 * changed. If there is freeing for the slot, we can catch it
@@ -775,6 +779,7 @@ static int read_from_bdev_sync(struct zram *zram, struct bio_vec *bvec,
 static int read_from_bdev(struct zram *zram, struct bio_vec *bvec,
 			unsigned long entry, struct bio *parent, bool sync)
 {
+	atomic64_inc(&zram->stats.bd_reads);
 	if (sync)
 		return read_from_bdev_sync(zram, bvec, entry, parent);
 	else
@@ -1031,6 +1036,25 @@ static ssize_t mm_stat_show(struct device *dev,
 	return ret;
 }
 
+#ifdef CONFIG_ZRAM_WRITEBACK
+static ssize_t bd_stat_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct zram *zram = dev_to_zram(dev);
+	ssize_t ret;
+
+	down_read(&zram->init_lock);
+	ret = scnprintf(buf, PAGE_SIZE,
+			"%8llu %8llu %8llu\n",
+			(u64)atomic64_read(&zram->stats.bd_count),
+			(u64)atomic64_read(&zram->stats.bd_reads),
+			(u64)atomic64_read(&zram->stats.bd_writes));
+	up_read(&zram->init_lock);
+
+	return ret;
+}
+#endif
+
 static ssize_t debug_stat_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
@@ -1051,6 +1075,9 @@ static ssize_t debug_stat_show(struct device *dev,
 
 static DEVICE_ATTR_RO(io_stat);
 static DEVICE_ATTR_RO(mm_stat);
+#ifdef CONFIG_ZRAM_WRITEBACK
+static DEVICE_ATTR_RO(bd_stat);
+#endif
 static DEVICE_ATTR_RO(debug_stat);
 
 static void zram_meta_free(struct zram *zram, u64 disksize)
@@ -1777,6 +1804,9 @@ static struct attribute *zram_disk_attrs[] = {
 #endif
 	&dev_attr_io_stat.attr,
 	&dev_attr_mm_stat.attr,
+#ifdef CONFIG_ZRAM_WRITEBACK
+	&dev_attr_bd_stat.attr,
+#endif
 	&dev_attr_debug_stat.attr,
 	NULL,
 };
drivers/block/zram/zram_drv.h +5 -0
index 07695fe70e17..7cbb134fc0c9 100644
@@ -82,6 +82,11 @@ struct zram_stats {
 	atomic_long_t max_used_pages;	/* no. of maximum pages stored */
 	atomic64_t writestall;		/* no. of write slow paths */
 	atomic64_t miss_free;		/* no. of missed free */
+#ifdef	CONFIG_ZRAM_WRITEBACK
+	atomic64_t bd_count;		/* no. of pages in backing device */
+	atomic64_t bd_reads;		/* no. of reads from backing device */
+	atomic64_t bd_writes;		/* no. of writes from backing device */
+#endif
 };
 
 struct zram {
Signature · 1 line
2.20.0.rc0.387.gc7a69e6b6c-goog
#13 lore raw

Re: [PATCH v2 6/7] zram: add bd_stat statistics

Documentation/blockdev/zram.txt The stat file represents device's mm statistics. It consists of a single · line 233

Quoted 10 lines · On Mon, 26 Nov 2018 17:28:12 +0900 Minchan Kim <[email protected]> wrote:
Documentation/blockdev/zram.txt +10 -0
+File /sys/block/zram<id>/bd_stat
+
+The stat file represents device's backing device statistics. It consists of
+a single line of text and contains the following stats separated by whitespace:
+ bd_count	size of data written in backing device.
+		Unit: pages
+ bd_reads	the number of reads from backing device
+		Unit: pages
+ bd_writes	the number of writes to backing device
+		Unit: pages

Using `pages' is a bad choice. And I assume this means that writeback_limit is in pages as well, which is worse.

Page sizes are not constant! We want userspace which was developed on 4k pagesize to work the same on 64k pagesize.

Arguably, we could require that well-written userspace remember to use getpagesize(). However we have traditionally tried to avoid that by performing the pagesize normalization within the kernel.

author maintainer
#14 lore raw

Re: [PATCH v2 6/7] zram: add bd_stat statistics

Quoted 16 lines · Andrew Morton

Documentation/blockdev/zram.txt The stat file represents device's mm statistics. It consists of a single · line 233

Quoted 10 lines · On Mon, 26 Nov 2018 17:28:12 +0900 Minchan Kim <[email protected]> wrote:
Documentation/blockdev/zram.txt +10 -0
+File /sys/block/zram<id>/bd_stat
+
+The stat file represents device's backing device statistics. It consists of
+a single line of text and contains the following stats separated by whitespace:
+ bd_count	size of data written in backing device.
+		Unit: pages
+ bd_reads	the number of reads from backing device
+		Unit: pages
+ bd_writes	the number of writes to backing device
+		Unit: pages

Using `pages' is a bad choice. And I assume this means that writeback_limit is in pages as well, which is worse.

Quoted 6 lines

Page sizes are not constant! We want userspace which was developed on 4k pagesize to work the same on 64k pagesize.

Arguably, we could require that well-written userspace remember to use getpagesize(). However we have traditionally tried to avoid that by performing the pagesize normalization within the kernel.

zram works based on page so I used that term but I agree it's rather vague. If there is no objection, I will use (Unit: 4K) instead of (Unit: pages).

#15 lore raw

Re: [PATCH v2 6/7] zram: add bd_stat statistics

Quoted 20 lines · On Tue, 27 Nov 2018 11:07:54 +0900 Minchan Kim <[email protected]> wrote:
Quoted 19 lines · Andrew Morton

Documentation/blockdev/zram.txt The stat file represents device's mm statistics. It consists of a single · line 233

Quoted 10 lines · On Mon, 26 Nov 2018 17:28:12 +0900 Minchan Kim <[email protected]> wrote:
Documentation/blockdev/zram.txt +10 -0
+File /sys/block/zram<id>/bd_stat
+
+The stat file represents device's backing device statistics. It consists of
+a single line of text and contains the following stats separated by whitespace:
+ bd_count	size of data written in backing device.
+		Unit: pages
+ bd_reads	the number of reads from backing device
+		Unit: pages
+ bd_writes	the number of writes to backing device
+		Unit: pages

Using `pages' is a bad choice. And I assume this means that writeback_limit is in pages as well, which is worse.

Page sizes are not constant! We want userspace which was developed on 4k pagesize to work the same on 64k pagesize.

Quoted 7 lines
Quoted 3 lines

Arguably, we could require that well-written userspace remember to use getpagesize(). However we have traditionally tried to avoid that by performing the pagesize normalization within the kernel.

zram works based on page so I used that term but I agree it's rather vague. If there is no objection, I will use (Unit: 4K) instead of (Unit: pages).

Is that still true if PAGE_SIZE=64k?

author maintainer
#16 lore raw

Re: [PATCH v2 6/7] zram: add bd_stat statistics

Quoted 26 lines · Andrew Morton
Quoted 24 lines · On Tue, 27 Nov 2018 11:07:54 +0900 Minchan Kim <[email protected]> wrote:
Quoted 22 lines · Andrew Morton

Documentation/blockdev/zram.txt The stat file represents device's mm statistics. It consists of a single · line 233

Quoted 10 lines · On Mon, 26 Nov 2018 17:28:12 +0900 Minchan Kim <[email protected]> wrote:
Documentation/blockdev/zram.txt +10 -0
+File /sys/block/zram<id>/bd_stat
+
+The stat file represents device's backing device statistics. It consists of
+a single line of text and contains the following stats separated by whitespace:
+ bd_count	size of data written in backing device.
+		Unit: pages
+ bd_reads	the number of reads from backing device
+		Unit: pages
+ bd_writes	the number of writes to backing device
+		Unit: pages

Using `pages' is a bad choice. And I assume this means that writeback_limit is in pages as well, which is worse.

Page sizes are not constant! We want userspace which was developed on 4k pagesize to work the same on 64k pagesize.

Arguably, we could require that well-written userspace remember to use getpagesize(). However we have traditionally tried to avoid that by performing the pagesize normalization within the kernel.

Quoted 5 lines
Quoted 3 lines

zram works based on page so I used that term but I agree it's rather vague. If there is no objection, I will use (Unit: 4K) instead of (Unit: pages).

Is that still true if PAGE_SIZE=64k?

Oops, it will fix.

author maintainer
#17 lore raw

PATCH v2 7/7 zram: writeback throttle

In reply to Minchan Kim

On small memory system, there are lots of write IO so if we use flash device as swap, there would be serious flash wearout. To overcome the problem, system developers need to design write limitation strategy to guarantee flash health for entire product life.

This patch creates a new konb "writeback_limit" on zram. With that, if current writeback IO count(/sys/block/zramX/io_stat) excceds the limitation, zram stops further writeback until admin can reset the limit.

---
 Documentation/ABI/testing/sysfs-block-zram |  9 +++++
 Documentation/blockdev/zram.txt            |  2 +
 drivers/block/zram/zram_drv.c              | 47 +++++++++++++++++++++-
 drivers/block/zram/zram_drv.h              |  2 +
 4 files changed, 59 insertions(+), 1 deletion(-)
Documentation/ABI/testing/sysfs-block-zram +9 -0
index 65fc33b2f53b..9d2339a485c8 100644
@@ -121,3 +121,12 @@ Contact:	Minchan Kim <[email protected]>
 		The bd_stat file is read-only and represents backing device's
 		statistics (bd_count, bd_reads, bd_writes) in a format
 		similar to block layer statistics file format.
+
+What:		/sys/block/zram<id>/writeback_limit
+Date:		November 2018
+Contact:	Minchan Kim <[email protected]>
+Description:
+		The writeback_limit file is read-write and specifies the maximum
+		amount of writeback ZRAM can do. The limit could be changed
+		in run time and "0" means disable the limit.
+		No limit is the initial state.
Documentation/blockdev/zram.txt +2 -0
index 550bca77d322..41748d52712d 100644
@@ -164,6 +164,8 @@ reset             WO    trigger device reset
 mem_used_max      WO    reset the `mem_used_max' counter (see later)
 mem_limit         WO    specifies the maximum amount of memory ZRAM can use
                         to store the compressed data
+writeback_limit	  WO	specifies the maximum amount of write IO zram can
+			write out to backing device
 max_comp_streams  RW    the number of possible concurrent compress operations
 comp_algorithm    RW    show and change the compression algorithm
 compact           WO    trigger memory compaction
drivers/block/zram/zram_drv.c +46 -1

89 lines not on this page · raw message

drivers/block/zram/zram_drv.h +2 -0
index 7cbb134fc0c9..024044e82c9b 100644
@@ -86,6 +86,7 @@ struct zram_stats {
 	atomic64_t bd_count;		/* no. of pages in backing device */
 	atomic64_t bd_reads;		/* no. of reads from backing device */
 	atomic64_t bd_writes;		/* no. of writes from backing device */
+	atomic64_t bd_wb_limit;		/* writeback limit of backing device */
 #endif
 };
 
@@ -113,6 +114,7 @@ struct zram {
 	 */
 	bool claim; /* Protected by bdev->bd_mutex */
 	struct file *backing_dev;
+	bool stop_writeback;
 #ifdef CONFIG_ZRAM_WRITEBACK
 	struct block_device *bdev;
 	unsigned int old_block_size;
Signature · 1 line
2.20.0.rc0.387.gc7a69e6b6c-goog
#18 lore raw

Re: [PATCH v2 7/7] zram: writeback throttle

Quoted 29 lines · On Mon, 26 Nov 2018 17:28:13 +0900 Minchan Kim <[email protected]> wrote:

On small memory system, there are lots of write IO so if we use flash device as swap, there would be serious flash wearout. To overcome the problem, system developers need to design write limitation strategy to guarantee flash health for entire product life.

This patch creates a new konb "writeback_limit" on zram. With that, if current writeback IO count(/sys/block/zramX/io_stat) excceds the limitation, zram stops further writeback until admin can reset the limit.

+++ b/Documentation/ABI/testing/sysfs-block-zram

Documentation/ABI/testing/sysfs-block-zram +9 -0
@@ -121,3 +121,12 @@ Contact:	Minchan Kim <[email protected]>
 		The bd_stat file is read-only and represents backing device's
 		statistics (bd_count, bd_reads, bd_writes) in a format
 		similar to block layer statistics file format.
+
+What:		/sys/block/zram<id>/writeback_limit
+Date:		November 2018
+Contact:	Minchan Kim <[email protected]>
+Description:
+		The writeback_limit file is read-write and specifies the maximum
+		amount of writeback ZRAM can do. The limit could be changed
+		in run time and "0" means disable the limit.
+		No limit is the initial state.
Documentation/blockdev/zram.txt +0 -0
index 550bca77d322..41748d52712d 100644

Documentation/blockdev/zram.txt reset WO trigger device reset · line 168

Quoted 5 lines
Documentation/blockdev/zram.txt +2 -0
@@ -164,6 +164,8 @@ reset             WO    trigger device reset
 mem_used_max      WO    reset the `mem_used_max' counter (see later)
 mem_limit         WO    specifies the maximum amount of memory ZRAM can use
                         to store the compressed data
+writeback_limit	  WO	specifies the maximum amount of write IO zram can
+			write out to backing device

Neither the changelog nor the Documentation specify the units of writeback_limit. Bytes? Pages? Blocks?

This gets so confusing that in many /proc/sys/vm files we actually put the units into the filenames.

author maintainer
#19 lore raw

Re: [PATCH v2 7/7] zram: writeback throttle

Quoted 40 lines · Andrew Morton
Quoted 29 lines · On Mon, 26 Nov 2018 17:28:13 +0900 Minchan Kim <[email protected]> wrote:

On small memory system, there are lots of write IO so if we use flash device as swap, there would be serious flash wearout. To overcome the problem, system developers need to design write limitation strategy to guarantee flash health for entire product life.

This patch creates a new konb "writeback_limit" on zram. With that, if current writeback IO count(/sys/block/zramX/io_stat) excceds the limitation, zram stops further writeback until admin can reset the limit.

+++ b/Documentation/ABI/testing/sysfs-block-zram

Documentation/ABI/testing/sysfs-block-zram +9 -0
@@ -121,3 +121,12 @@ Contact:	Minchan Kim <[email protected]>
 		The bd_stat file is read-only and represents backing device's
 		statistics (bd_count, bd_reads, bd_writes) in a format
 		similar to block layer statistics file format.
+
+What:		/sys/block/zram<id>/writeback_limit
+Date:		November 2018
+Contact:	Minchan Kim <[email protected]>
+Description:
+		The writeback_limit file is read-write and specifies the maximum
+		amount of writeback ZRAM can do. The limit could be changed
+		in run time and "0" means disable the limit.
+		No limit is the initial state.
Documentation/blockdev/zram.txt +0 -0
index 550bca77d322..41748d52712d 100644

Documentation/blockdev/zram.txt reset WO trigger device reset · line 168

Quoted 5 lines
Documentation/blockdev/zram.txt +2 -0
@@ -164,6 +164,8 @@ reset             WO    trigger device reset
 mem_used_max      WO    reset the `mem_used_max' counter (see later)
 mem_limit         WO    specifies the maximum amount of memory ZRAM can use
                         to store the compressed data
+writeback_limit	  WO	specifies the maximum amount of write IO zram can
+			write out to backing device

Neither the changelog nor the Documentation specify the units of writeback_limit. Bytes? Pages? Blocks?

Quoted 3 lines

This gets so confusing that in many /proc/sys/vm files we actually put the units into the filenames.

I will use unit as 4K.

Thanks.