forked from mirrors/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>
This commit is contained in:
		
							parent
							
								
									35cba15a50
								
							
						
					
					
						commit
						c07aea3ef4
					
				
					 4 changed files with 22 additions and 5 deletions
				
			
		|  | @ -1668,10 +1668,11 @@ struct address_space *page_mapping(struct page *page); | ||||||
| static inline bool page_is_pfmemalloc(const struct page *page) | static inline bool page_is_pfmemalloc(const struct page *page) | ||||||
| { | { | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Page index cannot be this large so this must be | 	 * lru.next has bit 1 set if the page is allocated from the | ||||||
| 	 * a pfmemalloc page. | 	 * pfmemalloc reserves.  Callers may simply overwrite it if | ||||||
|  | 	 * they do not need to preserve that information. | ||||||
| 	 */ | 	 */ | ||||||
| 	return page->index == -1UL; | 	return (uintptr_t)page->lru.next & BIT(1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -1680,12 +1681,12 @@ static inline bool page_is_pfmemalloc(const struct page *page) | ||||||
|  */ |  */ | ||||||
| static inline void set_page_pfmemalloc(struct page *page) | static inline void set_page_pfmemalloc(struct page *page) | ||||||
| { | { | ||||||
| 	page->index = -1UL; | 	page->lru.next = (void *)BIT(1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline void clear_page_pfmemalloc(struct page *page) | static inline void clear_page_pfmemalloc(struct page *page) | ||||||
| { | { | ||||||
| 	page->index = 0; | 	page->lru.next = NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  |  | ||||||
|  | @ -96,6 +96,13 @@ struct page { | ||||||
| 			unsigned long private; | 			unsigned long private; | ||||||
| 		}; | 		}; | ||||||
| 		struct {	/* page_pool used by netstack */ | 		struct {	/* page_pool used by netstack */ | ||||||
|  | 			/**
 | ||||||
|  | 			 * @pp_magic: magic value to avoid recycling non | ||||||
|  | 			 * page_pool allocated pages. | ||||||
|  | 			 */ | ||||||
|  | 			unsigned long pp_magic; | ||||||
|  | 			struct page_pool *pp; | ||||||
|  | 			unsigned long _pp_mapping_pad; | ||||||
| 			/**
 | 			/**
 | ||||||
| 			 * @dma_addr: might require a 64-bit value on | 			 * @dma_addr: might require a 64-bit value on | ||||||
| 			 * 32-bit architectures. | 			 * 32-bit architectures. | ||||||
|  |  | ||||||
|  | @ -78,4 +78,7 @@ | ||||||
| /********** security/ **********/ | /********** security/ **********/ | ||||||
| #define KEY_DESTROY		0xbd | #define KEY_DESTROY		0xbd | ||||||
| 
 | 
 | ||||||
|  | /********** net/core/page_pool.c **********/ | ||||||
|  | #define PP_SIGNATURE		(0x40 + POISON_POINTER_DELTA) | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ | ||||||
| #include <linux/dma-mapping.h> | #include <linux/dma-mapping.h> | ||||||
| #include <linux/page-flags.h> | #include <linux/page-flags.h> | ||||||
| #include <linux/mm.h> /* for __put_page() */ | #include <linux/mm.h> /* for __put_page() */ | ||||||
|  | #include <linux/poison.h> | ||||||
| 
 | 
 | ||||||
| #include <trace/events/page_pool.h> | #include <trace/events/page_pool.h> | ||||||
| 
 | 
 | ||||||
|  | @ -221,6 +222,8 @@ static struct page *__page_pool_alloc_page_order(struct page_pool *pool, | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	page->pp_magic |= PP_SIGNATURE; | ||||||
|  | 
 | ||||||
| 	/* Track how many pages are held 'in-flight' */ | 	/* Track how many pages are held 'in-flight' */ | ||||||
| 	pool->pages_state_hold_cnt++; | 	pool->pages_state_hold_cnt++; | ||||||
| 	trace_page_pool_state_hold(pool, page, pool->pages_state_hold_cnt); | 	trace_page_pool_state_hold(pool, page, pool->pages_state_hold_cnt); | ||||||
|  | @ -263,6 +266,7 @@ static struct page *__page_pool_alloc_pages_slow(struct page_pool *pool, | ||||||
| 			put_page(page); | 			put_page(page); | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
|  | 		page->pp_magic |= PP_SIGNATURE; | ||||||
| 		pool->alloc.cache[pool->alloc.count++] = page; | 		pool->alloc.cache[pool->alloc.count++] = page; | ||||||
| 		/* Track how many pages are held 'in-flight' */ | 		/* Track how many pages are held 'in-flight' */ | ||||||
| 		pool->pages_state_hold_cnt++; | 		pool->pages_state_hold_cnt++; | ||||||
|  | @ -341,6 +345,8 @@ void page_pool_release_page(struct page_pool *pool, struct page *page) | ||||||
| 			     DMA_ATTR_SKIP_CPU_SYNC); | 			     DMA_ATTR_SKIP_CPU_SYNC); | ||||||
| 	page_pool_set_dma_addr(page, 0); | 	page_pool_set_dma_addr(page, 0); | ||||||
| skip_dma_unmap: | skip_dma_unmap: | ||||||
|  | 	page->pp_magic = 0; | ||||||
|  | 
 | ||||||
| 	/* This may be the last page returned, releasing the pool, so
 | 	/* This may be the last page returned, releasing the pool, so
 | ||||||
| 	 * it is not safe to reference pool afterwards. | 	 * it is not safe to reference pool afterwards. | ||||||
| 	 */ | 	 */ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Matteo Croce
						Matteo Croce