165941f10SYunsheng Lin /* SPDX-License-Identifier: GPL-2.0 */
265941f10SYunsheng Lin 
365941f10SYunsheng Lin #ifndef _LINUX_PAGE_FRAG_CACHE_H
465941f10SYunsheng Lin #define _LINUX_PAGE_FRAG_CACHE_H
565941f10SYunsheng Lin 
6*0c3ce2f5SYunsheng Lin #include <linux/bits.h>
765941f10SYunsheng Lin #include <linux/log2.h>
865941f10SYunsheng Lin #include <linux/mm_types_task.h>
965941f10SYunsheng Lin #include <linux/types.h>
1065941f10SYunsheng Lin 
11*0c3ce2f5SYunsheng Lin #if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE)
12*0c3ce2f5SYunsheng Lin /* Use a full byte here to enable assembler optimization as the shift
13*0c3ce2f5SYunsheng Lin  * operation is usually expecting a byte.
14*0c3ce2f5SYunsheng Lin  */
15*0c3ce2f5SYunsheng Lin #define PAGE_FRAG_CACHE_ORDER_MASK		GENMASK(7, 0)
16*0c3ce2f5SYunsheng Lin #else
17*0c3ce2f5SYunsheng Lin /* Compiler should be able to figure out we don't read things as any value
18*0c3ce2f5SYunsheng Lin  * ANDed with 0 is 0.
19*0c3ce2f5SYunsheng Lin  */
20*0c3ce2f5SYunsheng Lin #define PAGE_FRAG_CACHE_ORDER_MASK		0
21*0c3ce2f5SYunsheng Lin #endif
22*0c3ce2f5SYunsheng Lin 
23*0c3ce2f5SYunsheng Lin #define PAGE_FRAG_CACHE_PFMEMALLOC_BIT		(PAGE_FRAG_CACHE_ORDER_MASK + 1)
24*0c3ce2f5SYunsheng Lin 
encoded_page_decode_pfmemalloc(unsigned long encoded_page)25*0c3ce2f5SYunsheng Lin static inline bool encoded_page_decode_pfmemalloc(unsigned long encoded_page)
26*0c3ce2f5SYunsheng Lin {
27*0c3ce2f5SYunsheng Lin 	return !!(encoded_page & PAGE_FRAG_CACHE_PFMEMALLOC_BIT);
28*0c3ce2f5SYunsheng Lin }
29*0c3ce2f5SYunsheng Lin 
page_frag_cache_init(struct page_frag_cache * nc)303d18dfe6SYunsheng Lin static inline void page_frag_cache_init(struct page_frag_cache *nc)
313d18dfe6SYunsheng Lin {
32*0c3ce2f5SYunsheng Lin 	nc->encoded_page = 0;
333d18dfe6SYunsheng Lin }
343d18dfe6SYunsheng Lin 
page_frag_cache_is_pfmemalloc(struct page_frag_cache * nc)353d18dfe6SYunsheng Lin static inline bool page_frag_cache_is_pfmemalloc(struct page_frag_cache *nc)
363d18dfe6SYunsheng Lin {
37*0c3ce2f5SYunsheng Lin 	return encoded_page_decode_pfmemalloc(nc->encoded_page);
383d18dfe6SYunsheng Lin }
393d18dfe6SYunsheng Lin 
4065941f10SYunsheng Lin void page_frag_cache_drain(struct page_frag_cache *nc);
4165941f10SYunsheng Lin void __page_frag_cache_drain(struct page *page, unsigned int count);
4265941f10SYunsheng Lin void *__page_frag_alloc_align(struct page_frag_cache *nc, unsigned int fragsz,
4365941f10SYunsheng Lin 			      gfp_t gfp_mask, unsigned int align_mask);
4465941f10SYunsheng Lin 
page_frag_alloc_align(struct page_frag_cache * nc,unsigned int fragsz,gfp_t gfp_mask,unsigned int align)4565941f10SYunsheng Lin static inline void *page_frag_alloc_align(struct page_frag_cache *nc,
4665941f10SYunsheng Lin 					  unsigned int fragsz, gfp_t gfp_mask,
4765941f10SYunsheng Lin 					  unsigned int align)
4865941f10SYunsheng Lin {
4965941f10SYunsheng Lin 	WARN_ON_ONCE(!is_power_of_2(align));
5065941f10SYunsheng Lin 	return __page_frag_alloc_align(nc, fragsz, gfp_mask, -align);
5165941f10SYunsheng Lin }
5265941f10SYunsheng Lin 
page_frag_alloc(struct page_frag_cache * nc,unsigned int fragsz,gfp_t gfp_mask)5365941f10SYunsheng Lin static inline void *page_frag_alloc(struct page_frag_cache *nc,
5465941f10SYunsheng Lin 				    unsigned int fragsz, gfp_t gfp_mask)
5565941f10SYunsheng Lin {
5665941f10SYunsheng Lin 	return __page_frag_alloc_align(nc, fragsz, gfp_mask, ~0u);
5765941f10SYunsheng Lin }
5865941f10SYunsheng Lin 
5965941f10SYunsheng Lin void page_frag_free(void *addr);
6065941f10SYunsheng Lin 
6165941f10SYunsheng Lin #endif
62