| From 88b1a17dfc3ed7728316478fae0f5ad508f50397 Mon Sep 17 00:00:00 2001 |
| From: Linus Torvalds <torvalds@linux-foundation.org> |
| Date: Thu, 11 Apr 2019 10:14:59 -0700 |
| Subject: mm: add 'try_get_page()' helper function |
| |
| From: Linus Torvalds <torvalds@linux-foundation.org> |
| |
| commit 88b1a17dfc3ed7728316478fae0f5ad508f50397 upstream. |
| |
| This is the same as the traditional 'get_page()' function, but instead |
| of unconditionally incrementing the reference count of the page, it only |
| does so if the count was "safe". It returns whether the reference count |
| was incremented (and is marked __must_check, since the caller obviously |
| has to be aware of it). |
| |
| Also like 'get_page()', you can't use this function unless you already |
| had a reference to the page. The intent is that you can use this |
| exactly like get_page(), but in situations where you want to limit the |
| maximum reference count. |
| |
| The code currently does an unconditional WARN_ON_ONCE() if we ever hit |
| the reference count issues (either zero or negative), as a notification |
| that the conditional non-increment actually happened. |
| |
| NOTE! The count access for the "safety" check is inherently racy, but |
| that doesn't matter since the buffer we use is basically half the range |
| of the reference count (ie we look at the sign of the count). |
| |
| Acked-by: Matthew Wilcox <willy@infradead.org> |
| Cc: Jann Horn <jannh@google.com> |
| Cc: stable@kernel.org |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| include/linux/mm.h | 9 +++++++++ |
| 1 file changed, 9 insertions(+) |
| |
| --- a/include/linux/mm.h |
| +++ b/include/linux/mm.h |
| @@ -839,6 +839,15 @@ static inline void get_page(struct page |
| page_ref_inc(page); |
| } |
| |
| +static inline __must_check bool try_get_page(struct page *page) |
| +{ |
| + page = compound_head(page); |
| + if (WARN_ON_ONCE(page_ref_count(page) <= 0)) |
| + return false; |
| + page_ref_inc(page); |
| + return true; |
| +} |
| + |
| static inline void put_page(struct page *page) |
| { |
| page = compound_head(page); |