On Thu 11-03-21 10:52:50, Peter Zijlstra wrote: > On Thu, Mar 11, 2021 at 10:44:56AM +0100, Michal Hocko wrote: > > On Thu 11-03-21 10:32:24, Peter Zijlstra wrote: > > > The whole changelog reads like a trainwreck, but akpm already commented > > > on that. I picked out a small factual incorrectness, simply because if > > > you can't get that right, the whole argument looses weight. > > > > Is there any reason why in_atomic || irq_disabled wouldn't work > > universally? > > I just explained to you how you really wanted: > > in_atomic() && !irq_disabled() Sorry for being dense but I do not follow. You have provided the following example spin_lock(&A); <IRQ> spin_lock(&A); if A == hugetlb_lock then we should never reenter with free_huge_page if (in_atomic() || irq_disabled()) schedule_in_wq(); else free_directly() because hugetlb_lock is never held in irq context other than from put_page (aka the above) path which will explicitly defer the handling and thus the lock to a different context. We need to check for irq_disabled because of the sleeping paths in the freeing path. Or do I miss something? >From the code simplicity POV (and hugetlb has grown a lot of complexity) it would be really easiest to make sure __free_huge_page to be called from a non-atomic process context. There are few ways to do that - defer each call to a WQ - user visible which sucks - defer from atomic or otherwise non-sleeping contextx - requires reliable in_atomic AFAICS - defer sleeping operations - makes the code flow more complex and it would be again user visible in some cases. So I would say we are in "pick your own poison" kind of situation. -- Michal Hocko SUSE Labs