On Thu, Aug 13, 2020 at 12:45 AM Alex Shi <alex.shi@xxxxxxxxxxxxxxxxx> wrote: > > > > 在 2020/8/13 下午12:02, Alexander Duyck 写道: > > - rcu_read_lock(); > > - lruvec = mem_cgroup_page_lruvec(page, pgdat); > > - > > /* If we already hold the lock, we can skip some rechecking */ > > - if (lruvec != locked) { > > - if (locked) > > - unlock_page_lruvec_irqrestore(locked, flags); > > + if (!lruvec || !lruvec_holds_page_lru_lock(page, lruvec)) { > > Ops, lruvec_holds_page_lru_lock need rcu_read_lock. How so? The reason I wrote lruvec_holds_page_lru_lock the way I did is that it is simply comparing the pointers held by the page and the lruvec. It is never actually accessing any of the values, just the pointers. As such we should be able to compare the two since the lruvec is still locked and the the memcg and pgdat held by the lruvec should not be changed. Likewise with the page pointers assuming the values match. > > + if (lruvec) > > + unlock_page_lruvec_irqrestore(lruvec, flags); > > > > + lruvec = mem_cgroup_page_lruvec(page, pgdat); > > compact_lock_irqsave(&lruvec->lru_lock, &flags, cc); > > - locked = lruvec; > > rcu_read_unlock(); > > > > and some bugs: > [ 534.564741] CPU: 23 PID: 545 Comm: kcompactd1 Kdump: loaded Tainted: G S W 5.8.0-next-20200803-00028-g9a7ff2cd6e5c #85 > [ 534.577320] Hardware name: Alibaba Alibaba Cloud ECS/Alibaba Cloud ECS, BIOS 1.0.PL.IP.P.027.02 05/29/2020 > [ 534.587693] Call Trace: > [ 534.590522] dump_stack+0x96/0xd0 > [ 534.594231] ___might_sleep.cold.90+0xff/0x115 > [ 534.599102] kcompactd+0x24b/0x370 > [ 534.602904] ? finish_wait+0x80/0x80 > [ 534.606897] ? kcompactd_do_work+0x3d0/0x3d0 > [ 534.611566] kthread+0x14e/0x170 > [ 534.615182] ? kthread_park+0x80/0x80 > [ 534.619252] ret_from_fork+0x1f/0x30 > [ 535.629483] BUG: sleeping function called from invalid context at include/linux/freezer.h:57 > [ 535.638691] in_atomic(): 0, irqs_disabled(): 0, non_block: 0, pid: 545, name: kcompactd1 > [ 535.647601] INFO: lockdep is turned off. Ah, I see the bug now. It isn't the lruvec_holds_page_lru_lock that needs the LRU lock. This is an issue as a part of a merge conflict. There should have been an rcu_read_lock added before mem_cgroup_page_lruvec.