This patch isn't complete (patch 6/6 isn't finished) so it's just for
discussion, although it does compile and run.
This introduces to nbdkit a concept of "filters" which can be placed
in front of plugins to modify their behaviour. Some examples where
you might use filters:
* Serve a subset of the data, such as (offset, range) or a
single partition from a disk image.
* Inject delays or errors for testing clients.
* Implement "copy-on-write" (a feature found in other NBD servers).
Filters are implemented by allowing them to intercept methods before a
plugin gets them. For example to implement a read delay the filter
would register for a .pread hook which is implemented like this:
static int
delay_pread (void *handle, void *buf, uint32_t count, uint64_t offset,
int (*next) (void *data,
void *buf, uint32_t count, uint64_t offset),
void *data)
{
nanosleep (...);
return next (data, buf, count, offset); // calls next filter or plugin
}
...
static struct nbdkit_filter filter = {
...
.pread = delay_pread,
...
};
For the filters I want to write this works fine, but with two caveats:
(1) If new datapath methods are introduced then filters won't get to
see them by default. For example, if we modify offsets when calling
.pread and .pwrite, and then later the .zero method is added to
plugins, then existing filters won't modify the parameters of .zero
correctly (resulting in wrong data being zeroed).
(2) You cannot do anything more complex in one of these functions than
calling the single underlying plugin method, possibly modifying the
arguments. For example it's hard to see how a "qcow2 decoder" filter
could be written since it would need to have full access to the plugin
methods, not just to the single method.
Unfortunately solving (1) & (2) makes the whole thing a lot more
complicated.
Rich.