1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * include/linux/pagevec.h 4 * 5 * In many places it is efficient to batch an operation up against multiple 6 * pages. A pagevec is a multipage container which is used for that. 7 */ 8 9 #ifndef _LINUX_PAGEVEC_H 10 #define _LINUX_PAGEVEC_H 11 12 #include <linux/xarray.h> 13 14 /* 15 pointers + header align the pagevec structure to a power of two */ 15 #define PAGEVEC_SIZE 15 16 17 struct page; 18 struct folio; 19 struct address_space; 20 21 /* Layout must match folio_batch */ 22 struct pagevec { 23 unsigned char nr; 24 bool percpu_pvec_drained; 25 struct page *pages[PAGEVEC_SIZE]; 26 }; 27 28 void __pagevec_release(struct pagevec *pvec); 29 pagevec_init(struct pagevec * pvec)30static inline void pagevec_init(struct pagevec *pvec) 31 { 32 pvec->nr = 0; 33 pvec->percpu_pvec_drained = false; 34 } 35 pagevec_reinit(struct pagevec * pvec)36static inline void pagevec_reinit(struct pagevec *pvec) 37 { 38 pvec->nr = 0; 39 } 40 pagevec_count(struct pagevec * pvec)41static inline unsigned pagevec_count(struct pagevec *pvec) 42 { 43 return pvec->nr; 44 } 45 pagevec_space(struct pagevec * pvec)46static inline unsigned pagevec_space(struct pagevec *pvec) 47 { 48 return PAGEVEC_SIZE - pvec->nr; 49 } 50 51 /* 52 * Add a page to a pagevec. Returns the number of slots still available. 53 */ pagevec_add(struct pagevec * pvec,struct page * page)54static inline unsigned pagevec_add(struct pagevec *pvec, struct page *page) 55 { 56 pvec->pages[pvec->nr++] = page; 57 return pagevec_space(pvec); 58 } 59 pagevec_release(struct pagevec * pvec)60static inline void pagevec_release(struct pagevec *pvec) 61 { 62 if (pagevec_count(pvec)) 63 __pagevec_release(pvec); 64 } 65 66 /** 67 * struct folio_batch - A collection of folios. 68 * 69 * The folio_batch is used to amortise the cost of retrieving and 70 * operating on a set of folios. The order of folios in the batch may be 71 * significant (eg delete_from_page_cache_batch()). Some users of the 72 * folio_batch store "exceptional" entries in it which can be removed 73 * by calling folio_batch_remove_exceptionals(). 74 */ 75 struct folio_batch { 76 unsigned char nr; 77 bool percpu_pvec_drained; 78 struct folio *folios[PAGEVEC_SIZE]; 79 }; 80 81 /* Layout must match pagevec */ 82 static_assert(sizeof(struct pagevec) == sizeof(struct folio_batch)); 83 static_assert(offsetof(struct pagevec, pages) == 84 offsetof(struct folio_batch, folios)); 85 86 /** 87 * folio_batch_init() - Initialise a batch of folios 88 * @fbatch: The folio batch. 89 * 90 * A freshly initialised folio_batch contains zero folios. 91 */ folio_batch_init(struct folio_batch * fbatch)92static inline void folio_batch_init(struct folio_batch *fbatch) 93 { 94 fbatch->nr = 0; 95 fbatch->percpu_pvec_drained = false; 96 } 97 folio_batch_reinit(struct folio_batch * fbatch)98static inline void folio_batch_reinit(struct folio_batch *fbatch) 99 { 100 fbatch->nr = 0; 101 } 102 folio_batch_count(struct folio_batch * fbatch)103static inline unsigned int folio_batch_count(struct folio_batch *fbatch) 104 { 105 return fbatch->nr; 106 } 107 fbatch_space(struct folio_batch * fbatch)108static inline unsigned int fbatch_space(struct folio_batch *fbatch) 109 { 110 return PAGEVEC_SIZE - fbatch->nr; 111 } 112 113 /** 114 * folio_batch_add() - Add a folio to a batch. 115 * @fbatch: The folio batch. 116 * @folio: The folio to add. 117 * 118 * The folio is added to the end of the batch. 119 * The batch must have previously been initialised using folio_batch_init(). 120 * 121 * Return: The number of slots still available. 122 */ folio_batch_add(struct folio_batch * fbatch,struct folio * folio)123static inline unsigned folio_batch_add(struct folio_batch *fbatch, 124 struct folio *folio) 125 { 126 fbatch->folios[fbatch->nr++] = folio; 127 return fbatch_space(fbatch); 128 } 129 folio_batch_release(struct folio_batch * fbatch)130static inline void folio_batch_release(struct folio_batch *fbatch) 131 { 132 pagevec_release((struct pagevec *)fbatch); 133 } 134 135 void folio_batch_remove_exceptionals(struct folio_batch *fbatch); 136 #endif /* _LINUX_PAGEVEC_H */ 137