xref: /linux-6.15/include/linux/folio_queue.h (revision db0aa2e9)
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