ANDROID: add vendor hook of add/delete/iterate node for swap_avail_heads

Our Android phones occur Panic as follows:

[77522.303024][ T9734] Call trace:
[77522.303039][ T9734] dump_backtrace.cfi_jt+0x0/0x8
[77522.303052][ T9734] dump_stack_lvl+0xc4/0x140
[77522.303061][ T9734] dump_stack+0x1c/0x2c
[77522.303123][ T9734] mrdump_common_die+0x3a8/0x544 [mrdump]
[77522.303177][ T9734] ipanic_die+0x24/0x38 [mrdump]
[77522.303189][ T9734] die+0x340/0x698
[77522.303199][ T9734] bug_handler+0x48/0x108
[77522.303210][ T9734] brk_handler+0xac/0x1a8
[77522.303221][ T9734] do_debug_exception+0xe0/0x1e0
[77522.303233][ T9734] el1_dbg+0x38/0x54
[77522.303242][ T9734] el1_sync_handler+0x40/0x88
[77522.303255][ T9734] el1_sync+0x8c/0x140
[77522.303264][ T9734] plist_requeue+0xd4/0x110
[77522.303297][ T9734] tran_get_swap_pages+0xc8/0x364 [memfusion]
[77522.303329][ T9734] probe_android_vh_get_swap_page+0x1b4/0x220 [memfusion]
[77522.303342][ T9734] get_swap_page+0x258/0x304
[77522.303352][ T9734] shrink_page_list+0xe00/0x1e0c
[77522.303361][ T9734] shrink_inactive_list+0x2f4/0xac8
[77522.303373][ T9734] shrink_lruvec+0x1a4/0x34c
[77522.303383][ T9734] shrink_node_memcgs+0x84/0x3b0
[77522.303391][ T9734] shrink_node+0x2c4/0x6e4
[77522.303400][ T9734] shrink_zones+0x16c/0x29c
[77522.303410][ T9734] do_try_to_free_pages+0xe4/0x2bc
[77522.303418][ T9734] try_to_free_pages+0x388/0x7b4
[77522.303429][ T9734] __alloc_pages_direct_reclaim+0x88/0x278
[77522.303438][ T9734] __alloc_pages_slowpath+0x464/0xb24
[77522.303447][ T9734] __alloc_pages_nodemask+0x1f4/0x3dc
[77522.303458][ T9734] do_anonymous_page+0x164/0x914
[77522.303466][ T9734] handle_pte_fault+0x15c/0x9f8
[77522.303476][ T9734] ___handle_speculative_fault+0x234/0xe18
[77522.303485][ T9734] __handle_speculative_fault+0x78/0x21c
[77522.303497][ T9734] do_page_fault+0x36c/0x754
[77522.303506][ T9734] do_translation_fault+0x48/0x64
[77522.303514][ T9734] do_mem_abort+0x6c/0x164
[77522.303522][ T9734] el0_da+0x24/0x34
[77522.303531][ T9734] el0_sync_handler+0xc8/0xf0
[77522.303539][ T9734] el0_sync+0x1b4/0x1c0

The analysis shows that when we iterate the swap_avail_heads list, we get
node A, but before we access node A, node A is maybe deleted, and by the time
we actually access node A, it no longer exists, as follows:

            CPU1 thread1                                 CPU2 thread2
plist_for_each_entry_safe()
get si->avail_lists[node] from swap_avail_heads
                                             remove si->avail_lists[node] from swap_avail_heads
plist_requeue(&si->avail_lists[node])
BUG_ON(plist_node_empty(node)); // trigger

Due to when we use vendor hook of get_swap_page, the get_swap_pages() function
is overridden, use our own spin_lock to protect when iterate swap_avail_heads
list, but now use native swap_avail_lock spin_lock protect when the
swap_avail_heads list to add and delete nodes, so there will be concurrent
access.

So add vendor hook of add/delete/iterate node for avail_list, in this way, we
can use our own spin_lock to protect the swap_avail_heads list to add, delete
and iterate node.

Due to enable_swap_info function to call vendor hook of add_to_avail_list,
need first init swap_avail_heads, so also add vendor hook of
swap_avail_heads_init.

Due to the vendor hook of __cgroup_throttle_swaprate need to call
blkcg_schedule_throttle function, so export it also.

Bug: 225795494
Change-Id: I03107cbda6310fa7ae85e41b8cf1fa8225cafe78
Signed-off-by: Lincheng Yang <lincheng.yang@transsion.com>
Suggested-by: Bing Han <bing.han@transsion.com>
This commit is contained in:
Lincheng Yang 2023-09-07 11:19:43 +08:00 committed by Treehugger Robot
parent bd34b88730
commit 6356ed35b9
4 changed files with 35 additions and 0 deletions

View File

