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