xref: /illumos-gate/usr/src/uts/common/sys/memlist_impl.h (revision 438283cf397cce47d80cc67b04bbfdfe73b0d142)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1997-1998 by Sun Microsystems, Inc.
24  * All rights reserved.
25  * Copyright 2026 Oxide Computer Company
26  */
27 
28 #ifndef	_SYS_MEMLIST_IMPL_H
29 #define	_SYS_MEMLIST_IMPL_H
30 
31 /*
32  * Common memlist routines.
33  */
34 
35 #include <sys/memlist.h>
36 #include <sys/mutex.h>
37 
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41 
42 struct memlist_pool {
43 	memlist_t *mp_freelist;
44 	uint_t mp_freelist_count;
45 	kmutex_t mp_freelist_mutex;
46 	uint_t mp_flags;
47 };
48 
49 #define	MEMLP_FL_EARLYBOOT	1
50 /*
51  * A pool that is not really a pool: entries come from kmem on demand and go
52  * back to it when freed, so allocation is unbounded and cannot fail rather
53  * than being served from a freelist that has to be stocked in advance.  For
54  * consumers that run late enough to call kmem and do not know ahead of time
55  * how many entries they will need.
56  *
57  * Such a pool holds no state, so a single one serves everybody: see
58  * memlist_kmem_pool below.  Its entries must never be mixed with a real
59  * pool's, since freeing them is kmem_free() rather than a freelist push.
60  * Use xmemlist_dup instead to copy entries to a memlist backed by a different
61  * pool.
62  */
63 #define	MEMLP_FL_KMEM		2
64 
65 extern memlist_pool_t memlist_kmem_pool;
66 
67 extern struct memlist *memlist_get_one(void);
68 extern void memlist_free_one(struct memlist *);
69 extern void memlist_free_list(struct memlist *);
70 extern void memlist_free_block(caddr_t, size_t);
71 extern void memlist_insert(struct memlist *, struct memlist **);
72 extern void memlist_del(struct memlist *, struct memlist **);
73 extern struct memlist *memlist_find(struct memlist *, uint64_t);
74 
75 extern struct memlist *xmemlist_get_one(struct memlist_pool *);
76 extern void xmemlist_free_one(struct memlist_pool *, struct memlist *);
77 extern void xmemlist_free_list(struct memlist_pool *, struct memlist *);
78 extern void xmemlist_free_block(struct memlist_pool *, caddr_t, size_t);
79 
80 #define	MEML_SPANOP_OK		0
81 #define	MEML_SPANOP_ESPAN	1
82 #define	MEML_SPANOP_EALLOC	2
83 #define	MEML_SPANOP_EOVERFLOW	3
84 
85 /*
86  * Optional for span operations: allow munging (relaxed coalescing).  When set,
87  * the span to be added or deleted from the list may overlap multiple existing
88  * entries and/or addresses not contained within the list.  See notes in
89  * memlist_new.c.
90  */
91 #define	MEML_FL_RELAXED	1
92 
93 extern int memlist_add_span(uint64_t, uint64_t, struct memlist **);
94 extern int memlist_delete_span(uint64_t, uint64_t, struct memlist **);
95 extern int xmemlist_add_span(struct memlist_pool *, uint64_t, uint64_t,
96     struct memlist **, uint64_t);
97 extern int xmemlist_delete_span(struct memlist_pool *, uint64_t, uint64_t,
98     struct memlist **, uint64_t);
99 
100 /*
101  * Copy a list into the given pool, for handing it from one pool's ownership to
102  * another's.  Returns NULL if that pool runs out.
103  */
104 extern struct memlist *xmemlist_dup(memlist_pool_t *, const struct memlist *);
105 
106 /*
107  * Free a whole list back to its pool and clear the caller's pointer to it.
108  */
109 extern void xmemlist_free_all(memlist_pool_t *, struct memlist **);
110 
111 /*
112  * Add every span of one list to another: their union, given MEML_FL_RELAXED.
113  * merge() leaves the source alone while subsume() empties it into the pool.
114  *
115  * Both stop at the first span that cannot be added, so on failure the
116  * destination holds what was transferred before it and, for subsume(), the
117  * source holds the rest.
118  */
119 extern int xmemlist_merge(memlist_pool_t *, const struct memlist *,
120     struct memlist **, uint64_t);
121 extern int xmemlist_subsume(memlist_pool_t *, struct memlist **,
122     struct memlist **, uint64_t);
123 
124 /*
125  * Delete every span of one list from another: their difference.  The list being
126  * subtracted is untouched and need not belong to this pool.
127  *
128  * This will stop at the first failure to delete a span: no such span exists
129  * (if MEML_FL_RELAXED wasn't passed) or failed to allocate an entry for a newly
130  * split off span.  In either case, the list under mutation holds whatever it
131  * started with less the spans successfully deleted.
132  */
133 extern int xmemlist_delete_list(memlist_pool_t *, struct memlist **,
134     const struct memlist *, uint64_t);
135 
136 /*
137  * Find the first span of the given size and alignment without modifying the
138  * list, for asking whether an allocation would succeed.  Returns
139  * MEML_SPANOP_ESPAN if there is no such span, otherwise MEML_SPANOP_OK with the
140  * address a claim would hand back.  Any non-zero alignment value must be a
141  * power-of-two.  The address out parameter may be NULL if the specific address
142  * is not needed but just that such a span exists.
143  */
144 extern int memlist_find_span(const struct memlist *, uint64_t, uint64_t,
145     uint64_t *);
146 
147 /*
148  * These routines first try to find a span of the given size and alignment
149  * (in the entry beginning exactly at the given address for the _at form) and
150  * then call xmemlist_delete_span (with MEML_FL_RELAXED) to remove said span.
151  * If no such span is not found, MEML_SPANOP_ESPAN is returned with the list
152  * remaining untouched.  If a span is found and successfully deleted from the
153  * list, the starting address is returned.  Any non-zero alignment value must be
154  * a power-of-two.
155  */
156 extern int xmemlist_claim_span(memlist_pool_t *, struct memlist **, uint64_t,
157     uint64_t, uint64_t *);
158 extern int xmemlist_claim_span_at(memlist_pool_t *, struct memlist **,
159     uint64_t, uint64_t, uint64_t, uint64_t *);
160 
161 /*
162  * Convenience methods for tracking available/in-use address space.  These are
163  * wrappers around the above xmemlist_* operations making use of the kmem pool
164  * and relaxed semantics.
165  *
166  * Fixing the pool and the flags is what makes most of these infallible, so they
167  * return nothing: relaxed semantics rule out MEML_SPANOP_ESPAN, and a
168  * kmem-backed pool sleeps for memory rather than returning MEML_SPANOP_EALLOC.
169  */
170 extern void memlist_rsrc_add(struct memlist **, uint64_t, uint64_t);
171 extern void memlist_rsrc_delete(struct memlist **, uint64_t, uint64_t);
172 extern void memlist_rsrc_delete_list(struct memlist **, const struct memlist *);
173 extern void memlist_rsrc_merge(const struct memlist *, struct memlist **);
174 extern void memlist_rsrc_subsume(struct memlist **, struct memlist **);
175 extern int memlist_rsrc_claim(struct memlist **, uint64_t, uint64_t,
176     uint64_t *);
177 extern int memlist_rsrc_claim_at(struct memlist **, uint64_t, uint64_t,
178     uint64_t, uint64_t *);
179 extern struct memlist *memlist_rsrc_dup(const struct memlist *);
180 extern void memlist_rsrc_free(struct memlist **);
181 
182 #ifdef __cplusplus
183 }
184 #endif
185 
186 #endif	/* _SYS_MEMLIST_IMPL_H */
187