1*db0aa2e9SDavid Howells /* SPDX-License-Identifier: GPL-2.0-or-later */ 2*db0aa2e9SDavid Howells /* Queue of folios definitions 3*db0aa2e9SDavid Howells * 4*db0aa2e9SDavid Howells * Copyright (C) 2024 Red Hat, Inc. All Rights Reserved. 5*db0aa2e9SDavid Howells * Written by David Howells ([email protected]) 6*db0aa2e9SDavid Howells */ 7*db0aa2e9SDavid Howells 8*db0aa2e9SDavid Howells #ifndef _LINUX_FOLIO_QUEUE_H 9*db0aa2e9SDavid Howells #define _LINUX_FOLIO_QUEUE_H 10*db0aa2e9SDavid Howells 11*db0aa2e9SDavid Howells #include <linux/pagevec.h> 12*db0aa2e9SDavid Howells 13*db0aa2e9SDavid Howells /* 14*db0aa2e9SDavid Howells * Segment in a queue of running buffers. Each segment can hold a number of 15*db0aa2e9SDavid Howells * folios and a portion of the queue can be referenced with the ITER_FOLIOQ 16*db0aa2e9SDavid Howells * iterator. The possibility exists of inserting non-folio elements into the 17*db0aa2e9SDavid Howells * queue (such as gaps). 18*db0aa2e9SDavid Howells * 19*db0aa2e9SDavid Howells * Explicit prev and next pointers are used instead of a list_head to make it 20*db0aa2e9SDavid Howells * easier to add segments to tail and remove them from the head without the 21*db0aa2e9SDavid Howells * need for a lock. 22*db0aa2e9SDavid Howells */ 23*db0aa2e9SDavid Howells struct folio_queue { 24*db0aa2e9SDavid Howells struct folio_batch vec; /* Folios in the queue segment */ 25*db0aa2e9SDavid Howells u8 orders[PAGEVEC_SIZE]; /* Order of each folio */ 26*db0aa2e9SDavid Howells struct folio_queue *next; /* Next queue segment or NULL */ 27*db0aa2e9SDavid Howells struct folio_queue *prev; /* Previous queue segment of NULL */ 28*db0aa2e9SDavid Howells unsigned long marks; /* 1-bit mark per folio */ 29*db0aa2e9SDavid Howells unsigned long marks2; /* Second 1-bit mark per folio */ 30*db0aa2e9SDavid Howells #if PAGEVEC_SIZE > BITS_PER_LONG 31*db0aa2e9SDavid Howells #error marks is not big enough 32*db0aa2e9SDavid Howells #endif 33*db0aa2e9SDavid Howells }; 34*db0aa2e9SDavid Howells 35*db0aa2e9SDavid Howells static inline void folioq_init(struct folio_queue *folioq) 36*db0aa2e9SDavid Howells { 37*db0aa2e9SDavid Howells folio_batch_init(&folioq->vec); 38*db0aa2e9SDavid Howells folioq->next = NULL; 39*db0aa2e9SDavid Howells folioq->prev = NULL; 40*db0aa2e9SDavid Howells folioq->marks = 0; 41*db0aa2e9SDavid Howells folioq->marks2 = 0; 42*db0aa2e9SDavid Howells } 43*db0aa2e9SDavid Howells 44*db0aa2e9SDavid Howells static inline unsigned int folioq_nr_slots(const struct folio_queue *folioq) 45*db0aa2e9SDavid Howells { 46*db0aa2e9SDavid Howells return PAGEVEC_SIZE; 47*db0aa2e9SDavid Howells } 48*db0aa2e9SDavid Howells 49*db0aa2e9SDavid Howells static inline unsigned int folioq_count(struct folio_queue *folioq) 50*db0aa2e9SDavid Howells { 51*db0aa2e9SDavid Howells return folio_batch_count(&folioq->vec); 52*db0aa2e9SDavid Howells } 53*db0aa2e9SDavid Howells 54*db0aa2e9SDavid Howells static inline bool folioq_full(struct folio_queue *folioq) 55*db0aa2e9SDavid Howells { 56*db0aa2e9SDavid Howells //return !folio_batch_space(&folioq->vec); 57*db0aa2e9SDavid Howells return folioq_count(folioq) >= folioq_nr_slots(folioq); 58*db0aa2e9SDavid Howells } 59*db0aa2e9SDavid Howells 60*db0aa2e9SDavid Howells static inline bool folioq_is_marked(const struct folio_queue *folioq, unsigned int slot) 61*db0aa2e9SDavid Howells { 62*db0aa2e9SDavid Howells return test_bit(slot, &folioq->marks); 63*db0aa2e9SDavid Howells } 64*db0aa2e9SDavid Howells 65*db0aa2e9SDavid Howells static inline void folioq_mark(struct folio_queue *folioq, unsigned int slot) 66*db0aa2e9SDavid Howells { 67*db0aa2e9SDavid Howells set_bit(slot, &folioq->marks); 68*db0aa2e9SDavid Howells } 69*db0aa2e9SDavid Howells 70*db0aa2e9SDavid Howells static inline void folioq_unmark(struct folio_queue *folioq, unsigned int slot) 71*db0aa2e9SDavid Howells { 72*db0aa2e9SDavid Howells clear_bit(slot, &folioq->marks); 73*db0aa2e9SDavid Howells } 74*db0aa2e9SDavid Howells 75*db0aa2e9SDavid Howells static inline bool folioq_is_marked2(const struct folio_queue *folioq, unsigned int slot) 76*db0aa2e9SDavid Howells { 77*db0aa2e9SDavid Howells return test_bit(slot, &folioq->marks2); 78*db0aa2e9SDavid Howells } 79*db0aa2e9SDavid Howells 80*db0aa2e9SDavid Howells static inline void folioq_mark2(struct folio_queue *folioq, unsigned int slot) 81*db0aa2e9SDavid Howells { 82*db0aa2e9SDavid Howells set_bit(slot, &folioq->marks2); 83*db0aa2e9SDavid Howells } 84*db0aa2e9SDavid Howells 85*db0aa2e9SDavid Howells static inline void folioq_unmark2(struct folio_queue *folioq, unsigned int slot) 86*db0aa2e9SDavid Howells { 87*db0aa2e9SDavid Howells clear_bit(slot, &folioq->marks2); 88*db0aa2e9SDavid Howells } 89*db0aa2e9SDavid Howells 90*db0aa2e9SDavid Howells static inline unsigned int __folio_order(struct folio *folio) 91*db0aa2e9SDavid Howells { 92*db0aa2e9SDavid Howells if (!folio_test_large(folio)) 93*db0aa2e9SDavid Howells return 0; 94*db0aa2e9SDavid Howells return folio->_flags_1 & 0xff; 95*db0aa2e9SDavid Howells } 96*db0aa2e9SDavid Howells 97*db0aa2e9SDavid Howells static inline unsigned int folioq_append(struct folio_queue *folioq, struct folio *folio) 98*db0aa2e9SDavid Howells { 99*db0aa2e9SDavid Howells unsigned int slot = folioq->vec.nr++; 100*db0aa2e9SDavid Howells 101*db0aa2e9SDavid Howells folioq->vec.folios[slot] = folio; 102*db0aa2e9SDavid Howells folioq->orders[slot] = __folio_order(folio); 103*db0aa2e9SDavid Howells return slot; 104*db0aa2e9SDavid Howells } 105*db0aa2e9SDavid Howells 106*db0aa2e9SDavid Howells static inline unsigned int folioq_append_mark(struct folio_queue *folioq, struct folio *folio) 107*db0aa2e9SDavid Howells { 108*db0aa2e9SDavid Howells unsigned int slot = folioq->vec.nr++; 109*db0aa2e9SDavid Howells 110*db0aa2e9SDavid Howells folioq->vec.folios[slot] = folio; 111*db0aa2e9SDavid Howells folioq->orders[slot] = __folio_order(folio); 112*db0aa2e9SDavid Howells folioq_mark(folioq, slot); 113*db0aa2e9SDavid Howells return slot; 114*db0aa2e9SDavid Howells } 115*db0aa2e9SDavid Howells 116*db0aa2e9SDavid Howells static inline struct folio *folioq_folio(const struct folio_queue *folioq, unsigned int slot) 117*db0aa2e9SDavid Howells { 118*db0aa2e9SDavid Howells return folioq->vec.folios[slot]; 119*db0aa2e9SDavid Howells } 120*db0aa2e9SDavid Howells 121*db0aa2e9SDavid Howells static inline unsigned int folioq_folio_order(const struct folio_queue *folioq, unsigned int slot) 122*db0aa2e9SDavid Howells { 123*db0aa2e9SDavid Howells return folioq->orders[slot]; 124*db0aa2e9SDavid Howells } 125*db0aa2e9SDavid Howells 126*db0aa2e9SDavid Howells static inline size_t folioq_folio_size(const struct folio_queue *folioq, unsigned int slot) 127*db0aa2e9SDavid Howells { 128*db0aa2e9SDavid Howells return PAGE_SIZE << folioq_folio_order(folioq, slot); 129*db0aa2e9SDavid Howells } 130*db0aa2e9SDavid Howells 131*db0aa2e9SDavid Howells static inline void folioq_clear(struct folio_queue *folioq, unsigned int slot) 132*db0aa2e9SDavid Howells { 133*db0aa2e9SDavid Howells folioq->vec.folios[slot] = NULL; 134*db0aa2e9SDavid Howells folioq_unmark(folioq, slot); 135*db0aa2e9SDavid Howells folioq_unmark2(folioq, slot); 136*db0aa2e9SDavid Howells } 137*db0aa2e9SDavid Howells 138*db0aa2e9SDavid Howells #endif /* _LINUX_FOLIO_QUEUE_H */ 139