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: 379617660
Change-Id: Id41a25fd15c5b71f8064f1c7d9cac9560fcdde85
Signed-off-by: Vivek Kumar <quic_vivekuma@quicinc.com>
Signed-off-by: Shreyas K K <quic_shrekk@quicinc.com>
Signed-off-by: Auditya Bhattaram <quic_audityab@quicinc.com>
This commit is contained in:
Shreyas K K
2022-10-07 22:12:28 +05:30
committed by Treehugger Robot
parent 2b6b7a90c8
commit 4f8ffa0f05
5 changed files with 50 additions and 2 deletions

View File

@@ -33,6 +33,7 @@
#include <asm/sysreg.h>
#include <asm/trans_pgd.h>
#include <asm/virt.h>
#include <trace/hooks/bl_hib.h>
/*
* 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)
@@ -116,6 +119,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);

View File

@@ -44,6 +44,7 @@
#include <trace/hooks/fault.h>
#include <trace/hooks/topology.h>
#include <trace/hooks/rwsem.h>
#include <trace/hooks/bl_hib.h>
/*
* Export tracepoints that act as a bare tracehook (ie: have no trace event
@@ -155,3 +156,6 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_rwsem_downgrade_wake_finish);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_rwsem_wake_finish);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_alter_mutex_list_add);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mutex_unlock_slowpath);
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);

View File

@@ -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_S2D_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_HOOK_S2D_H
#include <trace/hooks/vendor_hooks.h>
struct file;
DECLARE_HOOK(android_vh_check_hibernation_swap,
TP_PROTO(struct file *resume_block_file, bool *hib_swap),
TP_ARGS(resume_block_file, 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 file *hib_resume_bdev_file),
TP_ARGS(hib_resume_bdev_file));
#endif /* _TRACE_HOOK_S2D_H */
/* This part must be outside protection */
#include <trace/define_trace.h>

View File

@@ -29,6 +29,7 @@
#include <linux/kthread.h>
#include <linux/crc32.h>
#include <linux/ktime.h>
#include <trace/hooks/bl_hib.h>
#include "power.h"
@@ -1569,6 +1570,7 @@ int swsusp_check(bool exclusive)
hib_resume_bdev_file = bdev_file_open_by_dev(swsusp_resume_device,
BLK_OPEN_READ, holder, NULL);
if (!IS_ERR(hib_resume_bdev_file)) {
trace_android_vh_save_hib_resume_bdev(hib_resume_bdev_file);
clear_page(swsusp_header);
error = hib_submit_io(REQ_OP_READ, swsusp_resume_block,
swsusp_header, NULL);

View File

@@ -49,6 +49,7 @@
#include <linux/swap_cgroup.h>
#include "internal.h"
#include "swap.h"
#include <trace/hooks/bl_hib.h>
static bool swap_count_continued(struct swap_info_struct *, pgoff_t,
unsigned char);
@@ -2728,6 +2729,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
struct inode *inode;
struct filename *pathname;
int err, found = 0;
bool hibernation_swap = false;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -2818,10 +2820,13 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
flush_work(&p->discard_work);
destroy_swap_extents(p);
trace_android_vh_check_hibernation_swap(p->swap_file, &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);
@@ -3361,6 +3366,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
struct folio *folio = NULL;
struct inode *inode = NULL;
bool inced_nr_rotate_swap = false;
bool hibernation_swap = false;
if (swap_flags & ~SWAP_FLAGS_VALID)
return -EINVAL;
@@ -3440,6 +3446,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
if (error)
goto bad_swap_unlock_inode;
trace_android_vh_check_hibernation_swap(si->swap_file, &hibernation_swap);
nr_extents = setup_swap_map_and_extents(si, swap_header, swap_map,
maxpages, &span);
if (unlikely(nr_extents < 0)) {
@@ -3464,7 +3472,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
if (si->bdev && bdev_synchronous(si->bdev))
si->flags |= SWP_SYNCHRONOUS_IO;
if (si->bdev && bdev_nonrot(si->bdev)) {
if (si->bdev && !hibernation_swap && bdev_nonrot(si->bdev)) {
si->flags |= SWP_SOLIDSTATE;
cluster_info = setup_clusters(si, swap_header, maxpages);