XenevaOS
Loading...
Searching...
No Matches
idr.h
Go to the documentation of this file.
1#ifndef __LINUX_IDR_H
2#define __LINUX_IDR_H
3
4/*
5 * DCL <linux/idr.h> -- struct ida and the small allocation API.
6 *
7 * virtio-rng.c uses exactly two things from it:
8 *
9 * static DEFINE_IDA(rng_index_ida);
10 * vi->index = ida_alloc(&rng_index_ida, GFP_KERNEL);
11 * ...
12 * ida_free(&rng_index_ida, index);
13 *
14 * the index being used to name the device ("virtio-<n>"). mainline gets to
15 * this header by accident of its include graph -- there is no idr.h among the
16 * driver's own includes. The chain, confirmed against the header package:
17 *
18 * linux/virtio.h -> linux/device.h -> linux/kobject.h
19 * -> linux/sysfs.h -> linux/kernfs.h -> linux/idr.h
20 *
21 * DCL has no device.h (that chain is why <linux/virtio.h> here also pulls in
22 * completion.h and pm.h), so virtio.h includes this file directly instead of
23 * walking five headers to reach the same place. The driver's own #include
24 * list is therefore untouched, which is what has to stay true.
25 *
26 * ### struct ida keeps its own counter
27 *
28 * mainline's is `struct ida { struct xarray xa; }` -- a radix tree of ID
29 * bitmaps, because a kernel hands out millions of them. DCL's
30 * ida_alloc_range() (linux_kmod_shim.c) is a monotone counter, and the
31 * counter lives in this struct so that every ida numbers on its own. Three
32 * exist now and their numbering must not mix: virtio-rng's device index,
33 * virtio-console's vtermno (min 1), and drm's connector ids -- the
34 * per-config connector_ida, whose upper bound is 31, and the per-type idas
35 * in drm_connector_enum_list. One static counter in the shim served them all
36 * and would eventually have handed connector_ida an id past its own bound;
37 * the counter moved in here when the second user showed up.
38 *
39 * Ids are never reused -- mainline's reuses freed ones -- which costs
40 * nothing at DCL's scale: an ida here numbers devices or connectors, a
41 * handful per boot.
42 */
43
44#include <linux/kernel.h> /* gfp_t */
45
46struct ida {
47 unsigned int next_id;
48};
49
50/*
51 * struct idr -- DCL's is a fixed slot table; mainline's is a radix tree.
52 *
53 * The drm core hangs three of these off a device (mode_config object/tile
54 * ids, GEM object names) and one off every open file (GEM handles), and all
55 * it asks of them is "give me an int in [base, base+N) and give it back as a
56 * pointer". A 64-slot array answers that directly; what it does not answer
57 * is the two things mainline's tree buys -- ids beyond 64 at once, and
58 * lock-free lookup. Both are noted where they would bite:
59 * idr_alloc() (DCL/linux_idr_shim.c) returns -ENOSPC rather than growing, and
60 * rcu_read_lock() is a no-op, so the "lockless idr_find" mainline documents
61 * is simply single-threaded here like every other DCL lock.
62 *
63 * A slot answers two questions -- is the id taken, and what does it hold --
64 * and mainline keeps them apart: idr_alloc() may reserve an id and store
65 * NULL in it, which drm leans on. A connector's id is reserved as a NULL
66 * entry by __drm_mode_object_add() (register_obj false) and filled in later
67 * by drm_mode_object_register() through idr_replace() at connector
68 * registration; a GEM handle is reserved the same way in
69 * drm_gem_handle_create_tail(). A table of pointers alone cannot tell a
70 * reserved NULL entry from a free slot -- it would hand the id out a second
71 * time, and idr_replace() would refuse to fill the reservation -- so `used`
72 * carries the state and `slots` the value.
73 *
74 * idr_init_base()/idr_init()/idr_is_empty() are static inline over these
75 * fields, mirroring mainline (idr.h:152-181), so a `struct idr` member in
76 * drm_file.h or drm_mode_config.h is complete without a shim call.
77 */
78#define DCL_IDR_SLOTS 64
79
80struct idr {
81 void *slots[DCL_IDR_SLOTS]; /* slot i holds id base + i */
82 unsigned char used[DCL_IDR_SLOTS]; /* slot i's id has been reserved */
83 unsigned int base; /* first id this idr may hand out */
84};
85
86static inline void idr_init_base(struct idr *idr, int base)
87{
88 int i;
89
90 for (i = 0; i < DCL_IDR_SLOTS; i++) {
91 idr->slots[i] = NULL;
92 idr->used[i] = 0;
93 }
94 idr->base = (base > 0) ? (unsigned int)base : 0;
95}
96
97static inline void idr_init(struct idr *idr)
98{
99 idr_init_base(idr, 0);
100}
101
102static inline int idr_is_empty(struct idr *idr)
103{
104 int i;
105
106 for (i = 0; i < DCL_IDR_SLOTS; i++)
107 if (idr->used[i])
108 return 0;
109 return 1;
110}
111
112/*
113 * The rest of the API is extern -- mainline's are too (idr.h:113-126) --
114 * because the bodies share the slot arithmetic with each other and live in
115 * one file.
116 */
118int idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp);
119void *idr_remove(struct idr *idr, unsigned long id);
120void *idr_find(const struct idr *idr, unsigned long id);
121int idr_for_each(const struct idr *idr,
122 int (*fn)(int id, void *p, void *data), void *data);
123void *idr_get_next(struct idr *idr, int *nextid);
124void *idr_replace(struct idr *idr, void *ptr, unsigned long id);
125void idr_destroy(struct idr *idr);
126
127/*
128 * idr_preload_end() -- closes the section idr_preload() opened. mainline's
129 * is a static inline that unlocks the per-CPU radix-node cache (idr.h:189);
130 * the whole bracket does nothing in DCL because idr_alloc() takes its slot
131 * out of the struct itself, so there is nothing an allocation could have
132 * failed to find. It stays a static inline so drm_gem.c:502's call costs
133 * nothing at all. The long version of why the pair brackets nothing is at
134 * the top of DCL/linux_idr_shim.c.
135 */
136static inline void idr_preload_end(void)
137{
138}
139
140/*
141 * idr_for_each_entry() -- mainline's spelling (idr.h:204-205): idr_get_next()
142 * finds the first occupied id at or after *nextid and reports it there, so
143 * the loop's `id += 1U` starts the following search one past what it just
144 * found, and holes are skipped rather than returned as NULL entries.
145 */
146#define idr_for_each_entry(idr, entry, id) \
147 for (id = 0; ((entry) = idr_get_next((idr), &(id))) != NULL; id += 1U)
148
149#define DEFINE_IDA(name) struct ida name = { 0 }
150
151/*
152 * Matching DCL/linux_kmod_shim.c's definitions exactly -- same order, same
153 * types -- because both now appear in the same translation unit (the shim
154 * reaches this through <linux/virtio.h>). A `void*` here against a
155 * `struct ida*` there would be a conflicting-declaration error, not a
156 * harmless mismatch.
157 */
158extern int ida_alloc_range(struct ida* ida, unsigned int min,
159 unsigned int max, gfp_t gfp);
160extern void ida_free(struct ida* ida, unsigned int id);
161
177static inline int ida_alloc(struct ida* ida, gfp_t gfp)
178{
179 return ida_alloc_range(ida, 0, 0x7FFFFFFFu, gfp);
180}
181
197static inline int ida_alloc_min(struct ida* ida, unsigned int min, gfp_t gfp)
198{
199 return ida_alloc_range(ida, min, 0x7FFFFFFFu, gfp);
200}
201
202/*
203 * ida_alloc_max() -- mainline idr.h:327's third bound: [0, max] instead of
204 * [min, INT_MAX]. One caller, drm_connector.c:249, which asks the per-config
205 * connector_ida for an id no larger than 31, so the upper bound is real and
206 * not just mainline's usual ~0. The shim's range check answers -ENOSPC past
207 * it, which is also mainline's exhaustion errno, and the caller's
208 * `if (ret < 0) return ret;` takes it the same way.
209 */
210static inline int ida_alloc_max(struct ida* ida, unsigned int max, gfp_t gfp)
211{
212 return ida_alloc_range(ida, 0, max, gfp);
213}
214
215/*
216 * ida_init()/ida_destroy() -- mainline's pair for the xarray the ids live in
217 * (idr.h:332, and lib/idr.c's teardown). DCL's struct ida has no state: the
218 * numbering is the shim's static counter (linux_kmod_shim.c), which
219 * ida_free() deliberately does not wind back, so there is nothing to
220 * initialise and nothing to release. The bodies are empty rather than
221 * `ida->placeholder = 0` because the member this header documents as
222 * "documentation, not state" must not start being written by the one pair
223 * that would make it look load-bearing. drm_mode_config.c:455/:599 and
224 * drm_connector.c:122/:130 are the callers.
225 */
226static inline void ida_init(struct ida* ida)
227{
228 (void)ida;
229}
230
231static inline void ida_destroy(struct ida* ida)
232{
233 (void)ida;
234}
235
236#endif /* __LINUX_IDR_H */
#define NULL
Definition actypes.h:561
void * fn
Definition audrv.c:980
struct i915_user_extension base
Definition i915_drm.h:0
void * idr_get_next(struct idr *idr, int *nextid)
void idr_preload(gfp_t gfp)
void idr_destroy(struct idr *idr)
void * idr_replace(struct idr *idr, void *ptr, unsigned long id)
void * idr_remove(struct idr *idr, unsigned long id)
#define DCL_IDR_SLOTS
Definition idr.h:78
int idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp)
void * idr_find(const struct idr *idr, unsigned long id)
int idr_for_each(const struct idr *idr, int(*fn)(int id, void *p, void *data), void *data)
void ida_alloc_range(void)
void ida_free(void)
void * data
Definition kthread.h:30
unsigned int gfp_t
Definition kernel.h:56
char end[]
#define min(a, b)
Definition minmax.h:24
#define max(a, b)
Definition minmax.h:28
Definition idr.h:46
unsigned int next_id
Definition idr.h:47
Definition idr.h:80
unsigned char used[DCL_IDR_SLOTS]
Definition idr.h:82
unsigned int base
Definition idr.h:83
void * slots[DCL_IDR_SLOTS]
Definition idr.h:81