From: zhaowuyun <zhaowuyun@xxxxxxxxxxxx> issue is that there are two processes A and B, A is kworker/u16:8 normal priority, B is AudioTrack, RT priority, they are on the same CPU 3. The task A preempted by task B in the moment after __delete_from_swap_cache(page) and before swapcache_free(swap). The task B does __read_swap_cache_async in the do {} while loop, it will never find the page from swapper_space because the page is removed by the task A, and it will never sucessfully in swapcache_prepare because the entry is EEXIST. The task B then stuck in the loop infinitely because it is a RT task, no one can preempt it. so need to disable preemption until the swapcache_free executed. TASK A: ===================================================== Process: kworker/u16:8, cpu: 3 pid: 20289 start: 0xffffffc0385f8e00 ===================================================== Task name: kworker/u16:8 pid: 20289 cpu: 3 start: ffffffc0385f8e00 state: 0x0 exit_state: 0x0 stack base: 0xffffffc012ba0000 Prio: 120 Stack: [<ffffff80bca861a4>] __switch_to+0x90 [<ffffff80bd83eddc>] __schedule+0x29c [<ffffff80bd83f600>] preempt_schedule_common+0x24 [<ffffff80bd83f63c>] preempt_schedule.part.169+0x1c [<ffffff80bd83f664>] preempt_schedule+0x20 [<ffffff80bd84396c>] _raw_spin_unlock_irqrestore+0x40 [<ffffff80bcbc4710>] __remove_mapping+0x174 [<ffffff80bcbc7698>] shrink_page_list+0x894 [<ffffff80bcbc7d7c>] reclaim_pages_from_list+0xc8 [<ffffff80bcc7b910>] reclaim_pte_range+0x158 [<ffffff80bcbf45d4>] walk_pgd_range+0xd4 [<ffffff80bcbf476c>] walk_page_range+0x74 [<ffffff80bcc7cd64>] reclaim_task_anon+0xdc [<ffffff80bcc0a4c4>] swap_fn+0x1b8 [<ffffff80bcac2e88>] process_one_work+0x168 [<ffffff80bcac33a0>] worker_thread+0x224 [<ffffff80bcac9864>] kthread+0xe0 [<ffffff80bca836e0>] ret_from_fork+0x10 TASK B: [535478.724249] CPU: 3 PID: 4645 Comm: AudioTrack Tainted: GF UD W O 4.9.82-perf+ #1 [535478.724385] Hardware name: Qualcomm Technologies, Inc. SDM450 PMI632 MTP S3 (DT) [535478.724479] task: ffffffc026ce2a00 task.stack: ffffffc012e14000 [535478.724537] PC is at __read_swap_cache_async+0x154/0x25c [535478.724630] LR is at __read_swap_cache_async+0x9c/0x25c ... [535478.735546] [<ffffff80bcbf9970>] __read_swap_cache_async+0x154/0x25c [535478.735599] [<ffffff80bcbf9a98>] read_swap_cache_async+0x20/0x54 [535478.735697] [<ffffff80bcbf9b24>] swapin_readahead+0x58/0x218 [535478.735797] [<ffffff80bcbe5240>] do_swap_page+0x3c4/0x4d0 [535478.735850] [<ffffff80bcbe6bf8>] handle_mm_fault+0x364/0xba4 [535478.735949] [<ffffff80bca9b5a8>] do_page_fault+0x2a0/0x38c [535478.736003] [<ffffff80bca9b79c>] do_translation_fault+0x40/0x48 [535478.736100] [<ffffff80bca81340>] do_mem_abort+0x50/0xc8 Change-Id: I36d9df7ccff77c589b7157225410269c675a8504 Signed-off-by: zhaowuyun <zhaowuyun@xxxxxxxxxxxx> --- mm/vmscan.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mm/vmscan.c b/mm/vmscan.c index 2740973..acede002 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -674,6 +674,12 @@ static int __remove_mapping(struct address_space *mapping, struct page *page, BUG_ON(!PageLocked(page)); BUG_ON(mapping != page_mapping(page)); + /* + * preemption must be disabled to protect current task preempted before + * swapcache_free(swap) invoked by the task which do the + * __read_swap_cache_async job on the same page + */ + preempt_disable(); spin_lock_irqsave(&mapping->tree_lock, flags); /* * The non racy check for a busy page. @@ -714,6 +720,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page, __delete_from_swap_cache(page); spin_unlock_irqrestore(&mapping->tree_lock, flags); swapcache_free(swap); + preempt_enable(); } else { void (*freepage)(struct page *); void *shadow = NULL; @@ -740,6 +747,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page, shadow = workingset_eviction(mapping, page); __delete_from_page_cache(page, shadow); spin_unlock_irqrestore(&mapping->tree_lock, flags); + preempt_enable(); if (freepage != NULL) freepage(page); @@ -749,6 +757,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page, cannot_free: spin_unlock_irqrestore(&mapping->tree_lock, flags); + preempt_enable(); return 0; } -- 1.9.1