From d7e1f4f02153646cd5514cc134fbe9c1e1178869 Mon Sep 17 00:00:00 2001 From: Shreyas K K Date: Wed, 31 May 2023 10:16:20 +0530 Subject: [PATCH] ANDROID: vendor hooks: Add hooks to support bootloader based hibernation Add vendor hooks to disable randomization of swap slot allocation for swap partition used for saving hibernation image. Another level of randomization of swap slots takes place at the firmware level as well in order to address the wear leveling for UFS/MMC devices, so this vendor hook checks if a block device represents the swap partition being used for saving hibernation image, if yes, the swap slot allocation for such partition is serialized at kernel level. There is a performance advantage of reading contiguous pages of hibernation image, it makes the restore logic of hibernation image simpler and faster as there are no seeks involved in the secondary storage to read multiple contiguous pages of the image. Bug: 279879797 Change-Id: I8258b5166d8c6952fe9eb91a5a9826f33b836f00 Signed-off-by: Vivek Kumar Signed-off-by: Shreyas K K --- arch/arm64/kernel/hibernate.c | 6 ++++++ drivers/android/vendor_hooks.c | 4 ++++ include/trace/hooks/bl_hib.h | 28 ++++++++++++++++++++++++++++ kernel/power/swap.c | 2 ++ mm/swapfile.c | 14 ++++++++++++-- 5 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 include/trace/hooks/bl_hib.h diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c index 788597a6b6a2..2ea6bc542101 100644 --- a/arch/arm64/kernel/hibernate.c +++ b/arch/arm64/kernel/hibernate.c @@ -33,6 +33,7 @@ #include #include #include +#include /* * Hibernate core relies on this value being 0 on resume, and marks it @@ -80,6 +81,8 @@ static struct arch_hibernate_hdr { phys_addr_t __hyp_stub_vectors; u64 sleep_cpu_mpidr; + + ANDROID_VENDOR_DATA(1); } resume_hdr; static inline void arch_hdr_invariants(struct arch_hibernate_hdr_invariants *i) @@ -117,6 +120,9 @@ int arch_hibernation_header_save(void *addr, unsigned int max_size) hdr->ttbr1_el1 = __pa_symbol(swapper_pg_dir); hdr->reenter_kernel = _cpu_resume; + trace_android_vh_save_cpu_resume(&hdr->android_vendor_data1, + __pa(cpu_resume)); + /* We can't use __hyp_get_vectors() because kvm may still be loaded */ if (el2_reset_needed()) hdr->__hyp_stub_vectors = __pa_symbol(__hyp_stub_vectors); diff --git a/drivers/android/vendor_hooks.c b/drivers/android/vendor_hooks.c index 1df1f21fb156..481f11a67e29 100644 --- a/drivers/android/vendor_hooks.c +++ b/drivers/android/vendor_hooks.c @@ -65,6 +65,7 @@ #include #include #include +#include /* * Export tracepoints that act as a bare tracehook (ie: have no trace event @@ -293,3 +294,6 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_process_madvise_end); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_smaps_pte_entry); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_show_smap); EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_ctl_dirty_rate); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_check_hibernation_swap); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_save_cpu_resume); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_save_hib_resume_bdev); diff --git a/include/trace/hooks/bl_hib.h b/include/trace/hooks/bl_hib.h new file mode 100644 index 000000000000..f47f3760ffe4 --- /dev/null +++ b/include/trace/hooks/bl_hib.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM bl_hib + +#define TRACE_INCLUDE_PATH trace/hooks + +#if !defined(_TRACE_HOOK_BL_HIB_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_HOOK_BL_HIB_H + +#include + +struct block_device; + +DECLARE_HOOK(android_vh_check_hibernation_swap, + TP_PROTO(struct block_device *resume_block, bool *hib_swap), + TP_ARGS(resume_block, hib_swap)); + +DECLARE_HOOK(android_vh_save_cpu_resume, + TP_PROTO(u64 *addr, u64 phys_addr), + TP_ARGS(addr, phys_addr)); + +DECLARE_HOOK(android_vh_save_hib_resume_bdev, + TP_PROTO(struct block_device *hib_resume_bdev), + TP_ARGS(hib_resume_bdev)); + +#endif /* _TRACE_HOOK_BL_HIB_H */ +/* This part must be outside protection */ +#include diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 0973c628022d..d55b2c949c94 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "power.h" @@ -1524,6 +1525,7 @@ int swsusp_check(void) FMODE_READ | FMODE_EXCL, &holder); if (!IS_ERR(hib_resume_bdev)) { set_blocksize(hib_resume_bdev, PAGE_SIZE); + trace_android_vh_save_hib_resume_bdev(hib_resume_bdev); clear_page(swsusp_header); error = hib_submit_io(REQ_OP_READ, swsusp_resume_block, swsusp_header, NULL); diff --git a/mm/swapfile.c b/mm/swapfile.c index b63e7fd3d6c6..ce706c4a9b38 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -46,6 +46,7 @@ #include #include #include "swap.h" +#include static bool swap_count_continued(struct swap_info_struct *, pgoff_t, unsigned char); @@ -2399,6 +2400,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) struct filename *pathname; int err, found = 0; unsigned int old_block_size; + bool hibernation_swap = false; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -2488,10 +2490,14 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) flush_work(&p->discard_work); destroy_swap_extents(p); + + trace_android_vh_check_hibernation_swap(p->bdev, &hibernation_swap); + if (p->flags & SWP_CONTINUED) free_swap_count_continuations(p); - if (!p->bdev || !bdev_nonrot(p->bdev)) + if (!p->bdev || hibernation_swap || + !bdev_nonrot(p->bdev)) atomic_dec(&nr_rotate_swap); mutex_lock(&swapon_mutex); @@ -3001,6 +3007,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) struct page *page = NULL; struct inode *inode = NULL; bool inced_nr_rotate_swap = false; + bool hibernation_swap = false; if (swap_flags & ~SWAP_FLAGS_VALID) return -EINVAL; @@ -3076,13 +3083,16 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) goto bad_swap_unlock_inode; } + trace_android_vh_check_hibernation_swap(p->bdev, &hibernation_swap); + if (p->bdev && bdev_stable_writes(p->bdev)) p->flags |= SWP_STABLE_WRITES; if (p->bdev && p->bdev->bd_disk->fops->rw_page) p->flags |= SWP_SYNCHRONOUS_IO; - if (p->bdev && bdev_nonrot(p->bdev)) { + if (p->bdev && !hibernation_swap && + bdev_nonrot(p->bdev)) { int cpu; unsigned long ci, nr_cluster;