aboutsummaryrefslogtreecommitdiffstats
path: root/mm/page_alloc.c
diff options
context:
space:
mode:
authorSuren Baghdasaryan <[email protected]>2024-03-21 16:36:42 +0000
committerAndrew Morton <[email protected]>2024-04-26 03:55:54 +0000
commitcc92eba1c88b1f74e0f044df2738f4e4b22f1e4e (patch)
tree0ca9aeb6f5d3ea85c98b08c5a007a5e6ec6e5062 /mm/page_alloc.c
parentmm: create new codetag references during page splitting (diff)
downloadkernel-cc92eba1c88b1f74e0f044df2738f4e4b22f1e4e.tar.gz
kernel-cc92eba1c88b1f74e0f044df2738f4e4b22f1e4e.zip
mm: fix non-compound multi-order memory accounting in __free_pages
When a non-compound multi-order page is freed, it is possible that a speculative reference keeps the page pinned. In this case we free all pages except for the first page, which will be freed later by the last put_page(). However the page passed to put_page() is indistinguishable from an order-0 page, so it cannot do the accounting, just as it cannot free the subsequent pages. Do the accounting here, where we free the pages. Link: https://lkml.kernel.org/r/[email protected] Reported-by: Vlastimil Babka <[email protected]> Signed-off-by: Suren Baghdasaryan <[email protected]> Tested-by: Kees Cook <[email protected]> Cc: Alexander Viro <[email protected]> Cc: Alex Gaynor <[email protected]> Cc: Alice Ryhl <[email protected]> Cc: Andreas Hindborg <[email protected]> Cc: Benno Lossin <[email protected]> Cc: "Björn Roy Baron" <[email protected]> Cc: Boqun Feng <[email protected]> Cc: Christoph Lameter <[email protected]> Cc: Dennis Zhou <[email protected]> Cc: Gary Guo <[email protected]> Cc: Kent Overstreet <[email protected]> Cc: Miguel Ojeda <[email protected]> Cc: Pasha Tatashin <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Tejun Heo <[email protected]> Cc: Wedson Almeida Filho <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r--mm/page_alloc.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index e453ee22d489..e1241ecef271 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -4664,12 +4664,15 @@ void __free_pages(struct page *page, unsigned int order)
{
/* get PageHead before we drop reference */
int head = PageHead(page);
+ struct alloc_tag *tag = pgalloc_tag_get(page);
if (put_page_testzero(page))
free_the_page(page, order);
- else if (!head)
+ else if (!head) {
+ pgalloc_tag_sub_pages(tag, (1 << order) - 1);
while (order-- > 0)
free_the_page(page + (1 << order), order);
+ }
}
EXPORT_SYMBOL(__free_pages);