Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/* Queue of folios definitions
3 *
4 * Copyright (C) 2024 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
6 *
7 * See:
8 *
9 * Documentation/core-api/folio_queue.rst
10 *
11 * for a description of the API.
12 */
13
14#ifndef _LINUX_FOLIO_QUEUE_H
15#define _LINUX_FOLIO_QUEUE_H
16
17#include <linux/pagevec.h>
18
19/*
20 * Segment in a queue of running buffers. Each segment can hold a number of
21 * folios and a portion of the queue can be referenced with the ITER_FOLIOQ
22 * iterator. The possibility exists of inserting non-folio elements into the
23 * queue (such as gaps).
24 *
25 * Explicit prev and next pointers are used instead of a list_head to make it
26 * easier to add segments to tail and remove them from the head without the
27 * need for a lock.
28 */
29struct folio_queue {
30 struct folio_batch vec; /* Folios in the queue segment */
31 u8 orders[PAGEVEC_SIZE]; /* Order of each folio */
32 struct folio_queue *next; /* Next queue segment or NULL */
33 struct folio_queue *prev; /* Previous queue segment of NULL */
34 unsigned long marks; /* 1-bit mark per folio */
35 unsigned long marks2; /* Second 1-bit mark per folio */
36 unsigned long marks3; /* Third 1-bit mark per folio */
37#if PAGEVEC_SIZE > BITS_PER_LONG
38#error marks is not big enough
39#endif
40};
41
42/**
43 * folioq_init - Initialise a folio queue segment
44 * @folioq: The segment to initialise
45 *
46 * Initialise a folio queue segment. Note that the folio pointers are
47 * left uninitialised.
48 */
49static inline void folioq_init(struct folio_queue *folioq)
50{
51 folio_batch_init(&folioq->vec);
52 folioq->next = NULL;
53 folioq->prev = NULL;
54 folioq->marks = 0;
55 folioq->marks2 = 0;
56 folioq->marks3 = 0;
57}
58
59/**
60 * folioq_nr_slots: Query the capacity of a folio queue segment
61 * @folioq: The segment to query
62 *
63 * Query the number of folios that a particular folio queue segment might hold.
64 * [!] NOTE: This must not be assumed to be the same for every segment!
65 */
66static inline unsigned int folioq_nr_slots(const struct folio_queue *folioq)
67{
68 return PAGEVEC_SIZE;
69}
70
71/**
72 * folioq_count: Query the occupancy of a folio queue segment
73 * @folioq: The segment to query
74 *
75 * Query the number of folios that have been added to a folio queue segment.
76 * Note that this is not decreased as folios are removed from a segment.
77 */
78static inline unsigned int folioq_count(struct folio_queue *folioq)
79{
80 return folio_batch_count(&folioq->vec);
81}
82
83/**
84 * folioq_full: Query if a folio queue segment is full
85 * @folioq: The segment to query
86 *
87 * Query if a folio queue segment is fully occupied. Note that this does not
88 * change if folios are removed from a segment.
89 */
90static inline bool folioq_full(struct folio_queue *folioq)
91{
92 //return !folio_batch_space(&folioq->vec);
93 return folioq_count(folioq) >= folioq_nr_slots(folioq);
94}
95
96/**
97 * folioq_is_marked: Check first folio mark in a folio queue segment
98 * @folioq: The segment to query
99 * @slot: The slot number of the folio to query
100 *
101 * Determine if the first mark is set for the folio in the specified slot in a
102 * folio queue segment.
103 */
104static inline bool folioq_is_marked(const struct folio_queue *folioq, unsigned int slot)
105{
106 return test_bit(slot, &folioq->marks);
107}
108
109/**
110 * folioq_mark: Set the first mark on a folio in a folio queue segment
111 * @folioq: The segment to modify
112 * @slot: The slot number of the folio to modify
113 *
114 * Set the first mark for the folio in the specified slot in a folio queue
115 * segment.
116 */
117static inline void folioq_mark(struct folio_queue *folioq, unsigned int slot)
118{
119 set_bit(slot, &folioq->marks);
120}
121
122/**
123 * folioq_unmark: Clear the first mark on a folio in a folio queue segment
124 * @folioq: The segment to modify
125 * @slot: The slot number of the folio to modify
126 *
127 * Clear the first mark for the folio in the specified slot in a folio queue
128 * segment.
129 */
130static inline void folioq_unmark(struct folio_queue *folioq, unsigned int slot)
131{
132 clear_bit(slot, &folioq->marks);
133}
134
135/**
136 * folioq_is_marked2: Check second folio mark in a folio queue segment
137 * @folioq: The segment to query
138 * @slot: The slot number of the folio to query
139 *
140 * Determine if the second mark is set for the folio in the specified slot in a
141 * folio queue segment.
142 */
143static inline bool folioq_is_marked2(const struct folio_queue *folioq, unsigned int slot)
144{
145 return test_bit(slot, &folioq->marks2);
146}
147
148/**
149 * folioq_mark2: Set the second mark on a folio in a folio queue segment
150 * @folioq: The segment to modify
151 * @slot: The slot number of the folio to modify
152 *
153 * Set the second mark for the folio in the specified slot in a folio queue
154 * segment.
155 */
156static inline void folioq_mark2(struct folio_queue *folioq, unsigned int slot)
157{
158 set_bit(slot, &folioq->marks2);
159}
160
161/**
162 * folioq_unmark2: Clear the second mark on a folio in a folio queue segment
163 * @folioq: The segment to modify
164 * @slot: The slot number of the folio to modify
165 *
166 * Clear the second mark for the folio in the specified slot in a folio queue
167 * segment.
168 */
169static inline void folioq_unmark2(struct folio_queue *folioq, unsigned int slot)
170{
171 clear_bit(slot, &folioq->marks2);
172}
173
174/**
175 * folioq_is_marked3: Check third folio mark in a folio queue segment
176 * @folioq: The segment to query
177 * @slot: The slot number of the folio to query
178 *
179 * Determine if the third mark is set for the folio in the specified slot in a
180 * folio queue segment.
181 */
182static inline bool folioq_is_marked3(const struct folio_queue *folioq, unsigned int slot)
183{
184 return test_bit(slot, &folioq->marks3);
185}
186
187/**
188 * folioq_mark3: Set the third mark on a folio in a folio queue segment
189 * @folioq: The segment to modify
190 * @slot: The slot number of the folio to modify
191 *
192 * Set the third mark for the folio in the specified slot in a folio queue
193 * segment.
194 */
195static inline void folioq_mark3(struct folio_queue *folioq, unsigned int slot)
196{
197 set_bit(slot, &folioq->marks3);
198}
199
200/**
201 * folioq_unmark3: Clear the third mark on a folio in a folio queue segment
202 * @folioq: The segment to modify
203 * @slot: The slot number of the folio to modify
204 *
205 * Clear the third mark for the folio in the specified slot in a folio queue
206 * segment.
207 */
208static inline void folioq_unmark3(struct folio_queue *folioq, unsigned int slot)
209{
210 clear_bit(slot, &folioq->marks3);
211}
212
213static inline unsigned int __folio_order(struct folio *folio)
214{
215 if (!folio_test_large(folio))
216 return 0;
217 return folio->_flags_1 & 0xff;
218}
219
220/**
221 * folioq_append: Add a folio to a folio queue segment
222 * @folioq: The segment to add to
223 * @folio: The folio to add
224 *
225 * Add a folio to the tail of the sequence in a folio queue segment, increasing
226 * the occupancy count and returning the slot number for the folio just added.
227 * The folio size is extracted and stored in the queue and the marks are left
228 * unmodified.
229 *
230 * Note that it's left up to the caller to check that the segment capacity will
231 * not be exceeded and to extend the queue.
232 */
233static inline unsigned int folioq_append(struct folio_queue *folioq, struct folio *folio)
234{
235 unsigned int slot = folioq->vec.nr++;
236
237 folioq->vec.folios[slot] = folio;
238 folioq->orders[slot] = __folio_order(folio);
239 return slot;
240}
241
242/**
243 * folioq_append_mark: Add a folio to a folio queue segment
244 * @folioq: The segment to add to
245 * @folio: The folio to add
246 *
247 * Add a folio to the tail of the sequence in a folio queue segment, increasing
248 * the occupancy count and returning the slot number for the folio just added.
249 * The folio size is extracted and stored in the queue, the first mark is set
250 * and and the second and third marks are left unmodified.
251 *
252 * Note that it's left up to the caller to check that the segment capacity will
253 * not be exceeded and to extend the queue.
254 */
255static inline unsigned int folioq_append_mark(struct folio_queue *folioq, struct folio *folio)
256{
257 unsigned int slot = folioq->vec.nr++;
258
259 folioq->vec.folios[slot] = folio;
260 folioq->orders[slot] = __folio_order(folio);
261 folioq_mark(folioq, slot);
262 return slot;
263}
264
265/**
266 * folioq_folio: Get a folio from a folio queue segment
267 * @folioq: The segment to access
268 * @slot: The folio slot to access
269 *
270 * Retrieve the folio in the specified slot from a folio queue segment. Note
271 * that no bounds check is made and if the slot hasn't been added into yet, the
272 * pointer will be undefined. If the slot has been cleared, NULL will be
273 * returned.
274 */
275static inline struct folio *folioq_folio(const struct folio_queue *folioq, unsigned int slot)
276{
277 return folioq->vec.folios[slot];
278}
279
280/**
281 * folioq_folio_order: Get the order of a folio from a folio queue segment
282 * @folioq: The segment to access
283 * @slot: The folio slot to access
284 *
285 * Retrieve the order of the folio in the specified slot from a folio queue
286 * segment. Note that no bounds check is made and if the slot hasn't been
287 * added into yet, the order returned will be 0.
288 */
289static inline unsigned int folioq_folio_order(const struct folio_queue *folioq, unsigned int slot)
290{
291 return folioq->orders[slot];
292}
293
294/**
295 * folioq_folio_size: Get the size of a folio from a folio queue segment
296 * @folioq: The segment to access
297 * @slot: The folio slot to access
298 *
299 * Retrieve the size of the folio in the specified slot from a folio queue
300 * segment. Note that no bounds check is made and if the slot hasn't been
301 * added into yet, the size returned will be PAGE_SIZE.
302 */
303static inline size_t folioq_folio_size(const struct folio_queue *folioq, unsigned int slot)
304{
305 return PAGE_SIZE << folioq_folio_order(folioq, slot);
306}
307
308/**
309 * folioq_clear: Clear a folio from a folio queue segment
310 * @folioq: The segment to clear
311 * @slot: The folio slot to clear
312 *
313 * Clear a folio from a sequence in a folio queue segment and clear its marks.
314 * The occupancy count is left unchanged.
315 */
316static inline void folioq_clear(struct folio_queue *folioq, unsigned int slot)
317{
318 folioq->vec.folios[slot] = NULL;
319 folioq_unmark(folioq, slot);
320 folioq_unmark2(folioq, slot);
321 folioq_unmark3(folioq, slot);
322}
323
324#endif /* _LINUX_FOLIO_QUEUE_H */