~ubuntu-branches/ubuntu/vivid/nbdkit/vivid-proposed

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
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
=encoding utf8

=head1 NAME

nbdkit-plugin - How to write nbdkit plugins

=head1 SYNOPSIS

 #include <nbdkit-plugin.h>
 
 #define THREAD_MODEL NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS
 
 static void *
 myplugin_open (void)
 {
   /* create a handle ... */
   return handle;
 }
 
 static struct nbdkit_plugin plugin = {
   .name              = "myplugin",
   .open              = myplugin_open,
   .get_size          = myplugin_get_size,
   .pread             = myplugin_pread,
   .pwrite            = myplugin_pwrite,
   /* etc */
 };
 
 NBDKIT_REGISTER_PLUGIN(plugin)

When this has been compiled to a shared library, do:

 nbdkit [--args ...] ./myplugin.so [key=value ...]

When debugging, use the I<-fv> options:

 nbdkit -fv ./myplugin.so [key=value ...]

=head1 DESCRIPTION

An nbdkit plugin is a new source device which can be served using the
Network Block Device (NBD) protocol.  This manual page describes how
to create an nbdkit plugin in C.

For example plugins, take a look at the source of nbdkit, in the
C<plugins> directory.

To write plugins in other languages, see:
L<nbdkit-perl-plugin(3)>,
L<nbdkit-python-plugin(3)>.

=head1 C<nbdkit-plugin.h>

All plugins should start by including this header file:

 #include <nbdkit-plugin.h>

=head1 C<#define THREAD_MODEL>

All plugins must define a thread model.  See L</THREADS> below for
details.  It is generally safe to use:

 #define THREAD_MODEL NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS

=head1 C<struct nbdkit_plugin>

All plugins must define and register one C<struct nbdkit_plugin>,
which contains the name of the plugin and pointers to callback
functions.

 static struct nbdkit_plugin plugin = {
   .name              = "myplugin",
   .longname          = "My Plugin",
   .description       = "This is my great plugin for nbdkit",
   .open              = myplugin_open,
   .get_size          = myplugin_get_size,
   .pread             = myplugin_pread,
   .pwrite            = myplugin_pwrite,
   /* etc */
 };
 
 NBDKIT_REGISTER_PLUGIN(plugin)

The C<.name> field is the name of the plugin.

The callbacks are described below (see L</CALLBACKS>).  Only C<.name>,
C<.open>, C<.get_size> and C<.pread> are required.  All other
callbacks can be omitted.  However almost all plugins should have a
C<.close> callback.  Most real-world plugins will also want to declare
some of the other callbacks.

The nbdkit server calls the callbacks in the following order over the
lifetime of the plugin:

=over 4

=item C<.load>

is called once just after the plugin is loaded into memory.

=item C<.config> and C<.config_complete>

C<.config> is called zero or more times during command line parsing.
C<.config_complete> is called once after all configuration information
has been passed to the plugin.

Both are called after loading the plugin but before any connections
are accepted.

=item C<.open>

A new client has connected.

=item C<.can_write>, C<.get_size> and other option negotiation callbacks

These are called during option negotiation with the client, but
before any data is served.

=item C<.pread>, C<.pwrite> and other data serving callbacks

After option negotiation has finished, these may be called to serve
data.  Depending on the thread model chosen, they might be called in
parallel from multiple threads.

=item C<.close>

The client has disconnected.

=item C<.open> ... C<.close>

The sequence C<.open> ... C<.close> can be called repeatedly over the
lifetime of the plugin, and can be called in parallel (depending on
the thread model).

=item C<.unload>

is called once just before the plugin is unloaded from memory.

=back

=head1 ERROR HANDLING

If there is an error in the plugin, the plugin should call
C<nbdkit_error> with the error message, and then return an error
indication from the callback, eg. NULL or -1.

C<nbdkit_error> has the following prototype and works like
L<printf(3)>:

 void nbdkit_error (const char *fs, ...);

=head1 FILENAMES AND PATHS

