summaryrefslogtreecommitdiff
path: root/include/linux/mm.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/linux/mm.h')
-rw-r--r--include/linux/mm.h23
1 files changed, 22 insertions, 1 deletions
diff --git a/include/linux/mm.h b/include/linux/mm.h
index e7b15518189e..b6ad99903617 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -504,6 +504,15 @@ static inline void get_huge_page_tail(struct page *page)
extern bool __get_page_tail(struct page *page);
+static inline int page_ref_count(struct page *page)
+{
+ return atomic_read(&page->_count);
+}
+
+/* 127: arbitrary random number, small enough to assemble well */
+#define page_ref_zero_or_close_to_overflow(page) \
+ ((unsigned int) atomic_read(&page->_count) + 127u <= 127u)
+
static inline void get_page(struct page *page)
{
if (unlikely(PageTail(page)))
@@ -513,10 +522,22 @@ static inline void get_page(struct page *page)
* Getting a normal page or the head of a compound page
* requires to already have an elevated page->_count.
*/
- VM_BUG_ON_PAGE(atomic_read(&page->_count) <= 0, page);
+ VM_BUG_ON_PAGE(page_ref_zero_or_close_to_overflow(page), page);
atomic_inc(&page->_count);
}
+static inline __must_check bool try_get_page(struct page *page)
+{
+ if (unlikely(PageTail(page)))
+ if (likely(__get_page_tail(page)))
+ return true;
+
+ if (WARN_ON_ONCE(atomic_read(&page->_count) <= 0))
+ return false;
+ atomic_inc(&page->_count);
+ return true;
+}
+
static inline struct page *virt_to_head_page(const void *x)
{
struct page *page = virt_to_page(x);