2016-11-25 08:43:33

by Hui Zhu

[permalink] [raw]
Subject: [RFC 0/2] Add interface let ZRAM close swap cache

SWAP will keep before swap cache before swap space get full. It will
make swap space cannot be freed. It is harmful to the system that use
ZRAM because its space use memory too.

This two patches will add a sysfs switch to ZRAM that open or close swap
cache without check the swap space.
I got good result in real environment with them. And following part is
the record with vm-scalability case-swap-w-rand and case-swap-w-seq in
a Intel(R) Core(TM)2 Duo CPU, 2G memory and 1G ZRAM swap machine:
4.9.0-rc5 without the patches:
case-swap-w-rand
1129809600 bytes / 2149155959 usecs = 513 KB/s
1129809600 bytes / 2150796138 usecs = 512 KB/s
case-swap-w-rand
1124808768 bytes / 1973130450 usecs = 556 KB/s
1124808768 bytes / 1975142661 usecs = 556 KB/s
case-swap-w-rand
1130677056 bytes / 2154714972 usecs = 512 KB/s
1130677056 bytes / 2157542507 usecs = 511 KB/s
case-swap-w-seq
1117922688 bytes / 6596049 usecs = 165511 KB/s
1117922688 bytes / 6715711 usecs = 162562 KB/s
case-swap-w-seq
1115869824 bytes / 6909262 usecs = 157718 KB/s
1115869824 bytes / 7099283 usecs = 153496 KB/s
case-swap-w-seq
1116472896 bytes / 6451638 usecs = 168996 KB/s
1116472896 bytes / 6647963 usecs = 164005 KB/s
4.9.0-rc5 with the patches:
case-swap-w-rand
1127272896 bytes / 2060906184 usecs = 534 KB/s
1127272896 bytes / 2063671365 usecs = 533 KB/s
case-swap-w-rand
1131846912 bytes / 2097038264 usecs = 527 KB/s
1131846912 bytes / 2100148465 usecs = 526 KB/s
case-swap-w-rand
1129139136 bytes / 2038769367 usecs = 540 KB/s
1129139136 bytes / 2041411431 usecs = 540 KB/s
case-swap-w-seq
1129622976 bytes / 5910625 usecs = 186638 KB/s
1129622976 bytes / 6313311 usecs = 174733 KB/s
case-swap-w-seq
1130053248 bytes / 6771182 usecs = 162980 KB/s
1130053248 bytes / 6666061 usecs = 165550 KB/s
case-swap-w-seq
1126484928 bytes / 6555923 usecs = 167799 KB/s
1126484928 bytes / 6642291 usecs = 165617 KB/s

Hui Zhu (2):
SWAP: add interface to let disk close swap cache
ZRAM: add sysfs switch swap_cache_not_keep


2016-11-25 08:44:59

by Hui Zhu

[permalink] [raw]
Subject: [RFC 1/2] SWAP: add interface to let disk close swap cache

This patch add a interface to gendisk that SWAP device can use it to
control the swap cache rule.

Signed-off-by: Hui Zhu <[email protected]>
---
include/linux/genhd.h | 3 +++
include/linux/swap.h | 8 ++++++
mm/Kconfig | 10 +++++++
mm/memory.c | 2 +-
mm/swapfile.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++-
mm/vmscan.c | 2 +-
6 files changed, 96 insertions(+), 3 deletions(-)

diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index e0341af..6baec46 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -215,6 +215,9 @@ struct gendisk {
#endif /* CONFIG_BLK_DEV_INTEGRITY */
int node_id;
struct badblocks *bb;
+#ifdef CONFIG_SWAP_CACHE_RULE
+ bool swap_cache_not_keep;
+#endif
};

static inline struct gendisk *part_to_disk(struct hd_struct *part)
diff --git a/include/linux/swap.h b/include/linux/swap.h
index a56523c..6fa11ca 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -582,5 +582,13 @@ static inline bool mem_cgroup_swap_full(struct page *page)
}
#endif