The server usually (not always) changes directory to C</> before it
starts serving connections.  This means that any relative paths passed
during configuration will not work when the server is running
(example: S<C<nbdkit plugin.so file=disk.img>>).

To avoid problems, prepend relative paths with the current directory
before storing them in the handle.  Or open files and store the file
descriptor.

=head2 C<nbdkit_absolute_path>

 char *nbdkit_absolute_path (const char *filename);

The utility function C<nbdkit_absolute_path> converts any path to an
absolute path.

If conversion was not possible, this calls C<nbdkit_error> and returns
C<NULL>.  Note that this function does not check that the file exists.

The returned string must be freed by the caller.

=head1 CALLBACKS

=head2 C<.name>

 const char *name;

This field (a string) is required, and B<must> contain only ASCII
alphanumeric characters and be unique amongst all plugins.

=head2 C<.version>

 const char *version;

Plugins may optionally set a version string which is displayed in help
and debugging output.

=head2 C<.longname>

 const char *longname;

An optional free text name of the plugin.  This field is used in error
messages.

=head2 C<.description>

 const char *description;

An optional multi-line description of the plugin.

=head2 C<.load>

 void load (void);

This is called once just after the plugin is loaded into memory.  You
can use this to perform any global initialization needed by the
plugin.

=head2 C<.unload>

 void unload (void);

This may be called once just before the plugin is unloaded from
memory.  Note that it's not guaranteed that C<.unload> will always be
called (eg. the server might be killed or segfault), so you should try
to make the plugin as robust as possible by not requiring cleanup.

=head2 C<.config>

 int config (const char *key, const char *value);

On the nbdkit command line, after the plugin filename, come an
optional list of C<key=value> arguments.  These are passed to the
plugin through this callback when the plugin is first loaded and
before any connections are accepted.

This callback may be called zero or more times.  Both C<key> and
C<value> parameters will be non-NULL, but it is possible for either to
be empty strings.  The strings are owned by nbdkit but will remain
valid for the lifetime of the plugin, so the plugin does not need to
copy them.

The format of the C<key> accepted by plugins is up to the plugin, but
you should probably look at other plugins and follow the same
conventions.

If the value is a relative path, then note that the server changes
directory when it starts up.  See L</FILENAMES AND PATHS> above.

If the C<.config> callback is not provided by the plugin, and the user
tries to specify any C<key=value> arguments, then nbdkit will exit
with an error.

If there is an error, C<.config> should call C<nbdkit_error> with an
error message and return C<-1>.

=head2 C<.config_complete>

 int config_complete (void);

This optional callback is called after all the configuration has been
passed to the plugin.  It is a good place to do checks, for example
that the user has passed the required parameters to the plugin.

If there is an error, C<.config_complete> should call C<nbdkit_error>
with an error message and return C<-1>.

=head2 C<.config_help>

 const char *config_help;

This optional multi-line help message should summarize any
C<key=value> parameters that it takes.  It does I<not> need to repeat
what already appears in C<.description>.

If the plugin doesn't take any config parameters you should probably
omit this.

=head2 C<.open>

 void *open (int readonly);

This is called when a new client connects to the nbdkit server.  The
callback should allocate a handle and return it.  This handle
is passed back to other callbacks and could be freed in the C<.close>
callback.

Note that the handle is completely opaque to nbdkit, but it must not
be NULL.

The C<readonly> flag informs the plugin that the user requested a
read-only connection using the I<-r> flag on the command line.  Note
that the plugin may I<additionally> force the connection to be
readonly (even if this flag is false) by returning false from the
C<.can_write> callback.  So if your plugin can only serve read-only,
you can ignore this parameter.

If there is an error, C<.open> should call C<nbdkit_error> with an
error message and return C<NULL>.

=head2 C<.close>

 void close (void *handle);

This is called when the client closes the connection.  It should clean
up any per-connection resources.

