Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm: add a signature in struct page

This is needed by the page_pool to avoid recycling a page not allocated
via page_pool.

The page->signature field is aliased to page->lru.next and
page->compound_head, but it can't be set by mistake because the
signature value is a bad pointer, and can't trigger a false positive
in PageTail() because the last bit is 0.

Co-developed-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Matteo Croce <mcroce@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Matteo Croce and committed by
David S. Miller
c07aea3e 35cba15a

+22 -5
+6 -5
include/linux/mm.h
··· 1668 1668 static inline bool page_is_pfmemalloc(const struct page *page) 1669 1669 { 1670 1670 /* 1671 - * Page index cannot be this large so this must be 1672 - * a pfmemalloc page. 1671 + * lru.next has bit 1 set if the page is allocated from the 1672 + * pfmemalloc reserves. Callers may simply overwrite it if 1673 + * they do not need to preserve that information. 1673 1674 */ 1674 - return page->index == -1UL; 1675 + return (uintptr_t)page->lru.next & BIT(1); 1675 1676 } 1676 1677 1677 1678 /* ··· 1681 1680 */ 1682 1681 static inline void set_page_pfmemalloc(struct page *page) 1683 1682 { 1684 - page->index = -1UL; 1683 + page->lru.next = (void *)BIT(1); 1685 1684 } 1686 1685 1687 1686 static inline void clear_page_pfmemalloc(struct page *page) 1688 1687 { 1689 - page->index = 0; 1688 + page->lru.next = NULL; 1690 1689 } 1691 1690 1692 1691 /*
+7
include/linux/mm_types.h
··· 97 97 }; 98 98 struct { /* page_pool used by netstack */ 99 99 /** 100 + * @pp_magic: magic value to avoid recycling non 101 + * page_pool allocated pages. 102 + */ 103 + unsigned long pp_magic; 104 + struct page_pool *pp; 105 + unsigned long _pp_mapping_pad; 106 + /** 100 107 * @dma_addr: might require a 64-bit value on 101 108 * 32-bit architectures. 102 109 */
+3
include/linux/poison.h
··· 78 78 /********** security/ **********/ 79 79 #define KEY_DESTROY 0xbd 80 80 81 + /********** net/core/page_pool.c **********/ 82 + #define PP_SIGNATURE (0x40 + POISON_POINTER_DELTA) 83 + 81 84 #endif
+6
net/core/page_pool.c
··· 17 17 #include <linux/dma-mapping.h> 18 18 #include <linux/page-flags.h> 19 19 #include <linux/mm.h> /* for __put_page() */ 20 + #include <linux/poison.h> 20 21 21 22 #include <trace/events/page_pool.h> 22 23 ··· 222 221 return NULL; 223 222 } 224 223 224 + page->pp_magic |= PP_SIGNATURE; 225 + 225 226 /* Track how many pages are held 'in-flight' */ 226 227 pool->pages_state_hold_cnt++; 227 228 trace_page_pool_state_hold(pool, page, pool->pages_state_hold_cnt); ··· 266 263 put_page(page); 267 264 continue; 268 265 } 266 + page->pp_magic |= PP_SIGNATURE; 269 267 pool->alloc.cache[pool->alloc.count++] = page; 270 268 /* Track how many pages are held 'in-flight' */ 271 269 pool->pages_state_hold_cnt++; ··· 345 341 DMA_ATTR_SKIP_CPU_SYNC); 346 342 page_pool_set_dma_addr(page, 0); 347 343 skip_dma_unmap: 344 + page->pp_magic = 0; 345 + 348 346 /* This may be the last page returned, releasing the pool, so 349 347 * it is not safe to reference pool afterwards. 350 348 */