include/linux/page_ref.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/include/linux/page_ref.h b/include/linux/page_ref.h index 544150d1d5fd..ed3f262aa7f1 100644 --- a/include/linux/page_ref.h +++ b/include/linux/page_ref.h @@ -234,8 +234,18 @@ static inline bool page_ref_add_unless(struct page *page, int nr, int u) rcu_read_lock(); /* avoid writing to the vmemmap area being remapped */ - if (page_count_writable(page, u)) - ret = atomic_add_unless(&page->_refcount, nr, u); + if (page_count_writable(page, u)) { + /* Assume count == 1, don't read it! */ + int old = 1; + for (;;) { + if (atomic_try_cmpxchg(&page->_refcount, &old, old+1)) { + ret = true; + break; + } + if (unlikely(!old)) + break; + } + } rcu_read_unlock(); if (page_ref_tracepoint_active(page_ref_mod_unless))