[PATCH RT] mm/swap: use local lock in deactivate_page()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Zanxiong Qiu <zqiu2000@xxxxxxx>

get_cpu_var() calls preempt_disable(), while on RT kernel,
pagevec_lru_move_fn() will call spinlock and might schedule
the context out and hence the schedule bug occurred, issue
is found on 5.4.70-rt40 and reproducable on 5.4.74-rt41.

[  306.340109] BUG: scheduling while atomic: stress-ng-vm/3361/0x00000002
...
[  306.340143] Preemption disabled at:
[  306.340143] [<ffffffffaa42c2fd>] deactivate_page+0x5d/0x110
...
[  306.340151] Call Trace:
[  306.340153]  dump_stack+0x50/0x70
[  306.340157]  ? deactivate_page+0x5d/0x110
[  306.340158]  __schedule_bug.cold+0x89/0x96
[  306.340160]  __schedule+0x576/0x860
[  306.340163]  ? _raw_spin_lock+0x13/0x30
[  306.340164]  schedule+0x43/0xd0
[  306.340166]  rt_spin_lock_slowlock_locked+0x117/0x2c0
[  306.340168]  ? __activate_page+0x2f0/0x2f0
[  306.340169]  rt_spin_lock_slowlock+0x51/0x80
[  306.340171]  pagevec_lru_move_fn+0x62/0xc0
[  306.340172]  deactivate_page+0xb3/0x110
[  306.340174]  madvise_cold_or_pageout_pte_range+0x277/0x2d0
[  306.340176]  ? free_unref_page_list+0x3ac/0x3c0
[  306.340177]  __walk_page_range+0x1f4/0x490
[  306.340181]  walk_page_range+0x89/0x110
[  306.340182]  madvise_cold+0x7e/0xc0
[  306.340183]  ? syscall_return_via_sysret+0xf/0x7f
[  306.340185]  ? __switch_to_asm+0x34/0x70
[  306.340186]  ? __switch_to_asm+0x40/0x70
[  306.340187]  ? __switch_to_asm+0x34/0x70
[  306.340188]  ? __switch_to_asm+0x40/0x70
[  306.340188]  ? _raw_spin_unlock_irq+0x17/0x50
[  306.340189]  ? find_vma+0x16/0x70
[  306.340190]  __do_sys_madvise+0x328/0x810
[  306.340193]  ? do_syscall_64+0x67/0x1f0
[  306.340195]  do_syscall_64+0x67/0x1f0
[  306.340196]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[  306.340197] RIP: 0033:0x7f12e177510b

2154a0abcc9 ("mm: Revert the DEFINE_PER_CPU_PAGEVEC implementation")
reverted the lock/unlock_swap_pvec function, however, get_cpu_var()
was added back in deactivate_page(), actually, get_locked_var()
shall be used instead to avoid preempt_disable() call for RT.

Signed-off-by: Zanxiong Qiu <zqiu2000@xxxxxxx>
---
 mm/swap.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/mm/swap.c b/mm/swap.c
index cdb4f1fa3a48..463cac334fcf 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -666,12 +666,13 @@ void deactivate_file_page(struct page *page)
 void deactivate_page(struct page *page)
 {
 	if (PageLRU(page) && PageActive(page) && !PageUnevictable(page)) {
-		struct pagevec *pvec = &get_cpu_var(lru_deactivate_pvecs);
+		struct pagevec *pvec = &get_locked_var(swapvec_lock,
+							lru_deactivate_pvecs);
 
 		get_page(page);
 		if (!pagevec_add(pvec, page) || PageCompound(page))
 			pagevec_lru_move_fn(pvec, lru_deactivate_fn, NULL);
-		put_cpu_var(lru_deactivate_pvecs);
+		put_locked_var(swapvec_lock, lru_deactivate_pvecs);
 	}
 }
 
-- 
2.17.1




[Index of Archives]     [RT Stable]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]

  Powered by Linux