Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754021AbcKYIo7 (ORCPT ); Fri, 25 Nov 2016 03:44:59 -0500 Received: from outboundhk.mxmail.xiaomi.com ([207.226.244.122]:47757 "EHLO xiaomi.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1754093AbcKYImP (ORCPT ); Fri, 25 Nov 2016 03:42:15 -0500 X-Greylist: delayed 952 seconds by postgrey-1.27 at vger.kernel.org; Fri, 25 Nov 2016 03:42:04 EST From: Hui Zhu To: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , CC: Subject: [RFC 1/2] SWAP: add interface to let disk close swap cache Date: Fri, 25 Nov 2016 16:25:12 +0800 Message-ID: <1480062313-7361-2-git-send-email-zhuhui@xiaomi.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1480062313-7361-1-git-send-email-zhuhui@xiaomi.com> References: <1480062313-7361-1-git-send-email-zhuhui@xiaomi.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.237.10.122] X-ClientProxiedBy: CNCAS3.mioffice.cn (10.237.8.133) To cnbox6.mioffice.cn (10.237.8.146) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5212 Lines: 194 This patch add a interface to gendisk that SWAP device can use it to control the swap cache rule. Signed-off-by: Hui Zhu --- 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