Note there is no way in the NBD protocol to communicate close errors
back to the client, for example if your plugin calls L<close(2)> and
you are checking for errors (as you should do).  Therefore the best
you can do is to log the error on the server.  Well-behaved NBD
clients I<should> try to flush the connection before it is closed and
check for errors, but obviously this is outside the scope of nbdkit.

=head2 C<.get_size>

 int64_t get_size (void *handle);

This is called during the option negotiation phase of the protocol
to get the size (in bytes) of the block device being exported.

The returned size must be E<ge> 0.  If there is an error, C<.get_size>
should call C<nbdkit_error> with an error message and return C<-1>.

=head2 C<.can_write>

 int can_write (void *handle);

This is called during the option negotiation phase to find out if the
handle supports writes.

If there is an error, C<.can_write> should call C<nbdkit_error> with
an error message and return C<-1>.

This callback is not required.  If omitted, then we return true iff a
C<.pwrite> callback has been defined.

=head2 C<.can_flush>

 int can_flush (void *handle);

This is called during the option negotiation phase to find out if the
handle supports the flush-to-disk operation.

If there is an error, C<.can_flush> should call C<nbdkit_error> with
an error message and return C<-1>.

This callback is not required.  If omitted, then we return true iff a
C<.flush> callback has been defined.

=head2 C<.is_rotational>

 int is_rotational (void *handle);

This is called during the option negotiation phase to find out if the
backing disk is a rotational medium (like a disk) or not (like an
SSD).  If true, this may cause the client to reorder requests to make
them more efficient for a slow rotating disk.

If there is an error, C<.is_rotational> should call C<nbdkit_error>
with an error message and return C<-1>.

This callback is not required.  If omitted, then we return false.

=head2 C<.can_trim>

 int can_trim (void *handle);

This is called during the option negotiation phase to find out if the
plugin supports the trim/discard operation for punching holes in the
backing storage.

If there is an error, C<.can_trim> should call C<nbdkit_error> with an
error message and return C<-1>.

This callback is not required.  If omitted, then we return true iff a
C<.trim> callback has been defined.

=head2 C<.pread>

 int pread (void *handle, void *buf, uint32_t count, uint64_t offset);

During the data serving phase, nbdkit calls this callback to read data
from the backing store.  C<count> bytes starting at C<offset> in the
backing store should be read and copied into C<buf>.  nbdkit takes
care of all bounds- and sanity-checking, so the plugin does not need
to worry about that.

The callback must read the whole C<count> bytes if it can.  The NBD
protocol doesn't allow partial reads (instead, these would be errors).
If the whole C<count> bytes was read, the callback should return C<0>
to indicate there was I<no> error.

If there is an error (including a short read which couldn't be
recovered from), C<.pread> should call C<nbdkit_error> with an error
message and return C<-1>.

=head2 C<.pwrite>

 int pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset);

During the data serving phase, nbdkit calls this callback to write
data to the backing store.  C<count> bytes starting at C<offset> in
the backing store should be written using the data in C<buf>.  nbdkit
takes care of all bounds- and sanity-checking, so the plugin does not
need to worry about that.

The callback must write the whole C<count> bytes if it can.  The NBD
protocol doesn't allow partial writes (instead, these would be
errors).  If the whole C<count> bytes was written successfully, the
callback should return C<0> to indicate there was I<no> error.

If there is an error (including a short write which couldn't be
recovered from), C<.pwrite> should call C<nbdkit_error> with an error
message and return C<-1>.

=head2 C<.flush>

 int flush (void *handle);

During the data serving phase, this callback is used to
L<fdatasync(2)> the backing store, ie. to ensure it has been
completely written to a permanent medium.  If that is not possible
then you can omit this callback.

If there is an error, C<.flush> should call C<nbdkit_error> with an
error message and return C<-1>.

=head2 C<.trim>

 int trim (void *handle, uint32_t count, uint64_t offset);

During the data serving phase, this callback is used to "punch holes"
in the backing store.  If that is not possible then you can omit this
callback.

