[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1480062313-7361-2-git-send-email-zhuhui@xiaomi.com>
Date: Fri, 25 Nov 2016 16:25:12 +0800
From: Hui Zhu <zhuhui@...omi.com>
To: <minchan@...nel.org>, <ngupta@...are.org>,
<sergey.senozhatsky.work@...il.com>, <dan.j.williams@...el.com>,
<jthumshirn@...e.de>, <akpm@...ux-foundation.org>,
<zhuhui@...omi.com>, <re.emese@...il.com>,
<andriy.shevchenko@...ux.intel.com>, <vishal.l.verma@...el.com>,
<hannes@...xchg.org>, <mhocko@...e.com>,
<mgorman@...hsingularity.net>, <vbabka@...e.cz>,
<vdavydov.dev@...il.com>, <kirill.shutemov@...ux.intel.com>,
<ying.huang@...el.com>, <yang.shi@...aro.org>,
<dave.hansen@...ux.intel.com>, <willy@...ux.intel.com>,
<vkuznets@...hat.com>, <vitalywool@...il.com>,
<jmarchan@...hat.com>, <lstoakes@...il.com>, <geliangtang@....com>,
<viro@...iv.linux.org.uk>, <hughd@...gle.com>, <riel@...hat.com>,
<linux-kernel@...r.kernel.org>, <linux-mm@...ck.org>
CC: <teawater@...il.com>
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 <zhuhui@...omi.com>
---
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
Powered by blists - more mailing lists