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