+#ifdef CONFIG_SWAP_CACHE_RULE
+extern bool swap_not_keep_cache(struct page *page);
+extern void swap_cache_rule_update(void);
+#else
+#define swap_not_keep_cache(p) mem_cgroup_swap_full(p)
+#define swap_cache_rule_update()
+#endif
+
#endif /* __KERNEL__*/
#endif /* _LINUX_SWAP_H */
diff --git a/mm/Kconfig b/mm/Kconfig
index 86e3e0e..6623e87 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -711,3 +711,13 @@ config ARCH_USES_HIGH_VMA_FLAGS
bool
config ARCH_HAS_PKEYS
bool
+
+config SWAP_CACHE_RULE
+ bool "Swap cache rule support"
+ depends on SWAP
+ default n
+ help
+ add a interface to gendisk that SWAP device can use it to
+ control the swap cache rule.
+
+ If unsure, say "n".
diff --git a/mm/memory.c b/mm/memory.c
index e18c57b..099cb5b 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2654,7 +2654,7 @@ int do_swap_page(struct fault_env *fe, pte_t orig_pte)
}

swap_free(entry);
- if (mem_cgroup_swap_full(page) ||
+ if (swap_not_keep_cache(page) ||
(vma->vm_flags & VM_LOCKED) || PageMlocked(page))
try_to_free_swap(page);
unlock_page(page);
diff --git a/mm/swapfile.c b/mm/swapfile.c
index f304389..9837261 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1019,7 +1019,7 @@ int free_swap_and_cache(swp_entry_t entry)
* Also recheck PageSwapCache now page is locked (above).
*/
if (PageSwapCache(page) && !PageWriteback(page) &&
- (!page_mapped(page) || mem_cgroup_swap_full(page))) {
+ (!page_mapped(page) || swap_not_keep_cache(page))) {
delete_from_swap_cache(page);
SetPageDirty(page);
}
@@ -1992,6 +1992,8 @@ static void reinsert_swap_info(struct swap_info_struct *p)
filp_close(victim, NULL);
out:
putname(pathname);
+ if (!err)
+ swap_cache_rule_update();
return err;
}

@@ -2576,6 +2578,8 @@ static bool swap_discardable(struct swap_info_struct *si)
putname(name);
if (inode && S_ISREG(inode->i_mode))
inode_unlock(inode);
+ if (!error)
+ swap_cache_rule_update();
return error;
}

@@ -2954,3 +2958,71 @@ static void free_swap_count_continuations(struct swap_info_struct *si)
}
}
}
+
+#ifdef CONFIG_SWAP_CACHE_RULE
+enum swap_cache_rule_type {
+ SWAP_CACHE_UNKNOWN = 0,
+ SWAP_CACHE_SPECIAL_RULE,
+ SWAP_CACHE_NOT_KEEP,
+ SWAP_CACHE_NEED_CHECK,
+};
+
+static enum swap_cache_rule_type swap_cache_rule __read_mostly;
+
+bool swap_not_keep_cache(struct page *page)
+{
+ enum swap_cache_rule_type rule = READ_ONCE(swap_cache_rule);
+
+ if (rule == SWAP_CACHE_NOT_KEEP)
+ return true;
+
+ if (unlikely(rule == SWAP_CACHE_SPECIAL_RULE)) {
+ struct swap_info_struct *sis;
+
+ BUG_ON(!PageSwapCache(page));
+
+ sis = page_swap_info(page);
+ if (sis->flags & SWP_BLKDEV) {
+ struct gendisk *disk = sis->bdev->bd_disk;
+
+ if (READ_ONCE(disk->swap_cache_not_keep))
+ return true;
+ }
+ }
+
+ return mem_cgroup_swap_full(page);
+}
+
+void swap_cache_rule_update(void)
+{
+ enum swap_cache_rule_type rule = SWAP_CACHE_UNKNOWN;
+ int type;
+
+ spin_lock(&swap_lock);
+ for (type = 0; type < nr_swapfiles; type++) {
+ struct swap_info_struct *sis = swap_info[type];
+ enum swap_cache_rule_type current_rule = SWAP_CACHE_NEED_CHECK;
+
+ if (!(sis->flags & SWP_USED))
+ continue;
+
+ if (sis->flags & SWP_BLKDEV) {
+ struct gendisk *disk = sis->bdev->bd_disk;
+
+ if (READ_ONCE(disk->swap_cache_not_keep))
+ current_rule = SWAP_CACHE_NOT_KEEP;
+ }
+
+ if (rule == SWAP_CACHE_UNKNOWN)
+ rule = current_rule;
+ else if (rule != current_rule) {
+ rule = SWAP_CACHE_SPECIAL_RULE;
+ break;
+ }
+ }
+ spin_unlock(&swap_lock);
+
+ WRITE_ONCE(swap_cache_rule, rule);
+}
+EXPORT_SYMBOL(swap_cache_rule_update);
+#endif
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 76fda22..52c67fe 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1239,7 +1239,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,

