[Libguestfs] [PATCH nbdkit INCOMPLETE 6/6] filters: Implement chain of filters in front of ordinary plugin methods.
Richard W.M. Jones
rjones at redhat.com
Mon Jan 15 09:00:58 UTC 2018
Here's a fixed 6/6 patch. However I think this approach is wrong so
I'm going to try to come up with an alternative way.
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-builder quickly builds VMs from scratch
http://libguestfs.org/virt-builder.1.html
-------------- next part --------------
>From 7afbdf9da4608abcf0993fc1be95554639a6a415 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones at redhat.com>
Date: Sat, 13 Jan 2018 22:24:49 +0000
Subject: [PATCH 6/6] filters: Implement chain of filters in front of ordinary
plugin methods.
---
src/connections.c | 33 +++++-
src/internal.h | 4 +-
src/plugins.c | 315 +++++++++++++++++++++++++++++++++++++++++++++++++-----
3 files changed, 321 insertions(+), 31 deletions(-)
diff --git a/src/connections.c b/src/connections.c
index 111a810..afa6107 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -69,10 +69,13 @@ struct connection {
pthread_mutex_t write_lock;
pthread_mutex_t status_lock;
int status; /* 1 for more I/O with client, 0 for shutdown, -1 on error */
- void *handle;
void *crypto_session;
int nworkers;
+ void *handle;
+ void **filter_handles;
+ size_t nr_filter_handles;
+
uint64_t exportsize;
int readonly;
int can_flush;
@@ -112,6 +115,34 @@ connection_get_handle (struct connection *conn)
return conn->handle;
}
+int
+connection_set_filter_handle (struct connection *conn, size_t i, void *handle)
+{
+ if (i < conn->nr_filter_handles)
+ conn->filter_handles[i] = handle;
+ else {
+ conn->nr_filter_handles = i+1;
+ conn->filter_handles = realloc (conn->filter_handles,
+ conn->nr_filter_handles * sizeof (void *));
+ if (conn->filter_handles == NULL) {
+ perror ("realloc");
+ conn->nr_filter_handles = 0;
+ return -1;
+ }
+ conn->filter_handles[i] = handle;
+ }
+ return 0;
+}
+
+void *
+connection_get_filter_handle (struct connection *conn, size_t i)
+{
+ if (i < conn->nr_filter_handles)
+ return conn->filter_handles[i];
+ else
+ return NULL;
+}
+
pthread_mutex_t *
connection_get_request_lock (struct connection *conn)
{
diff --git a/src/internal.h b/src/internal.h
index 86cb0aa..ac33e50 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -126,6 +126,8 @@ typedef void (*connection_close_function) (struct connection *);
extern int handle_single_connection (int sockin, int sockout);
extern void connection_set_handle (struct connection *conn, void *handle);
extern void *connection_get_handle (struct connection *conn);
+extern int connection_set_filter_handle (struct connection *conn, size_t i, void *handle);
+extern void *connection_get_filter_handle (struct connection *conn, size_t i);
extern pthread_mutex_t *connection_get_request_lock (struct connection *conn);
extern void connection_set_crypto_session (struct connection *conn, void *session);
extern void *connection_get_crypto_session (struct connection *conn);
@@ -166,7 +168,7 @@ extern int plugin_can_flush (struct connection *conn);
extern int plugin_is_rotational (struct connection *conn);
extern int plugin_can_trim (struct connection *conn);
extern int plugin_pread (struct connection *conn, void *buf, uint32_t count, uint64_t offset);
-extern int plugin_pwrite (struct connection *conn, void *buf, uint32_t count, uint64_t offset);
+extern int plugin_pwrite (struct connection *conn, const void *buf, uint32_t count, uint64_t offset);
extern int plugin_flush (struct connection *conn);
extern int plugin_trim (struct connection *conn, uint32_t count, uint64_t offset);
extern int plugin_zero (struct connection *conn, uint32_t count, uint64_t offset, int may_trim);
diff --git a/src/plugins.c b/src/plugins.c
index 3600293..490ff3d 100644
--- a/src/plugins.c
+++ b/src/plugins.c
@@ -53,6 +53,7 @@
*/
struct filter {
struct filter *next;
+ size_t i; /* index of the filter, starting at 0 */
char *filename;
void *dl;
struct nbdkit_filter filter;
@@ -87,10 +88,14 @@ filter_register (const char *_filename,
perror ("malloc");
exit (EXIT_FAILURE);
}
- if (last_filter)
+ if (last_filter) {
last_filter->next = f;
- else
+ f->i = last_filter->i + 1;
+ }
+ else {
filters = f;
+ f->i = 0;
+ }
last_filter = f;
f->next = NULL;
@@ -406,8 +411,37 @@ plugin_dump_fields (void)
plugin.dump_plugin ();
}
-void
-plugin_config (const char *key, const char *value)
+/* For UNPACK trick, see: https://stackoverflow.com/a/35999754 */
+#define UNPACK(...) __VA_ARGS__
+#define CALL_FILTERS_1(method, comma_args_decl, comma_args, args, args_comma) \
+ static int \
+ filter_##method (void *datav UNPACK comma_args_decl) \
+ { \
+ struct filter *f = datav; \
+ \
+ if (f == NULL) \
+ return final_##method (UNPACK args); \
+ else { \
+ if (f->filter.method) { \
+ /* XXX Print args. */ \
+ debug ("%s: %s", f->filename, #method); \
+ if (f->filter.method (UNPACK args_comma \
+ filter_##method, f->next) == -1) \
+ return -1; \
+ return 0; \
+ } \
+ else \
+ return filter_##method (f->next UNPACK comma_args); \
+ } \
+ }
+#define CALL_FILTERS(method, args_decl, args) \
+ CALL_FILTERS_1 (method, (, UNPACK args_decl), \
+ (, UNPACK args), args, (UNPACK args,))
+#define CALL_FILTERS_NO_ARGS(method) \
+ CALL_FILTERS_1 (method, (), (), (), ())
+
+static int
+final_config (const char *key, const char *value)
{
assert (dl);
@@ -422,21 +456,37 @@ plugin_config (const char *key, const char *value)
exit (EXIT_FAILURE);
}
- if (plugin.config (key, value) == -1)
- exit (EXIT_FAILURE);
+ return plugin.config (key, value);
}
+CALL_FILTERS (config, (const char *key, const char *value), (key, value))
+
void
-plugin_config_complete (void)
+plugin_config (const char *key, const char *value)
+{
+ if (filter_config (filters, key, value) == -1)
+ exit (EXIT_FAILURE);
+}
+
+static int
+final_config_complete (void)
{
assert (dl);
debug ("%s: config_complete", filename);
if (!plugin.config_complete)
- return;
+ return 0;
+
+ return plugin.config_complete ();
+}
+
+CALL_FILTERS_NO_ARGS (config_complete)
- if (plugin.config_complete () == -1)
+void
+plugin_config_complete (void)
+{
+ if (filter_config_complete (filters) == -1)
exit (EXIT_FAILURE);
}
@@ -509,8 +559,48 @@ plugin_errno_is_preserved (void)
return plugin.errno_is_preserved;
}
-int
-plugin_open (struct connection *conn, int readonly)
+struct data {
+ struct connection *conn;
+ struct filter *f;
+};
+
+#undef CALL_FILTERS_1
+#undef CALL_FILTERS
+#undef CALL_FILTERS_NO_ARGS
+
+#define CALL_FILTERS_1(method, ret_type, comma_args_decl, comma_args, args, args_comma) \
+ static ret_type \
+ filter_##method (void *datav UNPACK comma_args_decl) \
+ { \
+ struct data *data = datav; \
+ struct connection *conn = data->conn; \
+ struct filter *f = data->f; \
+ void *handle; \
+ \
+ if (f == NULL) \
+ return final_##method (conn UNPACK comma_args); \
+ else { \
+ data->f = data->f->next; \
+ \
+ if (f->filter.method) { \
+ /* XXX Print args. */ \
+ debug ("%s: %s", f->filename, #method); \
+ handle = connection_get_filter_handle (conn, f->i); \
+ return f->filter.method (handle, UNPACK args_comma \
+ filter_##method, data); \
+ } \
+ else \
+ return filter_##method (data UNPACK comma_args); \
+ } \
+ }
+#define CALL_FILTERS(method, ret_type, args_decl, args) \
+ CALL_FILTERS_1 (method, ret_type, (, UNPACK args_decl), \
+ (, UNPACK args), args, (UNPACK args,))
+#define CALL_FILTERS_NO_ARGS(method, ret_type) \
+ CALL_FILTERS_1 (method, ret_type, (), (), (), ())
+
+static int
+final_open (struct connection *conn, int readonly)
{
void *handle;
@@ -528,8 +618,43 @@ plugin_open (struct connection *conn, int readonly)
return 0;
}
-void
-plugin_close (struct connection *conn)
+static int
+filter_open (void *datav, int readonly)
+{
+ struct data *data = datav;
+ struct connection *conn = data->conn;
+ struct filter *f = data->f;
+ void *handle;
+
+ if (f == NULL)
+ return final_open (conn, readonly);
+ else {
+ data->f = data->f->next;
+
+ if (f->filter.open) {
+ debug ("%s: open readonly=%d", f->filename, readonly);
+ handle = f->filter.open (readonly, filter_open, data);
+ if (!handle)
+ return -1;
+
+ if (connection_set_filter_handle (conn, f->i, handle) == -1)
+ return -1;
+ return 0;
+ }
+ else
+ return filter_open (data, readonly);
+ }
+}
+
+int
+plugin_open (struct connection *conn, int readonly)
+{
+ struct data data = { .conn = conn, .f = filters };
+ return filter_open (&data, readonly);
+}
+
+static void
+final_close (struct connection *conn)
{
assert (dl);
assert (connection_get_handle (conn));
@@ -542,8 +667,39 @@ plugin_close (struct connection *conn)
connection_set_handle (conn, NULL);
}
-int64_t
-plugin_get_size (struct connection *conn)
+static void
+filter_close (void *datav)
+{
+ struct data *data = datav;
+ struct connection *conn = data->conn;
+ struct filter *f = data->f;
+ void *handle;
+
+ if (f == NULL)
+ final_close (conn);
+ else {
+ data->f = data->f->next;
+
+ if (f->filter.close) {
+ debug ("%s: close", data->f->filename);
+ handle = connection_get_filter_handle (conn, f->i);
+ f->filter.close (handle, filter_close, data);
+ }
+ else
+ filter_close (data);
+ connection_set_filter_handle (conn, f->i, NULL);
+ }
+}
+
+void
+plugin_close (struct connection *conn)
+{
+ struct data data = { .conn = conn, .f = filters };
+ filter_close (&data);
+}
+
+static int64_t
+final_get_size (struct connection *conn)
{
assert (dl);
assert (connection_get_handle (conn));
@@ -554,8 +710,17 @@ plugin_get_size (struct connection *conn)
return plugin.get_size (connection_get_handle (conn));
}
-int
-plugin_can_write (struct connection *conn)
+CALL_FILTERS_NO_ARGS (get_size, int64_t)
+
+int64_t
+plugin_get_size (struct connection *conn)
+{
+ struct data data = { .conn = conn, .f = filters };
+ return filter_get_size (&data);
+}
+
+static int
+final_can_write (struct connection *conn)
{
assert (dl);
assert (connection_get_handle (conn));
@@ -568,8 +733,17 @@ plugin_can_write (struct connection *conn)
return plugin.pwrite != NULL;
}
+CALL_FILTERS_NO_ARGS (can_write, int)
+
int
-plugin_can_flush (struct connection *conn)
+plugin_can_write (struct connection *conn)
+{
+ struct data data = { .conn = conn, .f = filters };
+ return filter_can_write (&data);
+}
+
+static int
+final_can_flush (struct connection *conn)
{
assert (dl);
assert (connection_get_handle (conn));
@@ -582,8 +756,17 @@ plugin_can_flush (struct connection *conn)
return plugin.flush != NULL;
}
+CALL_FILTERS_NO_ARGS (can_flush, int)
+
int
-plugin_is_rotational (struct connection *conn)
+plugin_can_flush (struct connection *conn)
+{
+ struct data data = { .conn = conn, .f = filters };
+ return filter_can_flush (&data);
+}
+
+static int
+final_is_rotational (struct connection *conn)
{
assert (dl);
assert (connection_get_handle (conn));
@@ -596,8 +779,17 @@ plugin_is_rotational (struct connection *conn)
return 0; /* assume false */
}
+CALL_FILTERS_NO_ARGS (is_rotational, int)
+
int
-plugin_can_trim (struct connection *conn)
+plugin_is_rotational (struct connection *conn)
+{
+ struct data data = { .conn = conn, .f = filters };
+ return filter_is_rotational (&data);
+}
+
+static int
+final_can_trim (struct connection *conn)
{
assert (dl);
assert (connection_get_handle (conn));
@@ -610,9 +802,18 @@ plugin_can_trim (struct connection *conn)
return plugin.trim != NULL;
}
+CALL_FILTERS_NO_ARGS (can_trim, int)
+
int
-plugin_pread (struct connection *conn,
- void *buf, uint32_t count, uint64_t offset)
+plugin_can_trim (struct connection *conn)
+{
+ struct data data = { .conn = conn, .f = filters };
+ return filter_can_trim (&data);
+}
+
+static int
+final_pread (struct connection *conn,
+ void *buf, uint32_t count, uint64_t offset)
{
assert (dl);
assert (connection_get_handle (conn));
@@ -623,9 +824,21 @@ plugin_pread (struct connection *conn,
return plugin.pread (connection_get_handle (conn), buf, count, offset);
}
+CALL_FILTERS (pread, int,
+ (void *buf, uint32_t count, uint64_t offset),
+ (buf, count, offset))
+
int
-plugin_pwrite (struct connection *conn,
- void *buf, uint32_t count, uint64_t offset)
+plugin_pread (struct connection *conn,
+ void *buf, uint32_t count, uint64_t offset)
+{
+ struct data data = { .conn = conn, .f = filters };
+ return filter_pread (&data, buf, count, offset);
+}
+
+static int
+final_pwrite (struct connection *conn,
+ const void *buf, uint32_t count, uint64_t offset)
{
assert (dl);
assert (connection_get_handle (conn));
@@ -640,8 +853,20 @@ plugin_pwrite (struct connection *conn,
}
}
+CALL_FILTERS (pwrite, int,
+ (const void *buf, uint32_t count, uint64_t offset),
+ (buf, count, offset))
+
int
-plugin_flush (struct connection *conn)
+plugin_pwrite (struct connection *conn,
+ const void *buf, uint32_t count, uint64_t offset)
+{
+ struct data data = { .conn = conn, .f = filters };
+ return filter_pwrite (&data, buf, count, offset);
+}
+
+static int
+final_flush (struct connection *conn)
{
assert (dl);
assert (connection_get_handle (conn));
@@ -656,8 +881,17 @@ plugin_flush (struct connection *conn)
}
}
+CALL_FILTERS_NO_ARGS (flush, int)
+
int
-plugin_trim (struct connection *conn, uint32_t count, uint64_t offset)
+plugin_flush (struct connection *conn)
+{
+ struct data data = { .conn = conn, .f = filters };
+ return filter_flush (&data);
+}
+
+static int
+final_trim (struct connection *conn, uint32_t count, uint64_t offset)
{
assert (dl);
assert (connection_get_handle (conn));
@@ -672,9 +906,20 @@ plugin_trim (struct connection *conn, uint32_t count, uint64_t offset)
}
}
+CALL_FILTERS (trim, int,
+ (uint32_t count, uint64_t offset),
+ (count, offset))
+
int
-plugin_zero (struct connection *conn,
- uint32_t count, uint64_t offset, int may_trim)
+plugin_trim (struct connection *conn, uint32_t count, uint64_t offset)
+{
+ struct data data = { .conn = conn, .f = filters };
+ return filter_trim (&data, count, offset);
+}
+
+static int
+final_zero (struct connection *conn,
+ uint32_t count, uint64_t offset, int may_trim)
{
assert (dl);
assert (connection_get_handle (conn));
@@ -710,7 +955,7 @@ plugin_zero (struct connection *conn,
}
while (count) {
- result = plugin.pwrite (connection_get_handle (conn), buf, limit, offset);
+ result = plugin_pwrite (conn, buf, limit, offset);
if (result < 0)
break;
count -= limit;
@@ -723,3 +968,15 @@ plugin_zero (struct connection *conn,
errno = err;
return result;
}
+
+CALL_FILTERS (zero, int,
+ (uint32_t count, uint64_t offset, int may_trim),
+ (count, offset, may_trim))
+
+int
+plugin_zero (struct connection *conn,
+ uint32_t count, uint64_t offset, int may_trim)
+{
+ struct data data = { .conn = conn, .f = filters };
+ return filter_zero (&data, count, offset, may_trim);
+}
--
2.15.1
More information about the Libguestfs
mailing list