[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20211208203544.2297121-5-pasha.tatashin@soleen.com>
Date: Wed, 8 Dec 2021 20:35:38 +0000
From: Pasha Tatashin <pasha.tatashin@...een.com>
To: pasha.tatashin@...een.com, linux-kernel@...r.kernel.org,
linux-mm@...ck.org, linux-m68k@...ts.linux-m68k.org,
anshuman.khandual@....com, willy@...radead.org,
akpm@...ux-foundation.org, william.kucharski@...cle.com,
mike.kravetz@...cle.com, vbabka@...e.cz, geert@...ux-m68k.org,
schmitzmic@...il.com, rostedt@...dmis.org, mingo@...hat.com,
hannes@...xchg.org, guro@...com, songmuchun@...edance.com,
weixugc@...gle.com, gthelen@...gle.com, rientjes@...gle.com,
pjt@...gle.com
Subject: [PATCH 04/10] mm: remove set_page_count() from page_frag_alloc_align
set_page_count() unconditionally resets the value of _ref_count and that
is dangerous, as it is not programmatically verified. Instead we rely on
comments like: "OK, page count is 0, we can safely set it".
Add a new refcount function: page_ref_add_return() to return the new
refcount value after adding to it. Use the return value to verify that
the _ref_count was indeed the expected one.
Signed-off-by: Pasha Tatashin <pasha.tatashin@...een.com>
---
include/linux/page_ref.h | 11 +++++++++++
mm/page_alloc.c | 6 ++++--
2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/include/linux/page_ref.h b/include/linux/page_ref.h
index f3c61dc6344a..27880aca2e2f 100644
--- a/include/linux/page_ref.h
+++ b/include/linux/page_ref.h
@@ -115,6 +115,17 @@ static inline void init_page_count(struct page *page)
set_page_count(page, 1);
}
+static inline int page_ref_add_return(struct page *page, int nr)
+{
+ int old_val = atomic_fetch_add(nr, &page->_refcount);
+ int new_val = old_val + nr;
+
+ VM_BUG_ON_PAGE((unsigned int)new_val < (unsigned int)old_val, page);
+ if (page_ref_tracepoint_active(page_ref_mod_and_return))
+ __page_ref_mod_and_return(page, nr, new_val);
+ return new_val;
+}
+
static inline void page_ref_add(struct page *page, int nr)
{
int old_val = atomic_fetch_add(nr, &page->_refcount);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index edfd6c81af82..b5554767b9de 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -5523,6 +5523,7 @@ void *page_frag_alloc_align(struct page_frag_cache *nc,
unsigned int size = PAGE_SIZE;
struct page *page;
int offset;
+ int refcnt;
if (unlikely(!nc->va)) {
refill:
@@ -5561,8 +5562,9 @@ void *page_frag_alloc_align(struct page_frag_cache *nc,
/* if size can vary use size else just use PAGE_SIZE */
size = nc->size;
#endif
- /* OK, page count is 0, we can safely set it */
- set_page_count(page, PAGE_FRAG_CACHE_MAX_SIZE + 1);
+ /* page count is 0, set it to PAGE_FRAG_CACHE_MAX_SIZE + 1 */
+ refcnt = page_ref_add_return(page, PAGE_FRAG_CACHE_MAX_SIZE + 1);
+ VM_BUG_ON_PAGE(refcnt != PAGE_FRAG_CACHE_MAX_SIZE + 1, page);
/* reset page count bias and offset to start of new frag */
nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1;
--
2.34.1.400.ga245620fadb-goog
Powered by blists - more mailing lists