From 824502c8d18b2fb342c02d28890959a99e35d0a5 Mon Sep 17 00:00:00 2001 From: huangzq2 Date: Thu, 11 Mar 2021 09:49:55 +0800 Subject: [PATCH] mm: zram: fix swapcached issue on kernel 5.4 Afer Zram backing dev setuped, zram will be treated as a ASYNC IO swap device, no longer SYNC IO device, because WB pages do have IO operation on swap in, so the optimization on skiping swapcache for fast swap device will no longer be applyed on such case. Now we refactor this optimization, skip the swapcache by checking SYNC IO state on each swap page via ioctl. Reuse ioctl because we should not break the GKI. Change-Id: Ia1dc351eafc7c0b62126a3864a6da9136c2bfe6d Signed-off-by: huangzq2 Reviewed-on: https://gerrit.mot.com/1898090 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Yonghui Jia Reviewed-by: Zhizhong Ge Reviewed-by: Huosheng Liao Submit-Approved: Jira Key --- drivers/block/zram/zram_drv.c | 25 +++++++++++++++++++++++++ include/linux/swap.h | 1 + mm/memory.c | 17 +++++++++++++---- mm/page_io.c | 16 ++++++++++++++++ 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index cd242fd9db18..60650ecf9166 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -1630,6 +1631,27 @@ static void zram_slot_free_notify(struct block_device *bdev, zram_slot_unlock(zram, index); } +/* Moto huangzq2: check sync_io state on swap entry, + * return 0 on wb page, else return 1. + */ +#ifdef CONFIG_ZRAM_WRITEBACK +static int zram_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long index) +{ + struct zram *zram; + int has_sync_io = 1; + + if (cmd != SWP_SYNCHRONOUS_IO) return -EINVAL; + + zram = bdev->bd_disk->private_data; + zram_slot_lock(zram, index); + has_sync_io = zram_test_flag(zram, index, ZRAM_WB) ? 0 : 1; + zram_slot_unlock(zram, index); + + return has_sync_io; +} +#endif + static int zram_rw_page(struct block_device *bdev, sector_t sector, struct page *page, unsigned int op) { @@ -1822,6 +1844,9 @@ static int zram_open(struct block_device *bdev, fmode_t mode) static const struct block_device_operations zram_devops = { .open = zram_open, .swap_slot_free_notify = zram_slot_free_notify, +#ifdef CONFIG_ZRAM_WRITEBACK + .ioctl = zram_ioctl, +#endif .rw_page = zram_rw_page, .owner = THIS_MODULE }; diff --git a/include/linux/swap.h b/include/linux/swap.h index b407d3963649..bb50a6d0eee4 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -397,6 +397,7 @@ extern void end_swap_bio_write(struct bio *bio); extern int __swap_writepage(struct page *page, struct writeback_control *wbc, bio_end_io_t end_write_func); extern int swap_set_page_dirty(struct page *page); +extern bool swap_slot_has_sync_io(swp_entry_t entry); int add_swap_extent(struct swap_info_struct *sis, unsigned long start_page, unsigned long nr_pages, sector_t start_block); diff --git a/mm/memory.c b/mm/memory.c index 47c12f886c0d..609e32cfbb0e 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3089,9 +3089,18 @@ vm_fault_t do_swap_page(struct vm_fault *vmf) if (!page) { struct swap_info_struct *si = swp_swap_info(entry); + bool skip_swapcache = false; - if (si->flags & SWP_SYNCHRONOUS_IO && - __swap_count(entry) == 1) { + /* Moto huangzq2: check sync_io on each page if we enabled Zram wb. + * Zram writeback will remove SWP_SYNCHRONOUS_IO flag as it has disk + * IO operation on writeback page during swap in. + */ + if (si->flags & SWP_SYNCHRONOUS_IO && __swap_count(entry) == 1) + skip_swapcache = true; + else if (__swap_count(entry) == 1 && swap_slot_has_sync_io(entry)) + skip_swapcache = true; + + if (skip_swapcache) { /* skip swapcache */ page = alloc_page_vma(GFP_HIGHUSER_MOVABLE | __GFP_CMA | __GFP_OFFLINABLE, vma, @@ -3115,8 +3124,8 @@ vm_fault_t do_swap_page(struct vm_fault *vmf) ret = VM_FAULT_RETRY; goto out; } else { - page = swapin_readahead(entry, GFP_HIGHUSER_MOVABLE, - vmf); + page = swapin_readahead(entry, GFP_HIGHUSER_MOVABLE | __GFP_CMA + | __GFP_OFFLINABLE, vmf); swapcache = page; } diff --git a/mm/page_io.c b/mm/page_io.c index bc370c8e1667..e91f008af794 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -71,6 +71,22 @@ void end_swap_bio_write(struct bio *bio) bio_put(bio); } +/* Moto huangzq2: check sync_io state on swap entry */ +bool swap_slot_has_sync_io(swp_entry_t entry) +{ + struct swap_info_struct *sis; + struct gendisk *disk; + + sis = swp_swap_info(entry); + disk = sis->bdev->bd_disk; + if (disk->fops->ioctl) { + return disk->fops->ioctl(sis->bdev, 0, + SWP_SYNCHRONOUS_IO, swp_offset(entry)) == 1; + } + + return false; +} + static void swap_slot_free_notify(struct page *page) { struct swap_info_struct *sis;