1fe267a55SPedro F. Giffuni /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni *
4774d251dSAttilio Rao * Copyright (c) 2013 EMC Corp.
5774d251dSAttilio Rao * Copyright (c) 2011 Jeffrey Roberson <jeff@freebsd.org>
6774d251dSAttilio Rao * Copyright (c) 2008 Mayur Shardul <mayur.shardul@gmail.com>
7774d251dSAttilio Rao * All rights reserved.
8774d251dSAttilio Rao *
9774d251dSAttilio Rao * Redistribution and use in source and binary forms, with or without
10774d251dSAttilio Rao * modification, are permitted provided that the following conditions
11774d251dSAttilio Rao * are met:
12774d251dSAttilio Rao * 1. Redistributions of source code must retain the above copyright
13774d251dSAttilio Rao * notice, this list of conditions and the following disclaimer.
14774d251dSAttilio Rao * 2. Redistributions in binary form must reproduce the above copyright
15774d251dSAttilio Rao * notice, this list of conditions and the following disclaimer in the
16774d251dSAttilio Rao * documentation and/or other materials provided with the distribution.
17774d251dSAttilio Rao *
18774d251dSAttilio Rao * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19774d251dSAttilio Rao * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20774d251dSAttilio Rao * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21774d251dSAttilio Rao * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22774d251dSAttilio Rao * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23774d251dSAttilio Rao * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24774d251dSAttilio Rao * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25774d251dSAttilio Rao * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26774d251dSAttilio Rao * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27774d251dSAttilio Rao * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28774d251dSAttilio Rao * SUCH DAMAGE.
29774d251dSAttilio Rao */
30774d251dSAttilio Rao
31774d251dSAttilio Rao #ifndef _VM_RADIX_H_
32774d251dSAttilio Rao #define _VM_RADIX_H_
33774d251dSAttilio Rao
34774d251dSAttilio Rao #include <vm/_vm_radix.h>
35774d251dSAttilio Rao
36774d251dSAttilio Rao #ifdef _KERNEL
37429c871dSDoug Moore #include <sys/pctrie.h>
38429c871dSDoug Moore #include <vm/vm_page.h>
39429c871dSDoug Moore #include <vm/vm.h>
40774d251dSAttilio Rao
418d6fbbb8SJeff Roberson void vm_radix_wait(void);
42cd1241fbSKonstantin Belousov void vm_radix_zinit(void);
43429c871dSDoug Moore void *vm_radix_node_alloc(struct pctrie *ptree);
44429c871dSDoug Moore void vm_radix_node_free(struct pctrie *ptree, void *node);
45429c871dSDoug Moore extern smr_t vm_radix_smr;
462d2bcba7SDoug Moore
47cd1241fbSKonstantin Belousov static __inline void
vm_radix_init(struct vm_radix * rtree)48cd1241fbSKonstantin Belousov vm_radix_init(struct vm_radix *rtree)
49cd1241fbSKonstantin Belousov {
50429c871dSDoug Moore pctrie_init(&rtree->rt_trie);
51cd1241fbSKonstantin Belousov }
52cd1241fbSKonstantin Belousov
531efa7dbcSDoug Moore static __inline bool
vm_radix_is_empty(struct vm_radix * rtree)54cd1241fbSKonstantin Belousov vm_radix_is_empty(struct vm_radix *rtree)
55cd1241fbSKonstantin Belousov {
56429c871dSDoug Moore return (pctrie_is_empty(&rtree->rt_trie));
57429c871dSDoug Moore }
58429c871dSDoug Moore
59450a6690SDoug Moore PCTRIE_DEFINE_SMR(VM_RADIX, vm_page, pindex, vm_radix_node_alloc,
60450a6690SDoug Moore vm_radix_node_free, vm_radix_smr);
61429c871dSDoug Moore
62429c871dSDoug Moore /*
63c71c41daSDoug Moore * Inserts the key-value pair into the trie, starting search from root.
64429c871dSDoug Moore * Panics if the key already exists.
65429c871dSDoug Moore */
66429c871dSDoug Moore static __inline int
vm_radix_insert(struct vm_radix * rtree,vm_page_t page)67429c871dSDoug Moore vm_radix_insert(struct vm_radix *rtree, vm_page_t page)
68429c871dSDoug Moore {
69429c871dSDoug Moore return (VM_RADIX_PCTRIE_INSERT(&rtree->rt_trie, page));
70429c871dSDoug Moore }
71429c871dSDoug Moore
72429c871dSDoug Moore /*
73c71c41daSDoug Moore * Inserts the key-value pair into the trie, starting search from iterator.
74c71c41daSDoug Moore * Panics if the key already exists.
75c71c41daSDoug Moore */
76c71c41daSDoug Moore static __inline int
vm_radix_iter_insert(struct pctrie_iter * pages,vm_page_t page)77c71c41daSDoug Moore vm_radix_iter_insert(struct pctrie_iter *pages, vm_page_t page)
78c71c41daSDoug Moore {
79c71c41daSDoug Moore return (VM_RADIX_PCTRIE_ITER_INSERT(pages, page));
80c71c41daSDoug Moore }
81c71c41daSDoug Moore
82c71c41daSDoug Moore /*
837658d153SRyan Libby * Insert the page into the vm_radix tree with its pindex as the key. Panic if
847658d153SRyan Libby * the pindex already exists. Return zero on success or a non-zero error on
857658d153SRyan Libby * memory allocation failure. Set the out parameter mpred to the previous page
867658d153SRyan Libby * in the tree as if found by a previous call to vm_radix_lookup_le with the
877658d153SRyan Libby * new page pindex.
887658d153SRyan Libby */
897658d153SRyan Libby static __inline int
vm_radix_insert_lookup_lt(struct vm_radix * rtree,vm_page_t page,vm_page_t * mpred)907658d153SRyan Libby vm_radix_insert_lookup_lt(struct vm_radix *rtree, vm_page_t page,
917658d153SRyan Libby vm_page_t *mpred)
927658d153SRyan Libby {
937658d153SRyan Libby int error;
947658d153SRyan Libby
957658d153SRyan Libby error = VM_RADIX_PCTRIE_INSERT_LOOKUP_LE(&rtree->rt_trie, page, mpred);
967658d153SRyan Libby if (__predict_false(error == EEXIST))
977658d153SRyan Libby panic("vm_radix_insert_lookup_lt: page already present, %p",
987658d153SRyan Libby *mpred);
997658d153SRyan Libby return (error);
1007658d153SRyan Libby }
1017658d153SRyan Libby
1027658d153SRyan Libby /*
103429c871dSDoug Moore * Returns the value stored at the index assuming there is an external lock.
104429c871dSDoug Moore *
105429c871dSDoug Moore * If the index is not present, NULL is returned.
106429c871dSDoug Moore */
107429c871dSDoug Moore static __inline vm_page_t
vm_radix_lookup(struct vm_radix * rtree,vm_pindex_t index)108429c871dSDoug Moore vm_radix_lookup(struct vm_radix *rtree, vm_pindex_t index)
109429c871dSDoug Moore {
110429c871dSDoug Moore return (VM_RADIX_PCTRIE_LOOKUP(&rtree->rt_trie, index));
111429c871dSDoug Moore }
112429c871dSDoug Moore
113429c871dSDoug Moore /*
114429c871dSDoug Moore * Returns the value stored at the index without requiring an external lock.
115429c871dSDoug Moore *
116429c871dSDoug Moore * If the index is not present, NULL is returned.
117429c871dSDoug Moore */
118429c871dSDoug Moore static __inline vm_page_t
vm_radix_lookup_unlocked(struct vm_radix * rtree,vm_pindex_t index)119429c871dSDoug Moore vm_radix_lookup_unlocked(struct vm_radix *rtree, vm_pindex_t index)
120429c871dSDoug Moore {
121429c871dSDoug Moore return (VM_RADIX_PCTRIE_LOOKUP_UNLOCKED(&rtree->rt_trie, index));
122429c871dSDoug Moore }
123429c871dSDoug Moore
124429c871dSDoug Moore /*
125450a6690SDoug Moore * Initialize an iterator for vm_radix.
126450a6690SDoug Moore */
127450a6690SDoug Moore static __inline void
vm_radix_iter_init(struct pctrie_iter * pages,struct vm_radix * rtree)128450a6690SDoug Moore vm_radix_iter_init(struct pctrie_iter *pages, struct vm_radix *rtree)
129450a6690SDoug Moore {
130450a6690SDoug Moore pctrie_iter_init(pages, &rtree->rt_trie);
131450a6690SDoug Moore }
132450a6690SDoug Moore
133450a6690SDoug Moore /*
134450a6690SDoug Moore * Initialize an iterator for vm_radix.
135450a6690SDoug Moore */
136450a6690SDoug Moore static __inline void
vm_radix_iter_limit_init(struct pctrie_iter * pages,struct vm_radix * rtree,vm_pindex_t limit)137450a6690SDoug Moore vm_radix_iter_limit_init(struct pctrie_iter *pages, struct vm_radix *rtree,
138450a6690SDoug Moore vm_pindex_t limit)
139450a6690SDoug Moore {
140450a6690SDoug Moore pctrie_iter_limit_init(pages, &rtree->rt_trie, limit);
141450a6690SDoug Moore }
142450a6690SDoug Moore
143450a6690SDoug Moore /*
144450a6690SDoug Moore * Returns the value stored at the index.
145450a6690SDoug Moore * Requires that access be externally synchronized by a lock.
146450a6690SDoug Moore *
147450a6690SDoug Moore * If the index is not present, NULL is returned.
148450a6690SDoug Moore */
149450a6690SDoug Moore static __inline vm_page_t
vm_radix_iter_lookup(struct pctrie_iter * pages,vm_pindex_t index)150450a6690SDoug Moore vm_radix_iter_lookup(struct pctrie_iter *pages, vm_pindex_t index)
151450a6690SDoug Moore {
152450a6690SDoug Moore return (VM_RADIX_PCTRIE_ITER_LOOKUP(pages, index));
153450a6690SDoug Moore }
154450a6690SDoug Moore
155450a6690SDoug Moore /*
156450a6690SDoug Moore * Returns the value stored 'stride' steps beyond the current position.
157450a6690SDoug Moore * Requires that access be externally synchronized by a lock.
158450a6690SDoug Moore *
159450a6690SDoug Moore * If the index is not present, NULL is returned.
160450a6690SDoug Moore */
161450a6690SDoug Moore static __inline vm_page_t
vm_radix_iter_stride(struct pctrie_iter * pages,int stride)162450a6690SDoug Moore vm_radix_iter_stride(struct pctrie_iter *pages, int stride)
163450a6690SDoug Moore {
164450a6690SDoug Moore return (VM_RADIX_PCTRIE_ITER_STRIDE(pages, stride));
165450a6690SDoug Moore }
166450a6690SDoug Moore
167450a6690SDoug Moore /*
168429c871dSDoug Moore * Returns the page with the least pindex that is greater than or equal to the
169429c871dSDoug Moore * specified pindex, or NULL if there are no such pages.
170429c871dSDoug Moore *
171429c871dSDoug Moore * Requires that access be externally synchronized by a lock.
172429c871dSDoug Moore */
173429c871dSDoug Moore static __inline vm_page_t
vm_radix_lookup_ge(struct vm_radix * rtree,vm_pindex_t index)174429c871dSDoug Moore vm_radix_lookup_ge(struct vm_radix *rtree, vm_pindex_t index)
175429c871dSDoug Moore {
176429c871dSDoug Moore return (VM_RADIX_PCTRIE_LOOKUP_GE(&rtree->rt_trie, index));
177429c871dSDoug Moore }
178429c871dSDoug Moore
179429c871dSDoug Moore /*
180429c871dSDoug Moore * Returns the page with the greatest pindex that is less than or equal to the
181429c871dSDoug Moore * specified pindex, or NULL if there are no such pages.
182429c871dSDoug Moore *
183429c871dSDoug Moore * Requires that access be externally synchronized by a lock.
184429c871dSDoug Moore */
185429c871dSDoug Moore static __inline vm_page_t
vm_radix_lookup_le(struct vm_radix * rtree,vm_pindex_t index)186429c871dSDoug Moore vm_radix_lookup_le(struct vm_radix *rtree, vm_pindex_t index)
187429c871dSDoug Moore {
188429c871dSDoug Moore return (VM_RADIX_PCTRIE_LOOKUP_LE(&rtree->rt_trie, index));
189429c871dSDoug Moore }
190429c871dSDoug Moore
191429c871dSDoug Moore /*
192429c871dSDoug Moore * Remove the specified index from the trie, and return the value stored at
193429c871dSDoug Moore * that index. If the index is not present, return NULL.
194429c871dSDoug Moore */
195429c871dSDoug Moore static __inline vm_page_t
vm_radix_remove(struct vm_radix * rtree,vm_pindex_t index)196429c871dSDoug Moore vm_radix_remove(struct vm_radix *rtree, vm_pindex_t index)
197429c871dSDoug Moore {
198429c871dSDoug Moore return (VM_RADIX_PCTRIE_REMOVE_LOOKUP(&rtree->rt_trie, index));
199429c871dSDoug Moore }
200429c871dSDoug Moore
201429c871dSDoug Moore /*
202c71c41daSDoug Moore * Remove the current page from the trie.
203c71c41daSDoug Moore */
204c71c41daSDoug Moore static __inline void
vm_radix_iter_remove(struct pctrie_iter * pages)205c71c41daSDoug Moore vm_radix_iter_remove(struct pctrie_iter *pages)
206c71c41daSDoug Moore {
207c71c41daSDoug Moore VM_RADIX_PCTRIE_ITER_REMOVE(pages);
208c71c41daSDoug Moore }
209c71c41daSDoug Moore
210c71c41daSDoug Moore /*
211c3d743a6SDoug Moore * Reclaim all the interior nodes of the trie, and invoke the callback
212c3d743a6SDoug Moore * on all the pages, in order.
213429c871dSDoug Moore */
214429c871dSDoug Moore static __inline void
vm_radix_reclaim_callback(struct vm_radix * rtree,void (* page_cb)(vm_page_t,void *),void * arg)215c3d743a6SDoug Moore vm_radix_reclaim_callback(struct vm_radix *rtree,
216c3d743a6SDoug Moore void (*page_cb)(vm_page_t, void *), void *arg)
217429c871dSDoug Moore {
218c3d743a6SDoug Moore VM_RADIX_PCTRIE_RECLAIM_CALLBACK(&rtree->rt_trie, page_cb, arg);
219429c871dSDoug Moore }
220429c871dSDoug Moore
221429c871dSDoug Moore /*
222450a6690SDoug Moore * Initialize an iterator pointing to the page with the least pindex that is
223450a6690SDoug Moore * greater than or equal to the specified pindex, or NULL if there are no such
224450a6690SDoug Moore * pages. Return the page.
225450a6690SDoug Moore *
226450a6690SDoug Moore * Requires that access be externally synchronized by a lock.
227450a6690SDoug Moore */
228450a6690SDoug Moore static __inline vm_page_t
vm_radix_iter_lookup_ge(struct pctrie_iter * pages,vm_pindex_t index)229450a6690SDoug Moore vm_radix_iter_lookup_ge(struct pctrie_iter *pages, vm_pindex_t index)
230450a6690SDoug Moore {
231450a6690SDoug Moore return (VM_RADIX_PCTRIE_ITER_LOOKUP_GE(pages, index));
232450a6690SDoug Moore }
233450a6690SDoug Moore
234450a6690SDoug Moore /*
235450a6690SDoug Moore * Update the iterator to point to the page with the least pindex that is 'jump'
236450a6690SDoug Moore * or more greater than or equal to the current pindex, or NULL if there are no
237450a6690SDoug Moore * such pages. Return the page.
238450a6690SDoug Moore *
239450a6690SDoug Moore * Requires that access be externally synchronized by a lock.
240450a6690SDoug Moore */
241450a6690SDoug Moore static __inline vm_page_t
vm_radix_iter_jump(struct pctrie_iter * pages,vm_pindex_t jump)242450a6690SDoug Moore vm_radix_iter_jump(struct pctrie_iter *pages, vm_pindex_t jump)
243450a6690SDoug Moore {
244450a6690SDoug Moore return (VM_RADIX_PCTRIE_ITER_JUMP_GE(pages, jump));
245450a6690SDoug Moore }
246450a6690SDoug Moore
247450a6690SDoug Moore /*
248450a6690SDoug Moore * Update the iterator to point to the page with the least pindex that is one or
249450a6690SDoug Moore * more greater than the current pindex, or NULL if there are no such pages.
250450a6690SDoug Moore * Return the page.
251450a6690SDoug Moore *
252450a6690SDoug Moore * Requires that access be externally synchronized by a lock.
253450a6690SDoug Moore */
254450a6690SDoug Moore static __inline vm_page_t
vm_radix_iter_step(struct pctrie_iter * pages)255450a6690SDoug Moore vm_radix_iter_step(struct pctrie_iter *pages)
256450a6690SDoug Moore {
257450a6690SDoug Moore return (VM_RADIX_PCTRIE_ITER_STEP_GE(pages));
258450a6690SDoug Moore }
259450a6690SDoug Moore
260450a6690SDoug Moore /*
261*f3895e98SDoug Moore * Initialize an iterator pointing to the page with the greatest pindex that is
262*f3895e98SDoug Moore * less than or equal to the specified pindex, or NULL if there are no such
263*f3895e98SDoug Moore * pages. Return the page.
264*f3895e98SDoug Moore *
265*f3895e98SDoug Moore * Requires that access be externally synchronized by a lock.
266*f3895e98SDoug Moore */
267*f3895e98SDoug Moore static __inline vm_page_t
vm_radix_iter_lookup_le(struct pctrie_iter * pages,vm_pindex_t index)268*f3895e98SDoug Moore vm_radix_iter_lookup_le(struct pctrie_iter *pages, vm_pindex_t index)
269*f3895e98SDoug Moore {
270*f3895e98SDoug Moore return (VM_RADIX_PCTRIE_ITER_LOOKUP_LE(pages, index));
271*f3895e98SDoug Moore }
272*f3895e98SDoug Moore
273*f3895e98SDoug Moore /*
274450a6690SDoug Moore * Update the iterator to point to the page with the pindex that is one greater
275450a6690SDoug Moore * than the current pindex, or NULL if there is no such page. Return the page.
276450a6690SDoug Moore *
277450a6690SDoug Moore * Requires that access be externally synchronized by a lock.
278450a6690SDoug Moore */
279450a6690SDoug Moore static __inline vm_page_t
vm_radix_iter_next(struct pctrie_iter * pages)280450a6690SDoug Moore vm_radix_iter_next(struct pctrie_iter *pages)
281450a6690SDoug Moore {
282450a6690SDoug Moore return (VM_RADIX_PCTRIE_ITER_NEXT(pages));
283450a6690SDoug Moore }
284450a6690SDoug Moore
285450a6690SDoug Moore /*
286450a6690SDoug Moore * Update the iterator to point to the page with the pindex that is one less
287450a6690SDoug Moore * than the current pindex, or NULL if there is no such page. Return the page.
288450a6690SDoug Moore *
289450a6690SDoug Moore * Requires that access be externally synchronized by a lock.
290450a6690SDoug Moore */
291450a6690SDoug Moore static __inline vm_page_t
vm_radix_iter_prev(struct pctrie_iter * pages)292450a6690SDoug Moore vm_radix_iter_prev(struct pctrie_iter *pages)
293450a6690SDoug Moore {
294450a6690SDoug Moore return (VM_RADIX_PCTRIE_ITER_PREV(pages));
295450a6690SDoug Moore }
296450a6690SDoug Moore
297450a6690SDoug Moore /*
298450a6690SDoug Moore * Return the current page.
299450a6690SDoug Moore *
300450a6690SDoug Moore * Requires that access be externally synchronized by a lock.
301450a6690SDoug Moore */
302450a6690SDoug Moore static __inline vm_page_t
vm_radix_iter_page(struct pctrie_iter * pages)303450a6690SDoug Moore vm_radix_iter_page(struct pctrie_iter *pages)
304450a6690SDoug Moore {
305450a6690SDoug Moore return (VM_RADIX_PCTRIE_ITER_VALUE(pages));
306450a6690SDoug Moore }
307450a6690SDoug Moore
308450a6690SDoug Moore /*
309429c871dSDoug Moore * Replace an existing page in the trie with another one.
310429c871dSDoug Moore * Panics if there is not an old page in the trie at the new page's index.
311429c871dSDoug Moore */
312429c871dSDoug Moore static __inline vm_page_t
vm_radix_replace(struct vm_radix * rtree,vm_page_t newpage)313429c871dSDoug Moore vm_radix_replace(struct vm_radix *rtree, vm_page_t newpage)
314429c871dSDoug Moore {
315429c871dSDoug Moore return (VM_RADIX_PCTRIE_REPLACE(&rtree->rt_trie, newpage));
316cd1241fbSKonstantin Belousov }
317774d251dSAttilio Rao
318774d251dSAttilio Rao #endif /* _KERNEL */
319774d251dSAttilio Rao #endif /* !_VM_RADIX_H_ */
320