@ -1794,6 +1794,7 @@ void blkcg_schedule_throttle(struct request_queue *q, bool use_memdelay)
current->use_memdelay = use_memdelay; current->use_memdelay = use_memdelay;
set_notify_resume(current); set_notify_resume(current);
} }
EXPORT_SYMBOL_GPL(blkcg_schedule_throttle);
/** /**
* blkcg_add_delay - add delay to this blkg * blkcg_add_delay - add delay to this blkg

View File

@ -468,12 +468,16 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_free_swap_slot);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_free_swap_slot); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_free_swap_slot);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_get_swap_page); EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_get_swap_page);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_get_swap_page); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_get_swap_page);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_add_to_avail_list);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_del_from_avail_list);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh___cgroup_throttle_swaprate);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_madvise_cold_or_pageout); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_madvise_cold_or_pageout);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_page_isolated_for_reclaim); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_page_isolated_for_reclaim);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_inactive_is_low); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_inactive_is_low);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_snapshot_refaults); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_snapshot_refaults);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_account_swap_pages); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_account_swap_pages);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_unuse_swap_page); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_unuse_swap_page);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_swap_avail_heads_init);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_init_swap_info_struct); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_init_swap_info_struct);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_si_swapinfo); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_si_swapinfo);
EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_alloc_si); EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_alloc_si);

View File

@ -287,6 +287,15 @@ DECLARE_HOOK(android_vh_get_swap_page,
TP_PROTO(struct page *page, swp_entry_t *entry, TP_PROTO(struct page *page, swp_entry_t *entry,
struct swap_slots_cache *cache, bool *found), struct swap_slots_cache *cache, bool *found),
TP_ARGS(page, entry, cache, found)); TP_ARGS(page, entry, cache, found));
DECLARE_HOOK(android_vh_add_to_avail_list,
TP_PROTO(struct swap_info_struct *p, bool *skip),
TP_ARGS(p, skip));
DECLARE_HOOK(android_vh_del_from_avail_list,
TP_PROTO(struct swap_info_struct *p, bool *skip),
TP_ARGS(p, skip));
DECLARE_HOOK(android_vh___cgroup_throttle_swaprate,
TP_PROTO(int nid, bool *skip),
TP_ARGS(nid, skip));
DECLARE_HOOK(android_vh_madvise_cold_or_pageout, DECLARE_HOOK(android_vh_madvise_cold_or_pageout,
TP_PROTO(struct vm_area_struct *vma, bool *allow_shared), TP_PROTO(struct vm_area_struct *vma, bool *allow_shared),
TP_ARGS(vma, allow_shared)); TP_ARGS(vma, allow_shared));
@ -299,6 +308,9 @@ DECLARE_HOOK(android_vh_account_swap_pages,
DECLARE_HOOK(android_vh_unuse_swap_page, DECLARE_HOOK(android_vh_unuse_swap_page,
TP_PROTO(struct swap_info_struct *si, struct page *page), TP_PROTO(struct swap_info_struct *si, struct page *page),
TP_ARGS(si, page)); TP_ARGS(si, page));
DECLARE_HOOK(android_vh_swap_avail_heads_init,
TP_PROTO(struct plist_head *swap_avail_heads),
TP_ARGS(swap_avail_heads));
DECLARE_HOOK(android_vh_init_swap_info_struct, DECLARE_HOOK(android_vh_init_swap_info_struct,
TP_PROTO(struct swap_info_struct *p, struct plist_head *swap_avail_heads), TP_PROTO(struct swap_info_struct *p, struct plist_head *swap_avail_heads),
TP_ARGS(p, swap_avail_heads)); TP_ARGS(p, swap_avail_heads));

View File

@ -675,6 +675,12 @@ static void __del_from_avail_list(struct swap_info_struct *p)
static void del_from_avail_list(struct swap_info_struct *p) static void del_from_avail_list(struct swap_info_struct *p)
{ {
bool skip = false;
trace_android_vh_del_from_avail_list(p, &skip);
if (skip)
return;
spin_lock(&swap_avail_lock); spin_lock(&swap_avail_lock);
__del_from_avail_list(p); __del_from_avail_list(p);
spin_unlock(&swap_avail_lock); spin_unlock(&swap_avail_lock);
@ -700,6 +706,11 @@ static void swap_range_alloc(struct swap_info_struct *si, unsigned long offset,
static void add_to_avail_list(struct swap_info_struct *p) static void add_to_avail_list(struct swap_info_struct *p)
{ {
int nid; int nid;
bool skip = false;
trace_android_vh_add_to_avail_list(p, &skip);
if (skip)
return;
spin_lock(&swap_avail_lock); spin_lock(&swap_avail_lock);
for_each_node(nid) { for_each_node(nid) {
@ -3394,6 +3405,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
if (swap_flags & SWAP_FLAG_PREFER) if (swap_flags & SWAP_FLAG_PREFER)
prio = prio =
(swap_flags & SWAP_FLAG_PRIO_MASK) >> SWAP_FLAG_PRIO_SHIFT; (swap_flags & SWAP_FLAG_PRIO_MASK) >> SWAP_FLAG_PRIO_SHIFT;
trace_android_vh_swap_avail_heads_init(swap_avail_heads);
enable_swap_info(p, prio, swap_map, cluster_info, frontswap_map); enable_swap_info(p, prio, swap_map, cluster_info, frontswap_map);
trace_android_vh_init_swap_info_struct(p, swap_avail_heads); trace_android_vh_init_swap_info_struct(p, swap_avail_heads);
@ -3848,6 +3861,7 @@ void __cgroup_throttle_swaprate(struct page *page, gfp_t gfp_mask)
{ {
struct swap_info_struct *si, *next; struct swap_info_struct *si, *next;
int nid = page_to_nid(page); int nid = page_to_nid(page);
bool skip = false;
if (!(gfp_mask & __GFP_IO)) if (!(gfp_mask & __GFP_IO))
return; return;
@ -3862,6 +3876,10 @@ void __cgroup_throttle_swaprate(struct page *page, gfp_t gfp_mask)
if (current->throttle_queue) if (current->throttle_queue)
return; return;
trace_android_vh___cgroup_throttle_swaprate(nid, &skip);
if (skip)
return;
spin_lock(&swap_avail_lock); spin_lock(&swap_avail_lock);
plist_for_each_entry_safe(si, next, &swap_avail_heads[nid], plist_for_each_entry_safe(si, next, &swap_avail_heads[nid],
avail_lists[nid]) { avail_lists[nid]) {