On Wed, Oct 24, 2018 at 12:35:03AM +0300, Igor Stoppa wrote: > +static __always_inline > +bool __pratomic_long_op(bool inc, struct pratomic_long_t *l) > +{ > + struct page *page; > + uintptr_t base; > + uintptr_t offset; > + unsigned long flags; > + size_t size = sizeof(*l); > + bool is_virt = __is_wr_after_init(l, size); > + > + if (WARN(!(is_virt || likely(__is_wr_pool(l, size))), > + WR_ERR_RANGE_MSG)) > + return false; > + local_irq_save(flags); > + if (is_virt) > + page = virt_to_page(l); > + else > + vmalloc_to_page(l); > + offset = (~PAGE_MASK) & (uintptr_t)l; > + base = (uintptr_t)vmap(&page, 1, VM_MAP, PAGE_KERNEL); > + if (WARN(!base, WR_ERR_PAGE_MSG)) { > + local_irq_restore(flags); > + return false; > + } > + if (inc) > + atomic_long_inc((atomic_long_t *)(base + offset)); > + else > + atomic_long_dec((atomic_long_t *)(base + offset)); > + vunmap((void *)base); > + local_irq_restore(flags); > + return true; > + > +} That's just hideously nasty.. and horribly broken. We're not going to duplicate all these kernel interfaces wrapped in gunk like that. Also, you _cannot_ call vunmap() with IRQs disabled. Clearly you've never tested this with debug bits enabled.