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 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
;
65 filename
= strdup (_filename
);
66 if (filename
== NULL
) {
72 debug ("registering %s", filename
);
74 /* Call the initialization function which returns the address of the
75 * plugin's own 'struct nbdkit_plugin'.
77 _plugin
= plugin_init ();
79 fprintf (stderr
, "%s: %s: plugin registration function failed\n",
80 program_name
, filename
);
84 /* Check for incompatible future versions. */
85 if (_plugin
->_api_version
!= 1) {
86 fprintf (stderr
, "%s: %s: plugin is incompatible with this version of nbdkit (_api_version = %d)\n",
87 program_name
, filename
, _plugin
->_api_version
);
91 /* Since the plugin might be much older than the current version of
92 * nbdkit, only copy up to the self-declared _struct_size of the
93 * plugin and zero out the rest. If the plugin is much newer then
94 * we'll only call the "old" fields.
96 size
= sizeof plugin
; /* our struct */
97 memset (&plugin
, 0, size
);
98 if (size
> _plugin
->_struct_size
)
99 size
= _plugin
->_struct_size
;
100 memcpy (&plugin
, _plugin
, size
);
102 /* Check for the minimum fields which must exist in the
105 if (plugin
.name
== NULL
) {
106 fprintf (stderr
, "%s: %s: plugin must have a .name field\n",
107 program_name
, filename
);
110 if (plugin
.open
== NULL
) {
111 fprintf (stderr
, "%s: %s: plugin must have a .open callback\n",
112 program_name
, filename
);
115 if (plugin
.get_size
== NULL
) {
116 fprintf (stderr
, "%s: %s: plugin must have a .get_size callback\n",
117 program_name
, filename
);
120 if (plugin
.pread
== NULL
) {
121 fprintf (stderr
, "%s: %s: plugin must have a .pread callback\n",
122 program_name
, filename
);
126 len
= strlen (plugin
.name
);
128 fprintf (stderr
, "%s: %s: plugin.name field must not be empty\n",
129 program_name
, filename
);
132 for (i
= 0; i
< len
; ++i
) {
133 if (!((plugin
.name
[i
] >= '0' && plugin
.name
[i
] <= '9') ||
134 (plugin
.name
[i
] >= 'a' && plugin
.name
[i
] <= 'z') ||
135 (plugin
.name
[i
] >= 'A' && plugin
.name
[i
] <= 'Z'))) {
136 fprintf (stderr
, "%s: %s: plugin.name ('%s') field must contain only ASCII alphanumeric characters\n",
137 program_name
, filename
, plugin
.name
);
142 debug ("registered %s (name %s)", filename
, plugin
.name
);
144 /* Call the on-load callback if it exists. */
145 debug ("%s: load", filename
);
151 plugin_cleanup (void)
154 debug ("%s: unload", filename
);
178 printf ("%s", plugin
.name
);
180 printf (" (%s)", plugin
.longname
);
182 if (plugin
.description
) {
184 printf ("%s\n", plugin
.description
);
186 if (plugin
.config_help
) {
188 printf ("%s\n", plugin
.config_help
);
193 plugin_version (void)
197 printf ("%s", plugin
.name
);
199 printf (" %s", plugin
.version
);
204 plugin_config (const char *key
, const char *value
)
208 debug ("%s: config key=%s, value=%s",
209 filename
, key
, value
);
211 if (plugin
.config
== NULL
) {
212 fprintf (stderr
, "%s: %s: this plugin does not need command line configuration\n"
213 "Try using: %s --help %s\n",
214 program_name
, filename
,
215 program_name
, filename
);
219 if (plugin
.config (key
, value
) == -1)
224 plugin_config_complete (void)
228 debug ("%s: config_complete", filename
);
230 if (!plugin
.config_complete
)
233 if (plugin
.config_complete () == -1)
237 /* Handle the thread model. */
239 plugin_lock_connection (void)
243 if (plugin
._thread_model
<= NBDKIT_THREAD_MODEL_SERIALIZE_CONNECTIONS
) {
244 debug ("%s: acquire connection lock", filename
);
245 pthread_mutex_lock (&connection_lock
);
250 plugin_unlock_connection (void)
254 if (plugin
._thread_model
<= NBDKIT_THREAD_MODEL_SERIALIZE_CONNECTIONS
) {
255 debug ("%s: release connection lock", filename
);
256 pthread_mutex_unlock (&connection_lock
);
261 plugin_lock_request (struct connection
*conn
)
265 if (plugin
._thread_model
<= NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS
) {
266 debug ("acquire global request lock");
267 pthread_mutex_lock (&all_requests_lock
);
270 if (plugin
._thread_model
<= NBDKIT_THREAD_MODEL_SERIALIZE_REQUESTS
) {
271 debug ("acquire per-connection request lock");
272 pthread_mutex_lock (&conn
->request_lock
);
277 plugin_unlock_request (struct connection
*conn
)
281 if (plugin
._thread_model
<= NBDKIT_THREAD_MODEL_SERIALIZE_REQUESTS
) {
282 debug ("release per-connection request lock");
283 pthread_mutex_unlock (&conn
->request_lock
);
286 if (plugin
._thread_model
<= NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS
) {
287 debug ("release global request lock");
288 pthread_mutex_unlock (&all_requests_lock
);
293 plugin_open (struct connection
*conn
, int readonly
)
298 assert (conn
->handle
== NULL
);
299 assert (plugin
.open
!= NULL
);
301 debug ("%s: open readonly=%d", filename
, readonly
);
303 handle
= plugin
.open (readonly
);
307 conn
->handle
= handle
;
312 plugin_close (struct connection
*conn
)
315 assert (conn
->handle
);
320 plugin
.close (conn
->handle
);
326 plugin_get_size (struct connection
*conn
)
329 assert (conn
->handle
);
330 assert (plugin
.get_size
!= NULL
);
334 return plugin
.get_size (conn
->handle
);
338 plugin_can_write (struct connection
*conn
)
341 assert (conn
->handle
);
345 if (plugin
.can_write
)
346 return plugin
.can_write (conn
->handle
);
348 return plugin
.pwrite
!= NULL
;
352 plugin_can_flush (struct connection
*conn
)
355 assert (conn
->handle
);
359 if (plugin
.can_flush
)
360 return plugin
.can_flush (conn
->handle
);
362 return plugin
.flush
!= NULL
;
366 plugin_is_rotational (struct connection
*conn
)
369 assert (conn
->handle
);
371 debug ("is_rotational");
373 if (plugin
.is_rotational
)
374 return plugin
.is_rotational (conn
->handle
);
376 return 0; /* assume false */
380 plugin_can_trim (struct connection
*conn
)
383 assert (conn
->handle
);
388 return plugin
.can_trim (conn
->handle
);
390 return plugin
.trim
!= NULL
;
394 plugin_pread (struct connection
*conn
,
395 void *buf
, uint32_t count
, uint64_t offset
)
398 assert (conn
->handle
);
399 assert (plugin
.pread
!= NULL
);
401 debug ("pread count=%" PRIu32
" offset=%" PRIu64
, count
, offset
);
403 return plugin
.pread (conn
->handle
, buf
, count
, offset
);
407 plugin_pwrite (struct connection
*conn
,
408 void *buf
, uint32_t count
, uint64_t offset
)
411 assert (conn
->handle
);
413 debug ("pwrite count=%" PRIu32
" offset=%" PRIu64
, count
, offset
);
415 if (plugin
.pwrite
!= NULL
)
416 return plugin
.pwrite (conn
->handle
, buf
, count
, offset
);
424 plugin_flush (struct connection
*conn
)
427 assert (conn
->handle
);
431 if (plugin
.flush
!= NULL
)
432 return plugin
.flush (conn
->handle
);
440 plugin_trim (struct connection
*conn
, uint32_t count
, uint64_t offset
)
443 assert (conn
->handle
);
445 debug ("trim count=%" PRIu32
" offset=%" PRIu64
, count
, offset
);
447 if (plugin
.trim
!= NULL
)
448 return plugin
.trim (conn
->handle
, count
, offset
);