If there is an error, C<.trim> should call C<nbdkit_error> with an
error message and return C<-1>.

=head1 THREADS

Each nbdkit plugin must declare its thread safety model by defining
the C<THREAD_MODEL> macro.  (This macro is used by
C<NBDKIT_REGISTER_PLUGIN>).

The possible settings for C<THREAD_MODEL> are defined below.

=over 4

=item C<#define THREAD_MODEL NBDKIT_THREAD_MODEL_SERIALIZE_CONNECTIONS>

Only a single handle can be open at any time, and all requests happen
from one thread.

Note this means only one client can connect to the server at any time.
If a second client tries to connect it will block waiting for the
first client to close the connection.

=item C<#define THREAD_MODEL NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS>

I<This is a safe default for most plugins>.

Multiple handles can be open at the same time, but data requests are
serialized so that for the plugin as a whole only one read/write/etc
request will be in progress at any time.

This is a useful setting if the library you are using is not
thread-safe.  However performance may not be good.

=item C<#define THREAD_MODEL NBDKIT_THREAD_MODEL_SERIALIZE_REQUESTS>

Multiple handles can be open and multiple data requests can happen in
parallel.  However only one request will happen per handle at a time
(but requests on different handles might happen concurrently).

=item C<#define THREAD_MODEL NBDKIT_THREAD_MODEL_PARALLEL>

Multiple handles can be open and multiple data requests can happen in
parallel (even on the same handle).

All the libraries you use must be thread-safe and reentrant.  You may
also need to provide mutexes for fields in your connection handle.

=back

If none of the above thread models are suitable, then use
C<NBDKIT_THREAD_MODEL_PARALLEL> and implement your own locking using
C<pthread_mutex_t> etc.

=head1 PARSING SIZE PARAMETERS

Use the C<nbdkit_parse_size> utility function to parse human-readable
size strings such as "100M" into the size in bytes.

 int64_t nbdkit_parse_size (const char *str);

C<str> can be a string in a number of common formats.  The function
returns the size in bytes.  If there was an error, it returns C<-1>.

=head1 DEBUGGING

Run the server with I<-f> and I<-v> options so it doesn't fork and you
can see debugging information:

 nbdkit -fv ./myplugin.so [key=value [key=value [...]]]

To print debugging information from within the plugin, call
C<nbdkit_debug>, which has the following prototype and works like
L<printf(3)>:

 void nbdkit_debug (const char *fs, ...);

Note that C<nbdkit_debug> only prints things when the server is in
verbose mode (I<-v> option).

=head1 INSTALLING THE PLUGIN

The plugin is a C<*.so> file and possibly a manual page.  You can of
course install the plugin C<*.so> file wherever you want, and users
will be able to use it by running:

 nbdkit /path/to/plugin.so [args]

However B<if> the shared library has a name of the form
C<nbdkit-I<name>-plugin.so> B<and if> the library is installed in the
C<$plugindir> directory, then users can be run it by only typing:

 nbdkit name [args]

The location of the C<$plugindir> directory is set when nbdkit is
compiled and can be found by doing:

 nbdkit --dump-config

=head1 WRITING PLUGINS IN OTHER PROGRAMMING LANGUAGES

You can also write nbdkit plugins in Perl or Python.  Other
programming languages may be offered in future.

For more information see:
L<nbdkit-perl-plugin(3)>,
L<nbdkit-python-plugin(3)>.

=head1 SEE ALSO

L<nbdkit(1)>,
L<nbdkit-example1-plugin(1)>,
L<nbdkit-example2-plugin(1)>,
L<nbdkit-example3-plugin(1)>,
L<nbdkit-perl-plugin(3)>,
L<nbdkit-python-plugin(3)>.

=head1 AUTHORS

Richard W.M. Jones

=head1 COPYRIGHT

Copyright (C) 2013 Red Hat Inc.

=head1 LICENSE

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

=over 4

=item *

Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

=item *

Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

=item *

Neither the name of Red Hat nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.

=back

THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.