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