2 * Copyright (C) 2013 Red Hat Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * * Neither the name of Red Hat nor the names of its contributors may be
17 * used to endorse or promote products derived from this software without
18 * specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
27 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 #include "nbdkit-plugin.h"
48 static pthread_mutex_t connection_lock
= PTHREAD_MUTEX_INITIALIZER
;
49 static pthread_mutex_t all_requests_lock
= PTHREAD_MUTEX_INITIALIZER
;
51 /* Currently the server can only load one plugin (see TODO). Hence we
52 * can just use globals to store these.
54 static const char *filename
;
56 static struct nbdkit_plugin plugin
;
59 plugin_register (const char *_filename
,
60 void *_dl
, struct nbdkit_plugin
*(*plugin_init
) (void))
62 const struct nbdkit_plugin
*_plugin
;
68 debug ("registering %s", filename
);
70 /* Call the initialization function which returns the address of the
71 * plugin's own 'struct nbdkit_plugin'.
73 _plugin
= plugin_init ();
75 fprintf (stderr
, "%s: %s: plugin registration function failed\n",
76 program_name
, filename
);
80 /* Check for incompatible future versions. */
81 if (_plugin
->_api_version
!= 1) {
82 fprintf (stderr
, "%s: %s: plugin is incompatible with this version of nbdkit (_api_version = %d)\n",
83 program_name
, filename
, _plugin
->_api_version
);
87 /* Since the plugin might be much older than the current version of
88 * nbdkit, only copy up to the self-declared _struct_size of the
89 * plugin and zero out the rest. If the plugin is much newer then
90 * we'll only call the "old" fields.
92 size
= sizeof plugin
; /* our struct */
93 memset (&plugin
, 0, size
);
94 if (size
> _plugin
->_struct_size
)
95 size
= _plugin
->_struct_size
;
96 memcpy (&plugin
, _plugin
, size
);
98 /* Check for the minimum fields which must exist in the
101 if (plugin
.name
== NULL
) {
102 fprintf (stderr
, "%s: %s: plugin must have a .name field\n",
103 program_name
, filename
);
106 if (plugin
.open
== NULL
) {
107 fprintf (stderr
, "%s: %s: plugin must have a .open callback\n",
108 program_name
, filename
);
111 if (plugin
.get_size
== NULL
) {
112 fprintf (stderr
, "%s: %s: plugin must have a .get_size callback\n",
113 program_name
, filename
);
116 if (plugin
.pread
== NULL
) {
117 fprintf (stderr
, "%s: %s: plugin must have a .pread callback\n",
118 program_name
, filename
);
122 len
= strlen (plugin
.name
);
124 fprintf (stderr
, "%s: %s: plugin.name field must not be empty\n",
125 program_name
, filename
);
128 for (i
= 0; i
< len
; ++i
) {
129 if (!((plugin
.name
[i
] >= '0' && plugin
.name
[i
] <= '9') ||
130 (plugin
.name
[i
] >= 'a' && plugin
.name
[i
] <= 'z') ||
131 (plugin
.name
[i
] >= 'A' && plugin
.name
[i
] <= 'Z'))) {
132 fprintf (stderr
, "%s: %s: plugin.name ('%s') field must contain only ASCII alphanumeric characters\n",
133 program_name
, filename
, plugin
.name
);
138 debug ("registered %s (name %s)", filename
, plugin
.name
);
140 /* Call the on-load callback if it exists. */
141 debug ("%s: load", filename
);
147 plugin_cleanup (void)
150 debug ("%s: unload", filename
);
172 printf ("%s", plugin
.name
);
174 printf (" (%s)", plugin
.longname
);
176 if (plugin
.description
) {
178 printf ("%s\n", plugin
.description
);
180 if (plugin
.config_help
) {
182 printf ("%s\n", plugin
.config_help
);
187 plugin_version (void)
191 printf ("%s", plugin
.name
);
193 printf (" %s", plugin
.version
);
198 plugin_config (const char *key
, const char *value
)
202 debug ("%s: config key=%s, value=%s",
203 filename
, key
, value
);
205 if (plugin
.config
== NULL
) {
206 fprintf (stderr
, "%s: %s: this plugin does not need command line configuration\n"
207 "Try using: %s --help %s\n",
208 program_name
, filename
,
209 program_name
, filename
);
213 if (plugin
.config (key
, value
) == -1)
218 plugin_config_complete (void)
222 debug ("%s: config_complete", filename
);
224 if (!plugin
.config_complete
)
227 if (plugin
.config_complete () == -1)
231 /* Handle the thread model. */
233 plugin_lock_connection (void)
237 if (plugin
._thread_model
<= NBDKIT_THREAD_MODEL_SERIALIZE_CONNECTIONS
) {
238 debug ("%s: acquire connection lock", filename
);
239 pthread_mutex_lock (&connection_lock
);
244 plugin_unlock_connection (void)
248 if (plugin
._thread_model
<= NBDKIT_THREAD_MODEL_SERIALIZE_CONNECTIONS
) {
249 debug ("%s: release connection lock", filename
);
250 pthread_mutex_unlock (&connection_lock
);
255 plugin_lock_request (struct connection
*conn
)
259 if (plugin
._thread_model
<= NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS
) {
260 debug ("acquire global request lock");
261 pthread_mutex_lock (&all_requests_lock
);
264 if (plugin
._thread_model
<= NBDKIT_THREAD_MODEL_SERIALIZE_REQUESTS
) {
265 debug ("acquire per-connection request lock");
266 pthread_mutex_lock (&conn
->request_lock
);
271 plugin_unlock_request (struct connection
*conn
)
275 if (plugin
._thread_model
<= NBDKIT_THREAD_MODEL_SERIALIZE_REQUESTS
) {
276 debug ("release per-connection request lock");
277 pthread_mutex_unlock (&conn
->request_lock
);
280 if (plugin
._thread_model
<= NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS
) {
281 debug ("release global request lock");
282 pthread_mutex_unlock (&all_requests_lock
);
287 plugin_open (struct connection
*conn
, int readonly
)
292 assert (conn
->handle
== NULL
);
293 assert (plugin
.open
!= NULL
);
295 debug ("%s: open readonly=%d", filename
, readonly
);
297 handle
= plugin
.open (readonly
);
301 conn
->handle
= handle
;
306 plugin_close (struct connection
*conn
)
309 assert (conn
->handle
);
314 plugin
.close (conn
->handle
);
320 plugin_get_size (struct connection
*conn
)
323 assert (conn
->handle
);
324 assert (plugin
.get_size
!= NULL
);
328 return plugin
.get_size (conn
->handle
);
332 plugin_can_write (struct connection
*conn
)
335 assert (conn
->handle
);
339 if (plugin
.can_write
)
340 return plugin
.can_write (conn
->handle
);
342 return plugin
.pwrite
!= NULL
;
346 plugin_can_flush (struct connection
*conn
)
349 assert (conn
->handle
);
353 if (plugin
.can_flush
)
354 return plugin
.can_flush (conn
->handle
);
356 return plugin
.flush
!= NULL
;
360 plugin_is_rotational (struct connection
*conn
)
363 assert (conn
->handle
);
365 debug ("is_rotational");
367 if (plugin
.is_rotational
)
368 return plugin
.is_rotational (conn
->handle
);
370 return 0; /* assume false */
374 plugin_can_trim (struct connection
*conn
)
377 assert (conn
->handle
);
382 return plugin
.can_trim (conn
->handle
);
384 return plugin
.trim
!= NULL
;
388 plugin_pread (struct connection
*conn
,
389 void *buf
, uint32_t count
, uint64_t offset
)
392 assert (conn
->handle
);
393 assert (plugin
.pread
!= NULL
);
395 debug ("pread count=%" PRIu32
" offset=%" PRIu64
, count
, offset
);
397 return plugin
.pread (conn
->handle
, buf
, count
, offset
);
401 plugin_pwrite (struct connection
*conn
,
402 void *buf
, uint32_t count
, uint64_t offset
)
405 assert (conn
->handle
);
407 debug ("pwrite count=%" PRIu32
" offset=%" PRIu64
, count
, offset
);
409 if (plugin
.pwrite
!= NULL
)
410 return plugin
.pwrite (conn
->handle
, buf
, count
, offset
);
418 plugin_flush (struct connection
*conn
)
421 assert (conn
->handle
);
425 if (plugin
.flush
!= NULL
)
426 return plugin
.flush (conn
->handle
);
434 plugin_trim (struct connection
*conn
, uint32_t count
, uint64_t offset
)
437 assert (conn
->handle
);
439 debug ("trim count=%" PRIu32
" offset=%" PRIu64
, count
, offset
);
441 if (plugin
.trim
!= NULL
)
442 return plugin
.trim (conn
->handle
, count
, offset
);