activate_locked:
/* Not a candidate for swapping, so reclaim swap space. */
- if (PageSwapCache(page) && mem_cgroup_swap_full(page))
+ if (PageSwapCache(page) && swap_not_keep_cache(page))
try_to_free_swap(page);
VM_BUG_ON_PAGE(PageActive(page), page);
SetPageActive(page);
--
1.9.1

2016-11-25 08:45:39

by Hui Zhu

[permalink] [raw]
Subject: [RFC 2/2] ZRAM: add sysfs switch swap_cache_not_keep

This patch add a sysfs interface swap_cache_not_keep to control the swap
cache rule for a ZRAM disk.
Swap will not keep the swap cache anytime if it set to 1.

Signed-off-by: Hui Zhu <[email protected]>
---
drivers/block/zram/zram_drv.c | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)

diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 04365b1..bda9bbf 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -30,6 +30,8 @@
#include <linux/err.h>
#include <linux/idr.h>
#include <linux/sysfs.h>
+#include <linux/swap.h>
+#include <asm/barrier.h>

#include "zram_drv.h"

@@ -1158,6 +1160,32 @@ static ssize_t reset_store(struct device *dev,
return len;
}

+#ifdef CONFIG_SWAP_CACHE_RULE
+static ssize_t swap_cache_not_keep_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct zram *zram = dev_to_zram(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n",
+ zram->disk->swap_cache_not_keep);
+}
+
+static ssize_t swap_cache_not_keep_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct zram *zram = dev_to_zram(dev);
+ bool rule;
+
+ if (strtobool(buf, &rule) < 0)
+ return -EINVAL;
+ WRITE_ONCE(zram->disk->swap_cache_not_keep, rule);
+
+ swap_cache_rule_update();
+
+ return len;
+}
+#endif
+
static int zram_open(struct block_device *bdev, fmode_t mode)
{
int ret = 0;
@@ -1190,6 +1218,9 @@ static int zram_open(struct block_device *bdev, fmode_t mode)
static DEVICE_ATTR_RW(mem_used_max);
static DEVICE_ATTR_RW(max_comp_streams);
static DEVICE_ATTR_RW(comp_algorithm);
+#ifdef CONFIG_SWAP_CACHE_RULE
+static DEVICE_ATTR_RW(swap_cache_not_keep);
+#endif

static struct attribute *zram_disk_attrs[] = {
&dev_attr_disksize.attr,
@@ -1213,6 +1244,9 @@ static int zram_open(struct block_device *bdev, fmode_t mode)
&dev_attr_io_stat.attr,
&dev_attr_mm_stat.attr,
&dev_attr_debug_stat.attr,
+#ifdef CONFIG_SWAP_CACHE_RULE
+ &dev_attr_swap_cache_not_keep.attr,
+#endif
NULL,
};

--
1.9.1

2016-11-28 14:49:34

by Michal Hocko

[permalink] [raw]
Subject: Re: [RFC 0/2] Add interface let ZRAM close swap cache

On Fri 25-11-16 16:25:11, Hui Zhu wrote:
> SWAP will keep before swap cache before swap space get full. It will
> make swap space cannot be freed. It is harmful to the system that use
> ZRAM because its space use memory too.

I have hard time to follow what you are trying to say here. Could you be
more specific about what is the actual problem?

> This two patches will add a sysfs switch to ZRAM that open or close swap
> cache without check the swap space.

I find this a crude hack to be honest. Please make sure to describe why
the swap cache stays in the way and why this is not problem in other
setups.
--
Michal Hocko
SUSE Labs