1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
|
<table class="head">
<tr>
<td class="head-ltitle">OSD(9)</td>
<td class="head-vol">Kernel Developer's Manual</td>
<td class="head-rtitle">OSD(9)</td>
</tr>
</table>
<div class="manual-text">
<section class="Sh">
<h1 class="Sh" id="NAME"><a class="permalink" href="#NAME">NAME</a></h1>
<p class="Pp"><code class="Nm">osd</code>, <code class="Nm">osd_register</code>,
<code class="Nm">osd_deregister</code>, <code class="Nm">osd_set</code>,
<code class="Nm">osd_reserve</code>,
<code class="Nm">osd_set_reserved</code>,
<code class="Nm">osd_free_reserved</code>, <code class="Nm">osd_get</code>,
<code class="Nm">osd_del</code>, <code class="Nm">osd_call</code>,
<code class="Nm">osd_exit</code> — <span class="Nd">Object Specific
Data</span></p>
</section>
<section class="Sh">
<h1 class="Sh" id="SYNOPSIS"><a class="permalink" href="#SYNOPSIS">SYNOPSIS</a></h1>
<p class="Pp"><code class="In">#include
<<a class="In">sys/osd.h</a>></code></p>
<p class="Pp"><var class="Ft">typedef void</var>
<br/>
<code class="Fn">(*osd_destructor_t)</code>(<var class="Fa" style="white-space: nowrap;">void
*value</var>);</p>
<p class="Pp"><var class="Ft">typedef int</var>
<br/>
<code class="Fn">(*osd_method_t)</code>(<var class="Fa" style="white-space: nowrap;">void
*obj</var>, <var class="Fa" style="white-space: nowrap;">void
*data</var>);</p>
<p class="Pp"><var class="Ft">int</var>
<br/>
<code class="Fn">osd_register</code>(<var class="Fa">u_int type</var>,
<var class="Fa">osd_destructor_t destructor</var>, <var class="Fa">const
osd_method_t *methods</var>);</p>
<p class="Pp"><var class="Ft">void</var>
<br/>
<code class="Fn">osd_deregister</code>(<var class="Fa">u_int type</var>,
<var class="Fa">u_int slot</var>);</p>
<p class="Pp"><var class="Ft">int</var>
<br/>
<code class="Fn">osd_set</code>(<var class="Fa">u_int type</var>,
<var class="Fa">struct osd *osd</var>, <var class="Fa">u_int slot</var>,
<var class="Fa">void *value</var>);</p>
<p class="Pp"><var class="Ft">void **</var>
<br/>
<code class="Fn">osd_reserve</code>(<var class="Fa">u_int slot</var>);</p>
<p class="Pp"><var class="Ft">int</var>
<br/>
<code class="Fn">osd_set_reserved</code>(<var class="Fa">u_int type</var>,
<var class="Fa">struct osd *osd</var>, <var class="Fa">u_int slot</var>,
<var class="Fa">void **rsv</var>, <var class="Fa">void *value</var>);</p>
<p class="Pp"><var class="Ft">void</var>
<br/>
<code class="Fn">osd_free_reserved</code>(<var class="Fa">void
**rsv</var>);</p>
<p class="Pp"><var class="Ft">void *</var>
<br/>
<code class="Fn">osd_get</code>(<var class="Fa">u_int type</var>,
<var class="Fa">struct osd *osd</var>, <var class="Fa">u_int
slot</var>);</p>
<p class="Pp"><var class="Ft">void</var>
<br/>
<code class="Fn">osd_del</code>(<var class="Fa">u_int type</var>,
<var class="Fa">struct osd *osd</var>, <var class="Fa">u_int
slot</var>);</p>
<p class="Pp"><var class="Ft">int</var>
<br/>
<code class="Fn">osd_call</code>(<var class="Fa">u_int type</var>,
<var class="Fa">u_int method</var>, <var class="Fa">void *obj</var>,
<var class="Fa">void *data</var>);</p>
<p class="Pp"><var class="Ft">void</var>
<br/>
<code class="Fn">osd_exit</code>(<var class="Fa">u_int type</var>,
<var class="Fa">struct osd *osd</var>);</p>
</section>
<section class="Sh">
<h1 class="Sh" id="DESCRIPTION"><a class="permalink" href="#DESCRIPTION">DESCRIPTION</a></h1>
<p class="Pp">The <code class="Nm">osd</code> framework provides a mechanism to
dynamically associate arbitrary data at run-time with any kernel data
structure which has been suitably modified for use with
<code class="Nm">osd</code>. The one-off modification required involves
embedding a <var class="Vt">struct osd</var> inside the kernel data
structure.</p>
<p class="Pp">An additional benefit is that after the initial change to a
structure is made, all subsequent use of <code class="Nm">osd</code> with
the structure involves no changes to the structure's layout. By extension,
if the data structure is part of the ABI, <code class="Nm">osd</code>
provides a way of extending the structure in an ABI preserving manner.</p>
<p class="Pp">The details of the embedded <var class="Vt">struct osd</var> are
not relevant to consumers of the <code class="Nm">osd</code> framework and
should not be manipulated directly.</p>
<p class="Pp" id="osd_register">Data associated with a structure is referenced
by the <code class="Nm">osd</code> framework using a type/slot identifier
pair. Types are statically defined in
<code class="In"><<a class="In">sys/osd.h</a>></code> and provide a
high-level grouping for slots to be registered under. Slot identifiers are
dynamically assigned by the framework when a data type is registered using
<a class="permalink" href="#osd_register"><code class="Fn">osd_register</code></a>()
and remains valid until a corresponding call to
<code class="Fn">osd_deregister</code>().</p>
<section class="Ss">
<h2 class="Ss" id="Functions"><a class="permalink" href="#Functions">Functions</a></h2>
<p class="Pp">The <code class="Fn">osd_register</code>() function registers a
type/slot identifier pair with the <code class="Nm">osd</code> framework for
use with a new data type. The function may sleep and therefore cannot be
called from a non-sleepable context. The <var class="Fa">type</var> argument
specifies which high-level type grouping from
<code class="In"><<a class="In">sys/osd.h</a>></code> the slot
identifier should be allocated under. The <var class="Fa">destructor</var>
argument specifies an optional osd_destructor_t function pointer that will
be called for objects of the type being registered which are later destroyed
by the <code class="Fn">osd_del</code>() function. NULL may be passed if no
destructor is required. The <var class="Fa">methods</var> argument specifies
an optional array of osd_method_t function pointers which can be later
invoked by the <code class="Fn">osd_call</code>() function. NULL may be
passed if no methods are required. The <var class="Fa">methods</var>
argument is currently only useful with the OSD_JAIL type identifier.</p>
<p class="Pp" id="osd_deregister">The
<a class="permalink" href="#osd_deregister"><code class="Fn">osd_deregister</code></a>()
function deregisters a previously registered type/slot identifier pair. The
function may sleep and therefore cannot be called from a non-sleepable
context. The <var class="Fa">type</var> argument specifies which high-level
type grouping from
<code class="In"><<a class="In">sys/osd.h</a>></code> the slot
identifier is allocated under. The <var class="Fa">slot</var> argument
specifies the slot identifier which is being deregistered and should be the
value that was returned by <code class="Fn">osd_register</code>() when the
data type was registered.</p>
<p class="Pp" id="osd_set">The
<a class="permalink" href="#osd_set"><code class="Fn">osd_set</code></a>()
function associates a data object pointer with a kernel data structure's
<var class="Vt">struct osd</var> member. The <var class="Fa">type</var>
argument specifies which high-level type grouping from
<code class="In"><<a class="In">sys/osd.h</a>></code> the slot
identifier is allocated under. The <var class="Fa">osd</var> argument is a
pointer to the kernel data structure's <var class="Vt">struct osd</var>
which will have the <var class="Fa">value</var> pointer associated with it.
The <var class="Fa">slot</var> argument specifies the slot identifier to
assign the <var class="Fa">value</var> pointer to. The
<var class="Fa">value</var> argument points to a data object to associate
with <var class="Fa">osd</var>.</p>
<p class="Pp" id="osd_set_reserved">The
<a class="permalink" href="#osd_set_reserved"><code class="Fn">osd_set_reserved</code></a>()
function does the same as <code class="Fn">osd_set</code>(), but with an
extra argument <var class="Fa">rsv</var> that is internal-use memory
previously allocated via
<a class="permalink" href="#osd_reserve"><code class="Fn" id="osd_reserve">osd_reserve</code></a>().</p>
<p class="Pp" id="osd_get">The
<a class="permalink" href="#osd_get"><code class="Fn">osd_get</code></a>()
function returns the data pointer associated with a kernel data structure's
<var class="Vt">struct osd</var> member from the specified type/slot
identifier pair. The <var class="Fa">type</var> argument specifies which
high-level type grouping from
<code class="In"><<a class="In">sys/osd.h</a>></code> the slot
identifier is allocated under. The <var class="Fa">osd</var> argument is a
pointer to the kernel data structure's <var class="Vt">struct osd</var> to
retrieve the data pointer from. The <var class="Fa">slot</var> argument
specifies the slot identifier to retrieve the data pointer from.</p>
<p class="Pp" id="osd_del">The
<a class="permalink" href="#osd_del"><code class="Fn">osd_del</code></a>()
function removes the data pointer associated with a kernel data structure's
<var class="Vt">struct osd</var> member from the specified type/slot
identifier pair. The <var class="Fa">type</var> argument specifies which
high-level type grouping from
<code class="In"><<a class="In">sys/osd.h</a>></code> the slot
identifier is allocated under. The <var class="Fa">osd</var> argument is a
pointer to the kernel data structure's <var class="Vt">struct osd</var> to
remove the data pointer from. The <var class="Fa">slot</var> argument
specifies the slot identifier to remove the data pointer from. If an
osd_destructor_t function pointer was specified at registration time, the
destructor function will be called and passed the data pointer for the
type/slot identifier pair which is being deleted.</p>
<p class="Pp" id="osd_call">The
<a class="permalink" href="#osd_call"><code class="Fn">osd_call</code></a>()
function calls the specified osd_method_t function pointer for all currently
registered slots of a given type on the specified <var class="Fa">obj</var>
and <var class="Fa">data</var> pointers. The function may sleep and
therefore cannot be called from a non-sleepable context. The
<var class="Fa">type</var> argument specifies which high-level type grouping
from <code class="In"><<a class="In">sys/osd.h</a>></code> to call the
method for. The <var class="Fa">method</var> argument specifies the index
into the osd_method_t array that was passed to
<code class="Fn">osd_register</code>(). The <var class="Fa">obj</var> and
<var class="Fa">data</var> arguments are passed to the method function
pointer of each slot.</p>
<p class="Pp" id="osd_exit">The
<a class="permalink" href="#osd_exit"><code class="Fn">osd_exit</code></a>()
function removes all data object pointers from all currently registered
slots for a given type for the specified kernel data structure's
<var class="Vt">struct osd</var> member. The <var class="Fa">type</var>
argument specifies which high-level type grouping from
<code class="In"><<a class="In">sys/osd.h</a>></code> to remove data
pointers from. The <var class="Fa">osd</var> argument is a pointer to the
kernel data structure's <var class="Vt">struct osd</var> to remove all data
object pointers for all currently registered slots from.</p>
</section>
</section>
<section class="Sh">
<h1 class="Sh" id="IMPLEMENTATION_NOTES"><a class="permalink" href="#IMPLEMENTATION_NOTES">IMPLEMENTATION
NOTES</a></h1>
<p class="Pp"><code class="Nm">osd</code> uses a two dimensional matrix (array
of arrays) as the data structure to manage the external data associated with
a kernel data structure's <var class="Vt">struct osd</var> member. The type
identifier is used as the index into the outer array, and the slot
identifier is used as the index into the inner array. To set or retrieve a
data pointer for a given type/slot identifier pair,
<code class="Fn">osd_set</code>() and <code class="Fn">osd_get</code>()
perform the equivalent of array[type][slot], which is both constant time and
fast.</p>
<p class="Pp">If <code class="Fn">osd_set</code>() is called on a
<var class="Vt">struct osd</var> for the first time, the array for storing
data pointers is dynamically allocated using <a class="Xr">malloc(9)</a>
with M_NOWAIT to a size appropriate for the slot identifier being set. If a
subsequent call to <code class="Fn">osd_set</code>() attempts to set a slot
identifier which is numerically larger than the slot used in the previous
<code class="Fn">osd_set</code>() call, <a class="Xr">realloc(9)</a> is used
to grow the array to the appropriate size such that the slot identifier can
be used. To maximise the efficiency of any code which calls
<code class="Fn">osd_set</code>() sequentially on a number of different slot
identifiers (e.g., during an initialisation phase) one should loop through
the slot identifiers in descending order from highest to lowest. This will
result in only a single <a class="Xr">malloc(9)</a> call to create an array
of the largest slot size and all subsequent calls to
<code class="Fn">osd_set</code>() will proceed without any
<a class="Xr">realloc(9)</a> calls.</p>
<p class="Pp">It is possible for <code class="Fn">osd_set</code>() to fail to
allocate this array. To ensure that such allocation succeeds,
<code class="Fn">osd_reserve</code>() may be called (in a non-blocking
context), and it will pre-allocate the memory via
<a class="Xr">malloc(9)</a> with M_WAITOK. Then this pre-allocated memory is
passed to <code class="Fn">osd_set_reserved</code>(), which will use it if
necessary or otherwise discard it. The memory may also be explicitly
discarded by calling <code class="Fn">osd_free_reserved</code>(). As this
method always allocates memory whether or not it is ultimately needed, it
should be used only rarely, such as in the unlikely event that
<code class="Fn">osd_set</code>() fails.</p>
<p class="Pp">The <code class="Nm">osd</code> API is geared towards slot
identifiers storing pointers to the same underlying data structure type for
a given <code class="Nm">osd</code> type identifier. This is not a
requirement, and <a class="Xr">khelp(9)</a> for example stores completely
different data types in slots under the OSD_KHELP type identifier.</p>
<section class="Ss">
<h2 class="Ss" id="Locking"><a class="permalink" href="#Locking">Locking</a></h2>
<p class="Pp"><code class="Nm">osd</code> internally uses a mix of
<a class="Xr">mutex(9)</a>, <a class="Xr">rmlock(9)</a> and
<a class="Xr">sx(9)</a> locks to protect its internal data structures and
state.</p>
<p class="Pp">Responsibility for synchronising access to a kernel data
structure's <var class="Vt">struct osd</var> member is left to the subsystem
that uses the data structure and calls the <code class="Nm">osd</code>
API.</p>
<p class="Pp"><code class="Fn">osd_get</code>() only acquires an
<a class="Xr">rmlock(9)</a> in read mode, therefore making it safe to use in
the majority of contexts within the kernel including most fast paths.</p>
</section>
</section>
<section class="Sh">
<h1 class="Sh" id="RETURN_VALUES"><a class="permalink" href="#RETURN_VALUES">RETURN
VALUES</a></h1>
<p class="Pp"><code class="Fn">osd_register</code>() returns the slot identifier
for the newly registered data type.</p>
<p class="Pp"><code class="Fn">osd_set</code>() and
<code class="Fn">osd_set_reserved</code>() return zero on success or ENOMEM
if the specified type/slot identifier pair triggered an internal
<a class="Xr">realloc(9)</a> which failed
(<code class="Fn">osd_set_reserved</code>() will always succeed when
<var class="Fa">rsv</var> is non-NULL).</p>
<p class="Pp"><code class="Fn">osd_get</code>() returns the data pointer for the
specified type/slot identifier pair, or NULL if the slot has not been
initialised yet.</p>
<p class="Pp"><code class="Fn">osd_reserve</code>() returns a pointer suitable
for passing to <code class="Fn">osd_set_reserved</code>() or
<code class="Fn">osd_free_reserved</code>().</p>
<p class="Pp"><code class="Fn">osd_call</code>() returns zero if no method is
run or the method for each slot runs successfully. If a method for a slot
returns non-zero, <code class="Fn">osd_call</code>() terminates prematurely
and returns the method's error to the caller.</p>
</section>
<section class="Sh">
<h1 class="Sh" id="SEE_ALSO"><a class="permalink" href="#SEE_ALSO">SEE
ALSO</a></h1>
<p class="Pp"><a class="Xr">khelp(9)</a></p>
</section>
<section class="Sh">
<h1 class="Sh" id="HISTORY"><a class="permalink" href="#HISTORY">HISTORY</a></h1>
<p class="Pp">The Object Specific Data (OSD) facility first appeared in
<span class="Ux">FreeBSD 8.0</span>.</p>
</section>
<section class="Sh">
<h1 class="Sh" id="AUTHORS"><a class="permalink" href="#AUTHORS">AUTHORS</a></h1>
<p class="Pp">The <code class="Nm">osd</code> facility was written by
<span class="An">Pawel Jakub Dawidek</span>
<<a class="Mt" href="mailto:pjd@FreeBSD.org">pjd@FreeBSD.org</a>>.</p>
<p class="Pp">This manual page was written by <span class="An">Lawrence
Stewart</span>
<<a class="Mt" href="mailto:lstewart@FreeBSD.org">lstewart@FreeBSD.org</a>>.</p>
</section>
</div>
<table class="foot">
<tr>
<td class="foot-date">October 7, 2024</td>
<td class="foot-os">FreeBSD 15.0</td>
</tr>
</table>
|