linux_xa.c revision 1.1 1 1.1 riastrad /* $NetBSD: linux_xa.c,v 1.1 2021/12/19 11:51:07 riastradh Exp $ */
2 1.1 riastrad
3 1.1 riastrad /*-
4 1.1 riastrad * Copyright (c) 2021 The NetBSD Foundation, Inc.
5 1.1 riastrad * All rights reserved.
6 1.1 riastrad *
7 1.1 riastrad * Redistribution and use in source and binary forms, with or without
8 1.1 riastrad * modification, are permitted provided that the following conditions
9 1.1 riastrad * are met:
10 1.1 riastrad * 1. Redistributions of source code must retain the above copyright
11 1.1 riastrad * notice, this list of conditions and the following disclaimer.
12 1.1 riastrad * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 riastrad * notice, this list of conditions and the following disclaimer in the
14 1.1 riastrad * documentation and/or other materials provided with the distribution.
15 1.1 riastrad *
16 1.1 riastrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 1.1 riastrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.1 riastrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.1 riastrad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 1.1 riastrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.1 riastrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.1 riastrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.1 riastrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.1 riastrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.1 riastrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.1 riastrad * POSSIBILITY OF SUCH DAMAGE.
27 1.1 riastrad */
28 1.1 riastrad
29 1.1 riastrad #include <sys/cdefs.h>
30 1.1 riastrad __KERNEL_RCSID(0, "$NetBSD: linux_xa.c,v 1.1 2021/12/19 11:51:07 riastradh Exp $");
31 1.1 riastrad
32 1.1 riastrad #include <sys/radixtree.h>
33 1.1 riastrad
34 1.1 riastrad #include <uvm/uvm_pdaemon.h>
35 1.1 riastrad
36 1.1 riastrad #include <linux/xarray.h>
37 1.1 riastrad
38 1.1 riastrad const struct xa_limit xa_limit_32b = { .min = 0, .max = UINT32_MAX };
39 1.1 riastrad
40 1.1 riastrad void
41 1.1 riastrad xa_init_flags(struct xarray *xa, gfp_t gfp)
42 1.1 riastrad {
43 1.1 riastrad
44 1.1 riastrad mutex_init(&xa->xa_lock, MUTEX_DEFAULT, IPL_VM);
45 1.1 riastrad radix_tree_init_tree(&xa->xa_tree);
46 1.1 riastrad xa->xa_gfp = gfp;
47 1.1 riastrad }
48 1.1 riastrad
49 1.1 riastrad void
50 1.1 riastrad xa_destroy(struct xarray *xa)
51 1.1 riastrad {
52 1.1 riastrad
53 1.1 riastrad KASSERT(radix_tree_empty_tree_p(&xa->xa_tree));
54 1.1 riastrad radix_tree_fini_tree(&xa->xa_tree);
55 1.1 riastrad mutex_destroy(&xa->xa_lock);
56 1.1 riastrad }
57 1.1 riastrad
58 1.1 riastrad void *
59 1.1 riastrad xa_load(struct xarray *xa, unsigned long key)
60 1.1 riastrad {
61 1.1 riastrad void *datum;
62 1.1 riastrad
63 1.1 riastrad /* XXX pserialize */
64 1.1 riastrad mutex_enter(&xa->xa_lock);
65 1.1 riastrad datum = radix_tree_lookup_node(&xa->xa_tree, key);
66 1.1 riastrad mutex_exit(&xa->xa_lock);
67 1.1 riastrad
68 1.1 riastrad return datum;
69 1.1 riastrad }
70 1.1 riastrad
71 1.1 riastrad void *
72 1.1 riastrad xa_store(struct xarray *xa, unsigned long key, void *datum, gfp_t gfp)
73 1.1 riastrad {
74 1.1 riastrad void *collision;
75 1.1 riastrad int error;
76 1.1 riastrad
77 1.1 riastrad KASSERT(datum != NULL);
78 1.1 riastrad KASSERT(((uintptr_t)datum & 0x3) == 0);
79 1.1 riastrad
80 1.1 riastrad retry: mutex_enter(&xa->xa_lock);
81 1.1 riastrad collision = radix_tree_lookup_node(&xa->xa_tree, key);
82 1.1 riastrad error = radix_tree_insert_node(&xa->xa_tree, key, datum);
83 1.1 riastrad mutex_exit(&xa->xa_lock);
84 1.1 riastrad if (error) {
85 1.1 riastrad if (gfp & __GFP_WAIT) {
86 1.1 riastrad uvm_wait("xa");
87 1.1 riastrad goto retry;
88 1.1 riastrad }
89 1.1 riastrad /* XXX errno NetBSD->Linux */
90 1.1 riastrad return XA_ERROR(-error);
91 1.1 riastrad }
92 1.1 riastrad
93 1.1 riastrad return collision;
94 1.1 riastrad }
95 1.1 riastrad
96 1.1 riastrad int
97 1.1 riastrad xa_alloc(struct xarray *xa, uint32_t *idp, void *datum, struct xa_limit limit,
98 1.1 riastrad gfp_t gfp)
99 1.1 riastrad {
100 1.1 riastrad uint32_t key = limit.min;
101 1.1 riastrad void *collision;
102 1.1 riastrad int error;
103 1.1 riastrad
104 1.1 riastrad KASSERTMSG(limit.min < limit.max, "min=%"PRIu32" max=%"PRIu32,
105 1.1 riastrad limit.min, limit.max);
106 1.1 riastrad
107 1.1 riastrad retry: mutex_enter(&xa->xa_lock);
108 1.1 riastrad /* XXX use the radix tree to make this fast */
109 1.1 riastrad while ((collision = radix_tree_lookup_node(&xa->xa_tree, key))
110 1.1 riastrad != NULL) {
111 1.1 riastrad if (key++ == limit.max)
112 1.1 riastrad goto out;
113 1.1 riastrad }
114 1.1 riastrad error = radix_tree_insert_node(&xa->xa_tree, key, datum);
115 1.1 riastrad out: mutex_exit(&xa->xa_lock);
116 1.1 riastrad
117 1.1 riastrad if (collision)
118 1.1 riastrad return -EBUSY;
119 1.1 riastrad if (error) {
120 1.1 riastrad if (gfp & __GFP_WAIT) {
121 1.1 riastrad uvm_wait("xa");
122 1.1 riastrad goto retry;
123 1.1 riastrad }
124 1.1 riastrad /* XXX errno NetBSD->Linux */
125 1.1 riastrad return -error;
126 1.1 riastrad }
127 1.1 riastrad
128 1.1 riastrad /* Success! */
129 1.1 riastrad *idp = key;
130 1.1 riastrad return 0;
131 1.1 riastrad }
132 1.1 riastrad
133 1.1 riastrad void *
134 1.1 riastrad xa_find(struct xarray *xa, unsigned long *startp, unsigned long max,
135 1.1 riastrad unsigned tagmask)
136 1.1 riastrad {
137 1.1 riastrad uint64_t key = *startp;
138 1.1 riastrad void *candidate = NULL;
139 1.1 riastrad
140 1.1 riastrad mutex_enter(&xa->xa_lock);
141 1.1 riastrad for (; key < max; key++, candidate = NULL) {
142 1.1 riastrad candidate = radix_tree_lookup_node(&xa->xa_tree, key);
143 1.1 riastrad if (candidate == NULL)
144 1.1 riastrad continue;
145 1.1 riastrad if (tagmask == -1 ||
146 1.1 riastrad radix_tree_get_tag(&xa->xa_tree, key, tagmask))
147 1.1 riastrad break;
148 1.1 riastrad }
149 1.1 riastrad mutex_exit(&xa->xa_lock);
150 1.1 riastrad
151 1.1 riastrad if (candidate)
152 1.1 riastrad *startp = key;
153 1.1 riastrad return candidate;
154 1.1 riastrad }
155 1.1 riastrad
156 1.1 riastrad void *
157 1.1 riastrad xa_find_after(struct xarray *xa, unsigned long *startp, unsigned long max,
158 1.1 riastrad unsigned tagmask)
159 1.1 riastrad {
160 1.1 riastrad unsigned long start = *startp;
161 1.1 riastrad void *found;
162 1.1 riastrad
163 1.1 riastrad if (start == max)
164 1.1 riastrad return NULL;
165 1.1 riastrad found = xa_find(xa, &start, max, tagmask);
166 1.1 riastrad if (found)
167 1.1 riastrad *startp = start;
168 1.1 riastrad return found;
169 1.1 riastrad }
170 1.1 riastrad
171 1.1 riastrad void *
172 1.1 riastrad xa_erase(struct xarray *xa, unsigned long key)
173 1.1 riastrad {
174 1.1 riastrad void *datum;
175 1.1 riastrad
176 1.1 riastrad mutex_enter(&xa->xa_lock);
177 1.1 riastrad datum = radix_tree_remove_node(&xa->xa_tree, key);
178 1.1 riastrad mutex_exit(&xa->xa_lock);
179 1.1 riastrad
180 1.1 riastrad return datum;
181 1.1 riastrad }
182