Eric Blake
2021-Mar-05 23:31 UTC
[Libguestfs] [nbdkit PATCH v3 00/16] Add multi-conn filter, make filter context more flexible
In v2, I had made the multi-conn filter possible by reverting several patches to make the handle of filters.c a local struct instead of reusing 'struct backend *' from internal.h, and Rich (rightly) complained that it felt like a step backwards. That forced me to rethink about what filters really want, and ultimately (mostly) implement one of our TODO items about letting a filter be able to probe the backend separately from waiting for a connection from the client. I still have more work to do to get the ext2 filter where I want (while .after_fork is a great place to start a thread, we also need a place to end that thread gracefully before .unload, since right now .unload iterates inner-to-outer but cleanup must be done outer-to-inner). But this series has taken me all week to get to this point, so I'll post the progress I've made so far. Eric Blake (16): filters: Slightly reduce promise of nxdata lifetime filters: Temporarily make next_ops->reopen a public function server: Move default_exportname from handle to connection server: Rename struct handle to struct context server: Update signature of backend_open backend: Inline reset_context server: Manage contexts by backend, not int backend: Plumb context through internal callbacks filters: Use struct context for next_ops server: Store nbdkit_next_ops in struct context filters: Use context rather than connection to track c_next filters: New API for plugin context management ext2: Simplify use of next_ops filters: Adjust API for type-safety and merged next_ops/nxdata multi-conn: New filter multi-conn: Knob to limit consistency emulation by export name docs/nbdkit-filter.pod | 349 +++++++----- filters/cache/nbdkit-cache-filter.pod | 5 +- filters/fua/nbdkit-fua-filter.pod | 7 + .../multi-conn/nbdkit-multi-conn-filter.pod | 201 +++++++ filters/nocache/nbdkit-nocache-filter.pod | 1 + filters/noextents/nbdkit-noextents-filter.pod | 1 + .../noparallel/nbdkit-noparallel-filter.pod | 1 + filters/nozero/nbdkit-nozero-filter.pod | 1 + include/nbdkit-filter.h | 125 +++-- configure.ac | 4 +- filters/multi-conn/Makefile.am | 68 +++ tests/Makefile.am | 11 + server/internal.h | 147 ++--- server/backend.c | 458 ++++++++-------- server/connections.c | 25 +- server/extents.c | 21 +- server/filters.c | 251 +++++---- server/nbdkit.syms | 12 +- server/plugins.c | 141 +++-- server/protocol-handshake-newstyle.c | 23 +- server/protocol-handshake.c | 29 +- server/protocol.c | 23 +- filters/cache/blk.h | 16 +- filters/cow/blk.h | 8 +- filters/ext2/io.h | 11 +- filters/partition/partition.h | 4 +- filters/xz/xzfile.h | 6 +- filters/blocksize/blocksize.c | 76 ++- filters/cache/blk.c | 16 +- filters/cache/cache.c | 94 ++-- filters/cacheextents/cacheextents.c | 16 +- filters/checkwrite/checkwrite.c | 32 +- filters/cow/blk.c | 10 +- filters/cow/cow.c | 80 +-- filters/ddrescue/ddrescue.c | 10 +- filters/delay/delay.c | 30 +- filters/error/error.c | 26 +- filters/exitlast/exitlast.c | 2 +- filters/exitwhen/exitwhen.c | 11 +- filters/exportname/exportname.c | 14 +- filters/ext2/ext2.c | 56 +- filters/ext2/io.c | 73 ++- filters/extentlist/extentlist.c | 11 +- filters/fua/fua.c | 38 +- filters/gzip/gzip.c | 32 +- filters/ip/ip.c | 7 +- filters/limit/limit.c | 2 +- filters/log/log.c | 63 +-- filters/multi-conn/multi-conn.c | 515 ++++++++++++++++++ filters/nocache/nocache.c | 6 +- filters/noextents/noextents.c | 2 +- filters/noparallel/noparallel.c | 2 +- filters/nozero/nozero.c | 22 +- filters/offset/offset.c | 33 +- filters/partition/partition-gpt.c | 7 +- filters/partition/partition-mbr.c | 5 +- filters/partition/partition.c | 52 +- filters/pause/pause.c | 31 +- filters/rate/rate.c | 15 +- filters/readahead/readahead.c | 39 +- filters/retry/retry.c | 130 +++-- filters/stats/stats.c | 36 +- filters/swab/swab.c | 32 +- filters/tar/tar.c | 51 +- filters/tls-fallback/tls-fallback.c | 50 +- filters/truncate/truncate.c | 50 +- filters/xz/xz.c | 28 +- filters/xz/xzfile.c | 45 +- tests/test-multi-conn-name.sh | 88 +++ tests/test-multi-conn-plugin.sh | 141 +++++ tests/test-multi-conn.sh | 293 ++++++++++ tests/test-truncate4.sh | 2 +- tests/test-layers-filter.c | 153 +++--- TODO | 43 +- 74 files changed, 3015 insertions(+), 1504 deletions(-) create mode 100644 filters/multi-conn/nbdkit-multi-conn-filter.pod create mode 100644 filters/multi-conn/Makefile.am create mode 100644 filters/multi-conn/multi-conn.c create mode 100755 tests/test-multi-conn-name.sh create mode 100755 tests/test-multi-conn-plugin.sh create mode 100755 tests/test-multi-conn.sh -- 2.30.1
Eric Blake
2021-Mar-05 23:31 UTC
[Libguestfs] [nbdkit PATCH v3 01/16] filters: Slightly reduce promise of nxdata lifetime
We promise (and test-layers verifies) that the pointer value of nxdata passed to everything from .prepare to .finalize will be the same. But the wording was ambiguous on whether that promise extended to the nxdata of .open as well. In practice, this had been possible previously, but will get harder in upcoming patches that want to switch over to a struct context* that is not determined until after the next layer has been opened. So update the wording and test to match our intent. --- docs/nbdkit-filter.pod | 14 +++++++------- tests/test-layers-filter.c | 8 +++----- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/docs/nbdkit-filter.pod b/docs/nbdkit-filter.pod index 98a08ca4..65e56fe5 100644 --- a/docs/nbdkit-filter.pod +++ b/docs/nbdkit-filter.pod @@ -133,15 +133,15 @@ C<nbdkit_next_list_exports>, C<nbdkit_next_default_export>, C<nbdkit_next_open>) and a structure called C<struct nbdkit_next_ops>. These abstract the next plugin or filter in the chain. There is also an opaque pointer C<nxdata> which must be passed along when calling -these functions. The value of C<nxdata> passed to C<.open> has a -stable lifetime that lasts to the corresponding C<.close>, with all +these functions. The value of C<nxdata> passed to C<.prepare> has a +stable lifetime that lasts to the corresponding C<.finalize>, with all intermediate functions (such as C<.pread>) receiving the same value for convenience. Functions where C<nxdata> is not reused are C<.config>, C<.config_complete>, C<.get_ready>, and C<.after_fork>, which are called during initialization outside any connections, and -C<.preconnect>, C<.list_exports>, and C<.default_export>, which are -called based on client connections but prior to the stable lifetime of -C<.open>. +C<.preconnect>, C<.list_exports>, C<.default_export>, and C<.open> +which are called based on client connections but prior to the stable +lifetime of C<.prepare>. =head2 Next config, open and close @@ -865,7 +865,7 @@ extents covering the region C<[offset..offset+count-1]>. struct nbdkit_extents *nbdkit_extents_full ( struct nbdkit_next_ops *next_ops, - nbdkit_backend *nxdata, + void *nxdata, uint32_t count, uint64_t offset, uint32_t flags, int *err); @@ -885,7 +885,7 @@ A convenience function is provided to filters only which makes it easier to ensure that the client only encounters aligned extents. int nbdkit_extents_aligned (struct nbdkit_next_ops *next_ops, - nbdkit_backend *nxdata, + void *nxdata, uint32_t count, uint64_t offset, uint32_t flags, uint32_t align, struct nbdkit_extents *extents, int *err); diff --git a/tests/test-layers-filter.c b/tests/test-layers-filter.c index fcd13830..fc2fcbfd 100644 --- a/tests/test-layers-filter.c +++ b/tests/test-layers-filter.c @@ -1,5 +1,5 @@ /* nbdkit - * Copyright (C) 2018-2020 Red Hat Inc. + * Copyright (C) 2018-2021 Red Hat Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -132,14 +132,12 @@ static void * test_layers_filter_open (nbdkit_next_open *next, void *nxdata, int readonly, const char *exportname, int is_tls) { - struct handle *h = malloc (sizeof *h); + struct handle *h = calloc (1, sizeof *h); if (!h) { perror ("malloc"); exit (1); } - h->nxdata = nxdata; - h->next_ops = NULL; if (next (nxdata, readonly, exportname) == -1) return NULL; @@ -164,8 +162,8 @@ test_layers_filter_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, struct handle *h = handle; assert (h->next_ops == NULL); - assert (h->nxdata == nxdata); h->next_ops = next_ops; + h->nxdata = nxdata; DEBUG_FUNCTION; return 0; } -- 2.30.1
Eric Blake
2021-Mar-05 23:31 UTC
[Libguestfs] [nbdkit PATCH v3 02/16] filters: Temporarily make next_ops->reopen a public function
The reopen operation (key to the retry filter) is enough of an oddball that it does not belong as a function pointer in next_ops; in particular, while most functions in next_ops operate on an existing context, reopen can operate even after a previous failure has left no context, but passing NULL for nxdata to represent no context does not give us the information we need to associate the reopened context back to the right connection. Wrap backend_reopen with a new exported function nbdkit_backend_reopen, and drop the next_ops->reopen function pointer. Note that the function is only declared for the retry filter at this time, and that while at it, I made the retry filter use a bit more type safety. Later patches will perform more mechanical conversion of other filters to be type-safe. The new function depends on guaranteeing that the 'nxdata' passed to .open is stable for usage as the 'backend' parameter to pass to nbdkit_backend_reopen, so I renamed that parameter in the docs. Our testsuite coverage of the retry filter ensures we don't break this. And it gets us one step closer to allowing plugins to open a context into the backend without needing it to be tied to the current connection from the client. In this patch, 'backend' of .open and 'nxdata' of .pread happen to be the same pointer and reopen doesn't affect it, but in the upcoming patches, the two will be distinct pointers, where nxdata can sometimes be NULL on entry to .pread and set back to non-NULL by reopen. Note that the new function is intended to be temporary while I continue to make other refactorings. Ultimately, I want to get to the point where any filter can open up a new context without regards to the current connection, and then optionally associate any context into the current connection (that is, the next_open callback passed to .open will become shorthand for the paired action of nbdkit_backend_open/nbdkit_backend_associate); once that is in place, we don't need nbdkit_backend_reopen because the retry filter can just directly open new connections as needed. --- docs/nbdkit-filter.pod | 51 +++++++++++++++++++++++++++++------------ include/nbdkit-filter.h | 24 +++++++++++-------- server/backend.c | 6 +++-- server/filters.c | 12 ++++++++-- server/nbdkit.syms | 3 ++- filters/retry/retry.c | 47 ++++++++++++++++++------------------- 6 files changed, 91 insertions(+), 52 deletions(-) diff --git a/docs/nbdkit-filter.pod b/docs/nbdkit-filter.pod index 65e56fe5..e801965d 100644 --- a/docs/nbdkit-filter.pod +++ b/docs/nbdkit-filter.pod @@ -132,16 +132,18 @@ C<nbdkit_next_after_fork>, C<nbdkit_next_preconnect>, C<nbdkit_next_list_exports>, C<nbdkit_next_default_export>, C<nbdkit_next_open>) and a structure called C<struct nbdkit_next_ops>. These abstract the next plugin or filter in the chain. There is also -an opaque pointer C<nxdata> which must be passed along when calling -these functions. The value of C<nxdata> passed to C<.prepare> has a -stable lifetime that lasts to the corresponding C<.finalize>, with all -intermediate functions (such as C<.pread>) receiving the same value -for convenience. Functions where C<nxdata> is not reused are -C<.config>, C<.config_complete>, C<.get_ready>, and C<.after_fork>, -which are called during initialization outside any connections, and -C<.preconnect>, C<.list_exports>, C<.default_export>, and C<.open> -which are called based on client connections but prior to the stable -lifetime of C<.prepare>. +an opaque pointer C<backend> or C<nxdata> which must be passed along +when calling these functions. The value of C<nxdata> passed to +C<.prepare> has a stable lifetime that lasts to the corresponding +C<.finalize>, with all intermediate functions (such as C<.pread>) +receiving the same value for convenience. Functions where C<nxdata> +is not reused are C<.config>, C<.config_complete>, C<.get_ready>, and +C<.after_fork>, which are called during initialization outside any +connections, and C<.preconnect>, C<.list_exports>, C<.default_export>, +and C<.open> which are called based on client connections but prior to +the stable lifetime of C<.prepare>. The value of C<backend> passed to +C<.open> has a lifetime that lasts until the matching C<.close> for +use by C<nbdkit_backend_reopen>. =head2 Next config, open and close @@ -175,10 +177,6 @@ C<nbdkit_set_error> or setting C<errno>), whereas C<next_ops-E<gt>pread> exposes this via an explicit parameter, allowing a filter to learn or modify this error if desired. -There is also a C<next_ops-E<gt>reopen> function which is used by -L<nbdkit-retry-filter(1)> to close and reopen the underlying plugin. -It should be used with caution because it is difficult to use safely. - =head2 Other considerations You can modify parameters when you call the C<next> function. However @@ -431,7 +429,7 @@ C<next> because it cannot be altered. =head2 C<.open> - void * (*open) (nbdkit_next_open *next, void *nxdata, + void * (*open) (nbdkit_next_open *next, nbdkit_backend *backend, int readonly, const char *exportname, int is_tls); This is called when a new client connection is opened and can be used @@ -473,6 +471,29 @@ outer filter to the plugin will be in reverse. Skipping a call to C<next> is acceptable if the filter will not access C<next_ops> during any of the remaining callbacks reached on the same connection. +The value of C<backend> in this call has a lifetime that lasts until +the counterpart C<.close>, and it is this value (and not the distinct +C<nxdata> of C<.pread> and friends) that must be passed as the first +parameter to C<nbdkit_backend_reopen> by a filter attempting to retry +a connection into the backend. + +=head3 Reopening the backend + +Filters have access to a function for reopening the backend: + + int (nbdkit_backend *backend, int readonly, const char *exportname, + void **nxdata); + +This function is used by L<nbdkit-retry-filter(1)> to close and reopen +the underlying plugin, with possible changes to the C<readonly> and +C<exportname> parameters in relation to the original opening. It +should be used with caution because it is difficult to use safely. +The C<backend> parameter to this function should be the C<backend> +parameter originally passed in to C<.open>; while the C<nxdata> +pointer should be the address of C<nxdata> from any function with a +C<next_ops> parameter (such as C<.pread>) that wants to call into the +plugin after the reopen. + =head2 C<.close> void (*close) (void *handle); diff --git a/include/nbdkit-filter.h b/include/nbdkit-filter.h index 0964c6e7..0c172936 100644 --- a/include/nbdkit-filter.h +++ b/include/nbdkit-filter.h @@ -1,5 +1,5 @@ /* nbdkit - * Copyright (C) 2013-2020 Red Hat Inc. + * Copyright (C) 2013-2021 Red Hat Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -54,6 +54,8 @@ extern "C" { * the next filter or plugin. */ typedef struct backend nbdkit_backend; +#elif defined NBDKIT_RETRY_FILTER /* Hack to expose reopen to retry filter */ +typedef struct nbdkit_backend nbdkit_backend; #else typedef void nbdkit_backend; #endif @@ -69,16 +71,11 @@ typedef int nbdkit_next_list_exports (nbdkit_backend *nxdata, int readonly, struct nbdkit_exports *exports); typedef const char *nbdkit_next_default_export (nbdkit_backend *nxdata, int readonly); -typedef int nbdkit_next_open (nbdkit_backend *nxdata, +typedef int nbdkit_next_open (nbdkit_backend *backend, int readonly, const char *exportname); struct nbdkit_next_ops { - /* Performs close + open on the underlying chain. - * Used by the retry filter. - */ - int (*reopen) (nbdkit_backend *nxdata, int readonly, const char *exportname); - - /* The rest of the next ops are the same as normal plugin operations. */ + /* These callbacks are the same as normal plugin operations. */ int64_t (*get_size) (nbdkit_backend *nxdata); const char * (*export_description) (nbdkit_backend *nxdata); @@ -150,6 +147,15 @@ NBDKIT_EXTERN_DECL (size_t, nbdkit_exports_count, NBDKIT_EXTERN_DECL (const struct nbdkit_export, nbdkit_get_export, (const struct nbdkit_exports *, size_t)); +#ifdef NBDKIT_RETRY_FILTER +/* Performs close + open on the underlying chain. + * Used by the retry filter. + */ +NBDKIT_EXTERN_DECL (int, nbdkit_backend_reopen, + (nbdkit_backend *backend, int readonly, + const char *exportname, nbdkit_backend **nxdata)); +#endif + /* Filter struct. */ struct nbdkit_filter { /* Do not set these fields directly; use NBDKIT_REGISTER_FILTER. @@ -190,7 +196,7 @@ struct nbdkit_filter { nbdkit_backend *nxdata, int readonly, int is_tls); - void * (*open) (nbdkit_next_open *next, nbdkit_backend *nxdata, + void * (*open) (nbdkit_next_open *next, nbdkit_backend *backend, int readonly, const char *exportname, int is_tls); void (*close) (void *handle); diff --git a/server/backend.c b/server/backend.c index 3630163b..e9fcd696 100644 --- a/server/backend.c +++ b/server/backend.c @@ -1,5 +1,5 @@ /* nbdkit - * Copyright (C) 2013-2020 Red Hat Inc. + * Copyright (C) 2013-2021 Red Hat Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -337,7 +337,7 @@ backend_valid_range (struct backend *b, uint64_t offset, uint32_t count) offset + count <= h->exportsize; } -/* Wrappers for all callbacks in a filter's struct nbdkit_next_ops. */ +/* Core functionality of nbdkit_backend_reopen for retry filter */ int backend_reopen (struct backend *b, int readonly, const char *exportname) @@ -360,6 +360,8 @@ backend_reopen (struct backend *b, int readonly, const char *exportname) return 0; } +/* Wrappers for all callbacks in a filter's struct nbdkit_next_ops. */ + const char * backend_export_description (struct backend *b) { diff --git a/server/filters.c b/server/filters.c index 54abf9a4..31be9742 100644 --- a/server/filters.c +++ b/server/filters.c @@ -1,5 +1,5 @@ /* nbdkit - * Copyright (C) 2013-2020 Red Hat Inc. + * Copyright (C) 2013-2021 Red Hat Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -290,7 +290,6 @@ filter_close (struct backend *b, void *handle) } static struct nbdkit_next_ops next_ops = { - .reopen = backend_reopen, .export_description = backend_export_description, .get_size = backend_get_size, .can_write = backend_can_write, @@ -659,3 +658,12 @@ filter_register (struct backend *next, size_t index, const char *filename, return (struct backend *) f; } + +int +nbdkit_backend_reopen (struct backend *b, int readonly, + const char *exportname, struct backend **nxdata) +{ + /* For now, we don't need to update nxdata. */ + assert (b == *nxdata); + return backend_reopen (b, readonly, exportname); +} diff --git a/server/nbdkit.syms b/server/nbdkit.syms index 20ee27f3..50411d27 100644 --- a/server/nbdkit.syms +++ b/server/nbdkit.syms @@ -1,5 +1,5 @@ # nbdkit -# Copyright (C) 2018-2020 Red Hat Inc. +# Copyright (C) 2018-2021 Red Hat Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -41,6 +41,7 @@ nbdkit_absolute_path; nbdkit_add_export; nbdkit_add_extent; + nbdkit_backend_reopen; nbdkit_debug; nbdkit_error; nbdkit_export_name; diff --git a/filters/retry/retry.c b/filters/retry/retry.c index 7377fdf4..abd49eb8 100644 --- a/filters/retry/retry.c +++ b/filters/retry/retry.c @@ -40,6 +40,7 @@ #include <string.h> #include <sys/time.h> +#define NBDKIT_RETRY_FILTER /* Hack to expose reopen */ #include <nbdkit-filter.h> #include "cleanup.h" @@ -50,7 +51,7 @@ static unsigned initial_delay = 2; static bool exponential_backoff = true; static bool force_readonly = false; -/* Currently next_ops->reopen is not safe if another thread makes a +/* Currently nbdkit_backend_reopen is not safe if another thread makes a * request on the same connection (but on other connections it's OK). * To work around this for now we limit the thread model here, but * this is something we could improve in server/backend.c in future. @@ -62,7 +63,7 @@ retry_thread_model (void) } static int -retry_config (nbdkit_next_config *next, void *nxdata, +retry_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { int r; @@ -108,12 +109,13 @@ retry_config (nbdkit_next_config *next, void *nxdata, struct retry_handle { int readonly; /* Save original readonly setting. */ char *exportname; /* Client exportname. */ + nbdkit_backend *backend; /* Backend learned during .open. */ unsigned reopens; bool open; }; static void * -retry_open (nbdkit_next_open *next, void *nxdata, +retry_open (nbdkit_next_open *next, nbdkit_backend *nxdata, int readonly, const char *exportname, int is_tls) { struct retry_handle *h; @@ -129,6 +131,7 @@ retry_open (nbdkit_next_open *next, void *nxdata, h->readonly = readonly; h->exportname = strdup (exportname); + h->backend = nxdata; if (h->exportname == NULL) { nbdkit_error ("strdup: %m"); free (h); @@ -172,10 +175,8 @@ valid_range (struct nbdkit_next_ops *next_ops, void *nxdata, } static bool -do_retry (struct retry_handle *h, - struct retry_data *data, - struct nbdkit_next_ops *next_ops, void *nxdata, - const char *method, int *err) +do_retry (struct retry_handle *h, struct retry_data *data, + nbdkit_backend **nxdata, const char *method, int *err) { /* If it's the first retry, initialize the other fields in *data. */ if (data->retry == 0) @@ -208,8 +209,8 @@ do_retry (struct retry_handle *h, /* Reopen the connection. */ h->reopens++; - if (next_ops->reopen (nxdata, - h->readonly || force_readonly, h->exportname) == -1) { + if (nbdkit_backend_reopen (h->backend, h->readonly || force_readonly, + h->exportname, nxdata) == -1) { /* If the reopen fails we treat it the same way as a command * failing. */ @@ -224,7 +225,7 @@ do_retry (struct retry_handle *h, } static int -retry_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +retry_pread (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -237,7 +238,7 @@ retry_pread (struct nbdkit_next_ops *next_ops, void *nxdata, r = -1; else r = next_ops->pread (nxdata, buf, count, offset, flags, err); - if (r == -1 && do_retry (h, &data, next_ops, nxdata, "pread", err)) + if (r == -1 && do_retry (h, &data, &nxdata, "pread", err)) goto again; return r; @@ -245,7 +246,7 @@ retry_pread (struct nbdkit_next_ops *next_ops, void *nxdata, /* Write. */ static int -retry_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +retry_pwrite (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -272,7 +273,7 @@ retry_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, } else r = next_ops->pwrite (nxdata, buf, count, offset, flags, err); - if (r == -1 && do_retry (h, &data, next_ops, nxdata, "pwrite", err)) + if (r == -1 && do_retry (h, &data, &nxdata, "pwrite", err)) goto again; return r; @@ -280,7 +281,7 @@ retry_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, /* Trim. */ static int -retry_trim (struct nbdkit_next_ops *next_ops, void *nxdata, +retry_trim (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -307,7 +308,7 @@ retry_trim (struct nbdkit_next_ops *next_ops, void *nxdata, } else r = next_ops->trim (nxdata, count, offset, flags, err); - if (r == -1 && do_retry (h, &data, next_ops, nxdata, "trim", err)) + if (r == -1 && do_retry (h, &data, &nxdata, "trim", err)) goto again; return r; @@ -315,7 +316,7 @@ retry_trim (struct nbdkit_next_ops *next_ops, void *nxdata, /* Flush. */ static int -retry_flush (struct nbdkit_next_ops *next_ops, void *nxdata, +retry_flush (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, void *handle, uint32_t flags, int *err) { @@ -332,7 +333,7 @@ retry_flush (struct nbdkit_next_ops *next_ops, void *nxdata, } else r = next_ops->flush (nxdata, flags, err); - if (r == -1 && do_retry (h, &data, next_ops, nxdata, "flush", err)) + if (r == -1 && do_retry (h, &data, &nxdata, "flush", err)) goto again; return r; @@ -340,7 +341,7 @@ retry_flush (struct nbdkit_next_ops *next_ops, void *nxdata, /* Zero. */ static int -retry_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +retry_zero (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -372,7 +373,7 @@ retry_zero (struct nbdkit_next_ops *next_ops, void *nxdata, } else r = next_ops->zero (nxdata, count, offset, flags, err); - if (r == -1 && do_retry (h, &data, next_ops, nxdata, "zero", err)) + if (r == -1 && do_retry (h, &data, &nxdata, "zero", err)) goto again; return r; @@ -380,7 +381,7 @@ retry_zero (struct nbdkit_next_ops *next_ops, void *nxdata, /* Extents. */ static int -retry_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +retry_extents (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, void *handle, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err) @@ -408,7 +409,7 @@ retry_extents (struct nbdkit_next_ops *next_ops, void *nxdata, } r = next_ops->extents (nxdata, count, offset, flags, extents2, err); } - if (r == -1 && do_retry (h, &data, next_ops, nxdata, "extents", err)) + if (r == -1 && do_retry (h, &data, &nxdata, "extents", err)) goto again; if (r == 0) { @@ -428,7 +429,7 @@ retry_extents (struct nbdkit_next_ops *next_ops, void *nxdata, /* Cache. */ static int -retry_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +retry_cache (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -446,7 +447,7 @@ retry_cache (struct nbdkit_next_ops *next_ops, void *nxdata, } else r = next_ops->cache (nxdata, count, offset, flags, err); - if (r == -1 && do_retry (h, &data, next_ops, nxdata, "cache", err)) + if (r == -1 && do_retry (h, &data, &nxdata, "cache", err)) goto again; return r; -- 2.30.1
Eric Blake
2021-Mar-05 23:31 UTC
[Libguestfs] [nbdkit PATCH v3 03/16] server: Move default_exportname from handle to connection
struct handle represents things that can differ per export (such as the results of .can_write), but .default_exportname is really something that should be global to all possible exports of the connection. Moving it also gets rid of the leaky abstraction where NBD_OPT_STARTTLS has to reset the cached default when changing TLS even though there is no current handle at that time. It also lets us simplify reset_handle(), as it no longer tracks allocated memory, and prepares for an upcoming patch refactoring how backend_open operates. --- server/internal.h | 6 ++---- server/backend.c | 8 ++++---- server/connections.c | 15 ++++++++++++--- server/protocol-handshake-newstyle.c | 7 +++---- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/server/internal.h b/server/internal.h index 906f0690..1f37703f 100644 --- a/server/internal.h +++ b/server/internal.h @@ -211,8 +211,6 @@ struct handle { unsigned char state; /* Bitmask of HANDLE_* values */ - char *default_exportname; - uint64_t exportsize; int can_write; int can_flush; @@ -231,8 +229,6 @@ reset_handle (struct handle *h) { h->handle = NULL; h->state = 0; - free (h->default_exportname); - h->default_exportname = NULL; h->exportsize = -1; h->can_write = -1; h->can_flush = -1; @@ -261,6 +257,8 @@ struct connection { struct handle *handles; /* One per plugin and filter. */ size_t nr_handles; + char **default_exportname; /* One per plugin and filter. */ + uint32_t cflags; uint16_t eflags; bool handshake_complete; diff --git a/server/backend.c b/server/backend.c index e9fcd696..d08a2b6b 100644 --- a/server/backend.c +++ b/server/backend.c @@ -193,7 +193,7 @@ backend_default_export (struct backend *b, int readonly) controlpath_debug ("%s: default_export readonly=%d tls=%d", b->name, readonly, conn->using_tls); - if (h->default_exportname == NULL) { + if (conn->default_exportname[b->i] == NULL) { assert (h->handle == NULL); assert ((h->state & HANDLE_OPEN) == 0); s = b->default_export (b, readonly, conn->using_tls); @@ -205,12 +205,12 @@ backend_default_export (struct backend *b, int readonly) } if (s) { /* Best effort caching */ - h->default_exportname = strdup (s); - if (h->default_exportname == NULL) + conn->default_exportname[b->i] = strdup (s); + if (conn->default_exportname[b->i] == NULL) return s; } } - return h->default_exportname; + return conn->default_exportname[b->i]; } int diff --git a/server/connections.c b/server/connections.c index 38b32742..b56f89f8 100644 --- a/server/connections.c +++ b/server/connections.c @@ -1,5 +1,5 @@ /* nbdkit - * Copyright (C) 2013-2020 Red Hat Inc. + * Copyright (C) 2013-2021 Red Hat Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -263,6 +263,14 @@ new_connection (int sockin, int sockout, int nworkers) for_each_backend (b) reset_handle (get_handle (conn, b->i)); + conn->default_exportname = calloc (top->i + 1, + sizeof *conn->default_exportname); + if (conn->default_exportname == NULL) { + perror ("malloc"); + free (conn->handles); + goto error1; + } + conn->status = 1; conn->nworkers = nworkers; if (nworkers) { @@ -330,6 +338,7 @@ new_connection (int sockin, int sockout, int nworkers) if (conn->status_pipe[1] >= 0) close (conn->status_pipe[1]); free (conn->handles); + free (conn->default_exportname); error1: pthread_mutex_destroy (&conn->request_lock); @@ -373,9 +382,9 @@ free_connection (struct connection *conn) free (conn->exportname_from_set_meta_context); free_interns (); - /* This is needed in order to free a field in struct handle. */ for_each_backend (b) - reset_handle (get_handle (conn, b->i)); + free (conn->default_exportname[b->i]); + free (conn->default_exportname); free (conn->handles); free (conn); diff --git a/server/protocol-handshake-newstyle.c b/server/protocol-handshake-newstyle.c index 0a76a814..fb4a93bc 100644 --- a/server/protocol-handshake-newstyle.c +++ b/server/protocol-handshake-newstyle.c @@ -1,5 +1,5 @@ /* nbdkit - * Copyright (C) 2013-2020 Red Hat Inc. + * Copyright (C) 2013-2021 Red Hat Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -497,9 +497,8 @@ negotiate_handshake_newstyle_options (void) debug ("using TLS on this connection"); /* Wipe out any cached default export name. */ for_each_backend (b) { - struct handle *h = get_handle (conn, b->i); - free (h->default_exportname); - h->default_exportname = NULL; + free (conn->default_exportname[b->i]); + conn->default_exportname[b->i] = NULL; } } break; -- 2.30.1
Eric Blake
2021-Mar-05 23:31 UTC
[Libguestfs] [nbdkit PATCH v3 04/16] server: Rename struct handle to struct context
Reduce the confusion between the user's (filter or plugin) void *handle, and the extra context information we need to utilize that handle. This will also make it easier for an upcoming patch to update the signature of various backend_* functions called from nbdkit_next_ops. Also delete the nr_handles field, which was unused and always reflected 'top->i+1'. The HANDLE_* enum values are left unchanged, as they represent what we know about the user's handle, and therefore what user cleanup functions we still need to call. --- server/internal.h | 22 ++-- server/backend.c | 270 +++++++++++++++++++++---------------------- server/connections.c | 13 +-- 3 files changed, 151 insertions(+), 154 deletions(-) diff --git a/server/internal.h b/server/internal.h index 1f37703f..5e382fe0 100644 --- a/server/internal.h +++ b/server/internal.h @@ -1,5 +1,5 @@ /* nbdkit - * Copyright (C) 2013-2020 Red Hat Inc. + * Copyright (C) 2013-2021 Red Hat Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -192,12 +192,12 @@ typedef int (*connection_send_function) (const void *buf, size_t len, __attribute__((__nonnull__ (1))); typedef void (*connection_close_function) (void); -/* struct handle stores data per connection and backend. Primarily +/* struct context stores data per connection and backend. Primarily * this is the filter or plugin handle, but other state is also stored * here. * - * Use get_handle (conn, 0) to return the struct handle for the - * plugin, and get_handle (conn, b->i) to return the struct handle for + * Use get_context (conn, 0) to return the struct context for the + * plugin, and get_context (conn, b->i) to return the struct context for * the i'th backend (if b->i >= 1 then for a filter). */ enum { @@ -206,7 +206,7 @@ enum { HANDLE_FAILED = 4, /* Set if .finalize failed */ }; -struct handle { +struct context { void *handle; /* Plugin or filter handle. */ unsigned char state; /* Bitmask of HANDLE_* values */ @@ -225,7 +225,7 @@ struct handle { }; static inline void -reset_handle (struct handle *h) +reset_context (struct context *h) { h->handle = NULL; h->state = 0; @@ -254,9 +254,7 @@ struct connection { void *crypto_session; int nworkers; - struct handle *handles; /* One per plugin and filter. */ - size_t nr_handles; - + struct context *contexts; /* One per plugin and filter. */ char **default_exportname; /* One per plugin and filter. */ uint32_t cflags; @@ -276,10 +274,10 @@ struct connection { connection_close_function close; }; -static inline struct handle * -get_handle (struct connection *conn, int i) +static inline struct context * +get_context (struct connection *conn, int i) { - return &conn->handles[i]; + return &conn->contexts[i]; } extern void handle_single_connection (int sockin, int sockout); diff --git a/server/backend.c b/server/backend.c index d08a2b6b..0a67e8be 100644 --- a/server/backend.c +++ b/server/backend.c @@ -163,14 +163,14 @@ backend_list_exports (struct backend *b, int readonly, struct nbdkit_exports *exports) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); size_t count; controlpath_debug ("%s: list_exports readonly=%d tls=%d", b->name, readonly, conn->using_tls); - assert (h->handle == NULL); - assert ((h->state & HANDLE_OPEN) == 0); + assert (c->handle == NULL); + assert ((c->state & HANDLE_OPEN) == 0); if (b->list_exports (b, readonly, conn->using_tls, exports) == -1 || exports_resolve_default (exports, b, readonly) == -1) { @@ -187,15 +187,15 @@ const char * backend_default_export (struct backend *b, int readonly) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); const char *s; controlpath_debug ("%s: default_export readonly=%d tls=%d", b->name, readonly, conn->using_tls); if (conn->default_exportname[b->i] == NULL) { - assert (h->handle == NULL); - assert ((h->state & HANDLE_OPEN) == 0); + assert (c->handle == NULL); + assert ((c->state & HANDLE_OPEN) == 0); s = b->default_export (b, readonly, conn->using_tls); /* Ignore over-length strings. XXX Also ignore non-UTF8? */ if (s && strnlen (s, NBD_MAX_STRING + 1) > NBD_MAX_STRING) { @@ -217,16 +217,16 @@ int backend_open (struct backend *b, int readonly, const char *exportname) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); controlpath_debug ("%s: open readonly=%d exportname=\"%s\" tls=%d", b->name, readonly, exportname, conn->using_tls); - assert (h->handle == NULL); - assert ((h->state & HANDLE_OPEN) == 0); - assert (h->can_write == -1); + assert (c->handle == NULL); + assert ((c->state & HANDLE_OPEN) == 0); + assert (c->can_write == -1); if (readonly) - h->can_write = 0; + c->can_write = 0; /* Determine the canonical name for default export */ if (!*exportname) { @@ -240,16 +240,16 @@ backend_open (struct backend *b, int readonly, const char *exportname) /* Most filters will call next_open first, resulting in * inner-to-outer ordering. */ - h->handle = b->open (b, readonly, exportname, conn->using_tls); - controlpath_debug ("%s: open returned handle %p", b->name, h->handle); + c->handle = b->open (b, readonly, exportname, conn->using_tls); + controlpath_debug ("%s: open returned handle %p", b->name, c->handle); - if (h->handle == NULL) { + if (c->handle == NULL) { if (b->i) /* Do not strand backend if this layer failed */ backend_close (b->next); return -1; } - h->state |= HANDLE_OPEN; + c->state |= HANDLE_OPEN; return 0; } @@ -257,24 +257,24 @@ int backend_prepare (struct backend *b) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); - assert (h->handle); - assert ((h->state & (HANDLE_OPEN | HANDLE_CONNECTED)) == HANDLE_OPEN); + assert (c->handle); + assert ((c->state & (HANDLE_OPEN | HANDLE_CONNECTED)) == HANDLE_OPEN); /* Call these in order starting from the filter closest to the * plugin, similar to typical .open order. But remember that * a filter may skip opening its backend. */ - if (b->i && get_handle (conn, b->i-1)->handle != NULL && + if (b->i && get_context (conn, b->i-1)->handle != NULL && backend_prepare (b->next) == -1) return -1; - controlpath_debug ("%s: prepare readonly=%d", b->name, h->can_write == 0); + controlpath_debug ("%s: prepare readonly=%d", b->name, c->can_write == 0); - if (b->prepare (b, h->handle, h->can_write == 0) == -1) + if (b->prepare (b, c->handle, c->can_write == 0) == -1) return -1; - h->state |= HANDLE_CONNECTED; + c->state |= HANDLE_CONNECTED; return 0; } @@ -282,21 +282,21 @@ int backend_finalize (struct backend *b) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); /* Call these in reverse order to .prepare above, starting from the * filter furthest away from the plugin, and matching .close order. */ /* Once finalize fails, we can do nothing further on this connection */ - if (h->state & HANDLE_FAILED) + if (c->state & HANDLE_FAILED) return -1; - if (h->state & HANDLE_CONNECTED) { - assert (h->state & HANDLE_OPEN && h->handle); + if (c->state & HANDLE_CONNECTED) { + assert (c->state & HANDLE_OPEN && c->handle); controlpath_debug ("%s: finalize", b->name); - if (b->finalize (b, h->handle) == -1) { - h->state |= HANDLE_FAILED; + if (b->finalize (b, c->handle) == -1) { + c->state |= HANDLE_FAILED; return -1; } } @@ -310,18 +310,18 @@ void backend_close (struct backend *b) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); /* outer-to-inner order, opposite .open */ - if (h->handle) { - assert (h->state & HANDLE_OPEN); + if (c->handle) { + assert (c->state & HANDLE_OPEN); controlpath_debug ("%s: close", b->name); - b->close (b, h->handle); + b->close (b, c->handle); } else - assert (! (h->state & HANDLE_OPEN)); - reset_handle (h); + assert (! (c->state & HANDLE_OPEN)); + reset_context (c); if (b->i) backend_close (b->next); } @@ -330,11 +330,11 @@ bool backend_valid_range (struct backend *b, uint64_t offset, uint32_t count) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); - assert (h->exportsize <= INT64_MAX); /* Guaranteed by negotiation phase */ - return count > 0 && offset <= h->exportsize && - offset + count <= h->exportsize; + assert (c->exportsize <= INT64_MAX); /* Guaranteed by negotiation phase */ + return count > 0 && offset <= c->exportsize && + offset + count <= c->exportsize; } /* Core functionality of nbdkit_backend_reopen for retry filter */ @@ -366,14 +366,14 @@ const char * backend_export_description (struct backend *b) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); const char *s; controlpath_debug ("%s: export_description", b->name); - assert (h->handle && (h->state & HANDLE_CONNECTED)); + assert (c->handle && (c->state & HANDLE_CONNECTED)); /* Caching is not useful for this value. */ - s = b->export_description (b, h->handle); + s = b->export_description (b, c->handle); /* Ignore over-length strings. XXX Also ignore non-UTF8? */ if (s && strnlen (s, NBD_MAX_STRING + 1) > NBD_MAX_STRING) { @@ -388,178 +388,178 @@ int64_t backend_get_size (struct backend *b) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); - assert (h->handle && (h->state & HANDLE_CONNECTED)); - if (h->exportsize == -1) { + assert (c->handle && (c->state & HANDLE_CONNECTED)); + if (c->exportsize == -1) { controlpath_debug ("%s: get_size", b->name); - h->exportsize = b->get_size (b, h->handle); + c->exportsize = b->get_size (b, c->handle); } - return h->exportsize; + return c->exportsize; } int backend_can_write (struct backend *b) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); - assert (h->handle && (h->state & HANDLE_CONNECTED)); - if (h->can_write == -1) { + assert (c->handle && (c->state & HANDLE_CONNECTED)); + if (c->can_write == -1) { controlpath_debug ("%s: can_write", b->name); - h->can_write = b->can_write (b, h->handle); + c->can_write = b->can_write (b, c->handle); } - return h->can_write; + return c->can_write; } int backend_can_flush (struct backend *b) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); - assert (h->handle && (h->state & HANDLE_CONNECTED)); - if (h->can_flush == -1) { + assert (c->handle && (c->state & HANDLE_CONNECTED)); + if (c->can_flush == -1) { controlpath_debug ("%s: can_flush", b->name); - h->can_flush = b->can_flush (b, h->handle); + c->can_flush = b->can_flush (b, c->handle); } - return h->can_flush; + return c->can_flush; } int backend_is_rotational (struct backend *b) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); - assert (h->handle && (h->state & HANDLE_CONNECTED)); - if (h->is_rotational == -1) { + assert (c->handle && (c->state & HANDLE_CONNECTED)); + if (c->is_rotational == -1) { controlpath_debug ("%s: is_rotational", b->name); - h->is_rotational = b->is_rotational (b, h->handle); + c->is_rotational = b->is_rotational (b, c->handle); } - return h->is_rotational; + return c->is_rotational; } int backend_can_trim (struct backend *b) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); int r; - assert (h->handle && (h->state & HANDLE_CONNECTED)); - if (h->can_trim == -1) { + assert (c->handle && (c->state & HANDLE_CONNECTED)); + if (c->can_trim == -1) { controlpath_debug ("%s: can_trim", b->name); r = backend_can_write (b); if (r != 1) { - h->can_trim = 0; + c->can_trim = 0; return r; } - h->can_trim = b->can_trim (b, h->handle); + c->can_trim = b->can_trim (b, c->handle); } - return h->can_trim; + return c->can_trim; } int backend_can_zero (struct backend *b) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); int r; - assert (h->handle && (h->state & HANDLE_CONNECTED)); - if (h->can_zero == -1) { + assert (c->handle && (c->state & HANDLE_CONNECTED)); + if (c->can_zero == -1) { controlpath_debug ("%s: can_zero", b->name); r = backend_can_write (b); if (r != 1) { - h->can_zero = NBDKIT_ZERO_NONE; + c->can_zero = NBDKIT_ZERO_NONE; return r; /* Relies on 0 == NBDKIT_ZERO_NONE */ } - h->can_zero = b->can_zero (b, h->handle); + c->can_zero = b->can_zero (b, c->handle); } - return h->can_zero; + return c->can_zero; } int backend_can_fast_zero (struct backend *b) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); int r; - assert (h->handle && (h->state & HANDLE_CONNECTED)); - if (h->can_fast_zero == -1) { + assert (c->handle && (c->state & HANDLE_CONNECTED)); + if (c->can_fast_zero == -1) { controlpath_debug ("%s: can_fast_zero", b->name); r = backend_can_zero (b); if (r < NBDKIT_ZERO_EMULATE) { - h->can_fast_zero = 0; + c->can_fast_zero = 0; return r; /* Relies on 0 == NBDKIT_ZERO_NONE */ } - h->can_fast_zero = b->can_fast_zero (b, h->handle); + c->can_fast_zero = b->can_fast_zero (b, c->handle); } - return h->can_fast_zero; + return c->can_fast_zero; } int backend_can_extents (struct backend *b) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); - assert (h->handle && (h->state & HANDLE_CONNECTED)); - if (h->can_extents == -1) { + assert (c->handle && (c->state & HANDLE_CONNECTED)); + if (c->can_extents == -1) { controlpath_debug ("%s: can_extents", b->name); - h->can_extents = b->can_extents (b, h->handle); + c->can_extents = b->can_extents (b, c->handle); } - return h->can_extents; + return c->can_extents; } int backend_can_fua (struct backend *b) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); int r; - assert (h->handle && (h->state & HANDLE_CONNECTED)); - if (h->can_fua == -1) { + assert (c->handle && (c->state & HANDLE_CONNECTED)); + if (c->can_fua == -1) { controlpath_debug ("%s: can_fua", b->name); r = backend_can_write (b); if (r != 1) { - h->can_fua = NBDKIT_FUA_NONE; + c->can_fua = NBDKIT_FUA_NONE; return r; /* Relies on 0 == NBDKIT_FUA_NONE */ } - h->can_fua = b->can_fua (b, h->handle); + c->can_fua = b->can_fua (b, c->handle); } - return h->can_fua; + return c->can_fua; } int backend_can_multi_conn (struct backend *b) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); - assert (h->handle && (h->state & HANDLE_CONNECTED)); - if (h->can_multi_conn == -1) { + assert (c->handle && (c->state & HANDLE_CONNECTED)); + if (c->can_multi_conn == -1) { controlpath_debug ("%s: can_multi_conn", b->name); - h->can_multi_conn = b->can_multi_conn (b, h->handle); + c->can_multi_conn = b->can_multi_conn (b, c->handle); } - return h->can_multi_conn; + return c->can_multi_conn; } int backend_can_cache (struct backend *b) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); - assert (h->handle && (h->state & HANDLE_CONNECTED)); - if (h->can_cache == -1) { + assert (c->handle && (c->state & HANDLE_CONNECTED)); + if (c->can_cache == -1) { controlpath_debug ("%s: can_cache", b->name); - h->can_cache = b->can_cache (b, h->handle); + c->can_cache = b->can_cache (b, c->handle); } - return h->can_cache; + return c->can_cache; } int @@ -568,16 +568,16 @@ backend_pread (struct backend *b, uint32_t flags, int *err) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); int r; - assert (h->handle && (h->state & HANDLE_CONNECTED)); + assert (c->handle && (c->state & HANDLE_CONNECTED)); assert (backend_valid_range (b, offset, count)); assert (flags == 0); datapath_debug ("%s: pread count=%" PRIu32 " offset=%" PRIu64, b->name, count, offset); - r = b->pread (b, h->handle, buf, count, offset, flags, err); + r = b->pread (b, c->handle, buf, count, offset, flags, err); if (r == -1) assert (*err); return r; @@ -589,20 +589,20 @@ backend_pwrite (struct backend *b, uint32_t flags, int *err) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); bool fua = !!(flags & NBDKIT_FLAG_FUA); int r; - assert (h->handle && (h->state & HANDLE_CONNECTED)); - assert (h->can_write == 1); + assert (c->handle && (c->state & HANDLE_CONNECTED)); + assert (c->can_write == 1); assert (backend_valid_range (b, offset, count)); assert (!(flags & ~NBDKIT_FLAG_FUA)); if (fua) - assert (h->can_fua > NBDKIT_FUA_NONE); + assert (c->can_fua > NBDKIT_FUA_NONE); datapath_debug ("%s: pwrite count=%" PRIu32 " offset=%" PRIu64 " fua=%d", b->name, count, offset, fua); - r = b->pwrite (b, h->handle, buf, count, offset, flags, err); + r = b->pwrite (b, c->handle, buf, count, offset, flags, err); if (r == -1) assert (*err); return r; @@ -613,15 +613,15 @@ backend_flush (struct backend *b, uint32_t flags, int *err) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); int r; - assert (h->handle && (h->state & HANDLE_CONNECTED)); - assert (h->can_flush == 1); + assert (c->handle && (c->state & HANDLE_CONNECTED)); + assert (c->can_flush == 1); assert (flags == 0); datapath_debug ("%s: flush", b->name); - r = b->flush (b, h->handle, flags, err); + r = b->flush (b, c->handle, flags, err); if (r == -1) assert (*err); return r; @@ -633,21 +633,21 @@ backend_trim (struct backend *b, int *err) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); bool fua = !!(flags & NBDKIT_FLAG_FUA); int r; - assert (h->handle && (h->state & HANDLE_CONNECTED)); - assert (h->can_write == 1); - assert (h->can_trim == 1); + assert (c->handle && (c->state & HANDLE_CONNECTED)); + assert (c->can_write == 1); + assert (c->can_trim == 1); assert (backend_valid_range (b, offset, count)); assert (!(flags & ~NBDKIT_FLAG_FUA)); if (fua) - assert (h->can_fua > NBDKIT_FUA_NONE); + assert (c->can_fua > NBDKIT_FUA_NONE); datapath_debug ("%s: trim count=%" PRIu32 " offset=%" PRIu64 " fua=%d", b->name, count, offset, fua); - r = b->trim (b, h->handle, count, offset, flags, err); + r = b->trim (b, c->handle, count, offset, flags, err); if (r == -1) assert (*err); return r; @@ -659,27 +659,27 @@ backend_zero (struct backend *b, int *err) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); bool fua = !!(flags & NBDKIT_FLAG_FUA); bool fast = !!(flags & NBDKIT_FLAG_FAST_ZERO); int r; - assert (h->handle && (h->state & HANDLE_CONNECTED)); - assert (h->can_write == 1); - assert (h->can_zero > NBDKIT_ZERO_NONE); + assert (c->handle && (c->state & HANDLE_CONNECTED)); + assert (c->can_write == 1); + assert (c->can_zero > NBDKIT_ZERO_NONE); assert (backend_valid_range (b, offset, count)); assert (!(flags & ~(NBDKIT_FLAG_MAY_TRIM | NBDKIT_FLAG_FUA | NBDKIT_FLAG_FAST_ZERO))); if (fua) - assert (h->can_fua > NBDKIT_FUA_NONE); + assert (c->can_fua > NBDKIT_FUA_NONE); if (fast) - assert (h->can_fast_zero == 1); + assert (c->can_fast_zero == 1); datapath_debug ("%s: zero count=%" PRIu32 " offset=%" PRIu64 " may_trim=%d fua=%d fast=%d", b->name, count, offset, !!(flags & NBDKIT_FLAG_MAY_TRIM), fua, fast); - r = b->zero (b, h->handle, count, offset, flags, err); + r = b->zero (b, c->handle, count, offset, flags, err); if (r == -1) { assert (*err); if (!fast) @@ -694,17 +694,17 @@ backend_extents (struct backend *b, struct nbdkit_extents *extents, int *err) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); int r; - assert (h->handle && (h->state & HANDLE_CONNECTED)); - assert (h->can_extents >= 0); + assert (c->handle && (c->state & HANDLE_CONNECTED)); + assert (c->can_extents >= 0); assert (backend_valid_range (b, offset, count)); assert (!(flags & ~NBDKIT_FLAG_REQ_ONE)); datapath_debug ("%s: extents count=%" PRIu32 " offset=%" PRIu64 " req_one=%d", b->name, count, offset, !!(flags & NBDKIT_FLAG_REQ_ONE)); - if (h->can_extents == 0) { + if (c->can_extents == 0) { /* By default it is safe assume that everything in the range is * allocated. */ @@ -713,7 +713,7 @@ backend_extents (struct backend *b, *err = errno; return r; } - r = b->extents (b, h->handle, count, offset, flags, extents, err); + r = b->extents (b, c->handle, count, offset, flags, extents, err); if (r == -1) assert (*err); return r; @@ -725,17 +725,17 @@ backend_cache (struct backend *b, uint32_t flags, int *err) { GET_CONN; - struct handle *h = get_handle (conn, b->i); + struct context *c = get_context (conn, b->i); int r; - assert (h->handle && (h->state & HANDLE_CONNECTED)); - assert (h->can_cache > NBDKIT_CACHE_NONE); + assert (c->handle && (c->state & HANDLE_CONNECTED)); + assert (c->can_cache > NBDKIT_CACHE_NONE); assert (backend_valid_range (b, offset, count)); assert (flags == 0); datapath_debug ("%s: cache count=%" PRIu32 " offset=%" PRIu64, b->name, count, offset); - if (h->can_cache == NBDKIT_CACHE_EMULATE) { + if (c->can_cache == NBDKIT_CACHE_EMULATE) { static char buf[MAX_REQUEST_SIZE]; /* data sink, never read */ uint32_t limit; @@ -747,7 +747,7 @@ backend_cache (struct backend *b, } return 0; } - r = b->cache (b, h->handle, count, offset, flags, err); + r = b->cache (b, c->handle, count, offset, flags, err); if (r == -1) assert (*err); return r; diff --git a/server/connections.c b/server/connections.c index b56f89f8..87db2d80 100644 --- a/server/connections.c +++ b/server/connections.c @@ -254,20 +254,19 @@ new_connection (int sockin, int sockout, int nworkers) pthread_mutex_init (&conn->write_lock, NULL); pthread_mutex_init (&conn->status_lock, NULL); - conn->handles = calloc (top->i + 1, sizeof *conn->handles); - if (conn->handles == NULL) { + conn->contexts = calloc (top->i + 1, sizeof *conn->contexts); + if (conn->contexts == NULL) { perror ("malloc"); goto error1; } - conn->nr_handles = top->i + 1; for_each_backend (b) - reset_handle (get_handle (conn, b->i)); + reset_context (get_context (conn, b->i)); conn->default_exportname = calloc (top->i + 1, sizeof *conn->default_exportname); if (conn->default_exportname == NULL) { perror ("malloc"); - free (conn->handles); + free (conn->contexts); goto error1; } @@ -337,7 +336,7 @@ new_connection (int sockin, int sockout, int nworkers) close (conn->status_pipe[0]); if (conn->status_pipe[1] >= 0) close (conn->status_pipe[1]); - free (conn->handles); + free (conn->contexts); free (conn->default_exportname); error1: @@ -385,7 +384,7 @@ free_connection (struct connection *conn) for_each_backend (b) free (conn->default_exportname[b->i]); free (conn->default_exportname); - free (conn->handles); + free (conn->contexts); free (conn); threadlocal_set_conn (NULL); -- 2.30.1
Eric Blake
2021-Mar-05 23:31 UTC
[Libguestfs] [nbdkit PATCH v3 05/16] server: Update signature of backend_open
Instead of returning an int on success, return a pointer to everything needed to call into the next layer via next_ops. The public interface in nbdkit-filter.h still returns int, so we need a next_open() wrapper added back in filters.h. Similarly, an upcoming patch wants to update backend_* functions to directly take a struct context* instead of the current approach of a struct backend* coupled with querying TLS for the current connection. This will be easier by making struct context track the struct backend that it was opened under. Struct connection still maintains a list of contexts, but now instead of directly populating direct members of an array during backend_open, we now populate pointers in the callers of backend_open; this will let us progress towards filters opening a context independently from the current client connection. --- server/internal.h | 15 +++++-- server/backend.c | 65 +++++++++++++++------------- server/connections.c | 7 +-- server/filters.c | 16 ++++++- server/protocol-handshake-newstyle.c | 8 ++-- server/protocol-handshake.c | 7 ++- 6 files changed, 73 insertions(+), 45 deletions(-) diff --git a/server/internal.h b/server/internal.h index 5e382fe0..1add5f36 100644 --- a/server/internal.h +++ b/server/internal.h @@ -208,6 +208,7 @@ enum { struct context { void *handle; /* Plugin or filter handle. */ + struct backend *b; /* Backend that provided handle. */ unsigned char state; /* Bitmask of HANDLE_* values */ @@ -254,7 +255,7 @@ struct connection { void *crypto_session; int nworkers; - struct context *contexts; /* One per plugin and filter. */ + struct context **contexts; /* One per plugin and filter. */ char **default_exportname; /* One per plugin and filter. */ uint32_t cflags; @@ -277,7 +278,13 @@ struct connection { static inline struct context * get_context (struct connection *conn, int i) { - return &conn->contexts[i]; + return conn->contexts[i]; +} + +static inline void +set_context (struct connection *conn, int i, struct context *context) +{ + conn->contexts[i] = context; } extern void handle_single_connection (int sockin, int sockout); @@ -443,8 +450,8 @@ extern const char *backend_export_description (struct backend *b) * freed on return of this function, so backends must save the * exportname if they need to refer to it later. */ -extern int backend_open (struct backend *b, - int readonly, const char *exportname) +extern struct context *backend_open (struct backend *b, + int readonly, const char *exportname) __attribute__((__nonnull__ (1, 3))); extern int backend_prepare (struct backend *b) __attribute__((__nonnull__ (1))); diff --git a/server/backend.c b/server/backend.c index 0a67e8be..cebd55ab 100644 --- a/server/backend.c +++ b/server/backend.c @@ -169,8 +169,7 @@ backend_list_exports (struct backend *b, int readonly, controlpath_debug ("%s: list_exports readonly=%d tls=%d", b->name, readonly, conn->using_tls); - assert (c->handle == NULL); - assert ((c->state & HANDLE_OPEN) == 0); + assert (c == NULL); if (b->list_exports (b, readonly, conn->using_tls, exports) == -1 || exports_resolve_default (exports, b, readonly) == -1) { @@ -194,8 +193,7 @@ backend_default_export (struct backend *b, int readonly) b->name, readonly, conn->using_tls); if (conn->default_exportname[b->i] == NULL) { - assert (c->handle == NULL); - assert ((c->state & HANDLE_OPEN) == 0); + assert (c == NULL); s = b->default_export (b, readonly, conn->using_tls); /* Ignore over-length strings. XXX Also ignore non-UTF8? */ if (s && strnlen (s, NBD_MAX_STRING + 1) > NBD_MAX_STRING) { @@ -213,18 +211,22 @@ backend_default_export (struct backend *b, int readonly) return conn->default_exportname[b->i]; } -int +struct context * backend_open (struct backend *b, int readonly, const char *exportname) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = malloc (sizeof *c); + + if (c == NULL) { + nbdkit_error ("malloc: %m"); + return NULL; + } controlpath_debug ("%s: open readonly=%d exportname=\"%s\" tls=%d", b->name, readonly, exportname, conn->using_tls); - assert (c->handle == NULL); - assert ((c->state & HANDLE_OPEN) == 0); - assert (c->can_write == -1); + assert (conn->contexts[b->i] == NULL); + reset_context (c); if (readonly) c->can_write = 0; @@ -233,7 +235,8 @@ backend_open (struct backend *b, int readonly, const char *exportname) exportname = backend_default_export (b, readonly); if (exportname == NULL) { nbdkit_error ("default export (\"\") not permitted"); - return -1; + free (c); + return NULL; } } @@ -246,11 +249,13 @@ backend_open (struct backend *b, int readonly, const char *exportname) if (c->handle == NULL) { if (b->i) /* Do not strand backend if this layer failed */ backend_close (b->next); - return -1; + free (c); + return NULL; } c->state |= HANDLE_OPEN; - return 0; + c->b = b; + return c; } int @@ -266,7 +271,7 @@ backend_prepare (struct backend *b) * plugin, similar to typical .open order. But remember that * a filter may skip opening its backend. */ - if (b->i && get_context (conn, b->i-1)->handle != NULL && + if (b->i && get_context (conn, b->i-1) != NULL && backend_prepare (b->next) == -1) return -1; @@ -301,7 +306,7 @@ backend_finalize (struct backend *b) } } - if (b->i) + if (b->i && get_context (conn, b->i-1)) return backend_finalize (b->next); return 0; } @@ -313,16 +318,13 @@ backend_close (struct backend *b) struct context *c = get_context (conn, b->i); /* outer-to-inner order, opposite .open */ - - if (c->handle) { - assert (c->state & HANDLE_OPEN); - controlpath_debug ("%s: close", b->name); - b->close (b, c->handle); - } - else - assert (! (c->state & HANDLE_OPEN)); - reset_context (c); - if (b->i) + assert (c->handle); + assert (c->state & HANDLE_OPEN); + controlpath_debug ("%s: close", b->name); + b->close (b, c->handle); + free (c); + set_context (conn, b->i, NULL); + if (b->i && get_context (conn, b->i-1)) backend_close (b->next); } @@ -342,16 +344,21 @@ backend_valid_range (struct backend *b, uint64_t offset, uint32_t count) int backend_reopen (struct backend *b, int readonly, const char *exportname) { + GET_CONN; + struct context *h; + controlpath_debug ("%s: reopen readonly=%d exportname=\"%s\"", b->name, readonly, exportname); - if (backend_finalize (b) == -1) - return -1; - backend_close (b); - if (backend_open (b, readonly, exportname) == -1) { + if (get_context (conn, b->i)) { + if (backend_finalize (b) == -1) + return -1; backend_close (b); - return -1; } + h = backend_open (b, readonly, exportname); + if (h == NULL) + return -1; + set_context (conn, b->i, h); if (backend_prepare (b) == -1) { backend_finalize (b); backend_close (b); diff --git a/server/connections.c b/server/connections.c index 87db2d80..e3fdc649 100644 --- a/server/connections.c +++ b/server/connections.c @@ -240,7 +240,6 @@ new_connection (int sockin, int sockout, int nworkers) struct connection *conn; int opt; socklen_t optlen = sizeof opt; - struct backend *b; conn = calloc (1, sizeof *conn); if (conn == NULL) { @@ -259,9 +258,6 @@ new_connection (int sockin, int sockout, int nworkers) perror ("malloc"); goto error1; } - for_each_backend (b) - reset_context (get_context (conn, b->i)); - conn->default_exportname = calloc (top->i + 1, sizeof *conn->default_exportname); if (conn->default_exportname == NULL) { @@ -364,7 +360,8 @@ free_connection (struct connection *conn) */ if (!quit) { lock_request (); - backend_close (top); + if (get_context (conn, top->i)) + backend_close (top); unlock_request (); } diff --git a/server/filters.c b/server/filters.c index 31be9742..dde36306 100644 --- a/server/filters.c +++ b/server/filters.c @@ -260,6 +260,18 @@ filter_default_export (struct backend *b, int readonly, int is_tls) return backend_default_export (b->next, readonly); } +static int +next_open (struct backend *b, int readonly, const char *exportname) +{ + GET_CONN; + struct context *c = backend_open (b, readonly, exportname); + + if (c == NULL) + return -1; + set_context (conn, b->i, c); + return 0; +} + static void * filter_open (struct backend *b, int readonly, const char *exportname, int is_tls) @@ -271,9 +283,9 @@ filter_open (struct backend *b, int readonly, const char *exportname, * inner-to-outer ordering. */ if (f->filter.open) - handle = f->filter.open (backend_open, b->next, readonly, exportname, + handle = f->filter.open (next_open, b->next, readonly, exportname, is_tls); - else if (backend_open (b->next, readonly, exportname) == -1) + else if (next_open (b->next, readonly, exportname) == -1) handle = NULL; else handle = NBDKIT_HANDLE_NOT_NEEDED; diff --git a/server/protocol-handshake-newstyle.c b/server/protocol-handshake-newstyle.c index fb4a93bc..015e7f9b 100644 --- a/server/protocol-handshake-newstyle.c +++ b/server/protocol-handshake-newstyle.c @@ -567,9 +567,11 @@ negotiate_handshake_newstyle_options (void) */ if (finish_newstyle_options (&exportsize, &data[4], exportnamelen) == -1) { - if (backend_finalize (top) == -1) - return -1; - backend_close (top); + if (get_context (conn, top->i)) { + if (backend_finalize (top) == -1) + return -1; + backend_close (top); + } if (send_newstyle_option_reply (option, NBD_REP_ERR_UNKNOWN) == -1) return -1; continue; diff --git a/server/protocol-handshake.c b/server/protocol-handshake.c index 80233713..82e7e647 100644 --- a/server/protocol-handshake.c +++ b/server/protocol-handshake.c @@ -1,5 +1,5 @@ /* nbdkit - * Copyright (C) 2013-2020 Red Hat Inc. + * Copyright (C) 2013-2021 Red Hat Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -79,9 +79,12 @@ protocol_common_open (uint64_t *exportsize, uint16_t *flags, int64_t size; uint16_t eflags = NBD_FLAG_HAS_FLAGS; int fl; + struct context *c; - if (backend_open (top, read_only, exportname) == -1) + c = backend_open (top, read_only, exportname); + if (c == NULL) return -1; + set_context (conn, top->i, c); /* Prepare (for filters), called just after open. */ if (backend_prepare (top) == -1) -- 2.30.1
Eric Blake
2021-Mar-05 23:31 UTC
[Libguestfs] [nbdkit PATCH v3 06/16] backend: Inline reset_context
Now that there is only one caller, we don't need it to live in internal.h. --- server/internal.h | 18 ------------------ server/backend.c | 18 ++++++++++++++---- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/server/internal.h b/server/internal.h index 1add5f36..ff543200 100644 --- a/server/internal.h +++ b/server/internal.h @@ -225,24 +225,6 @@ struct context { int can_cache; }; -static inline void -reset_context (struct context *h) -{ - h->handle = NULL; - h->state = 0; - h->exportsize = -1; - h->can_write = -1; - h->can_flush = -1; - h->is_rotational = -1; - h->can_trim = -1; - h->can_zero = -1; - h->can_fast_zero = -1; - h->can_fua = -1; - h->can_multi_conn = -1; - h->can_extents = -1; - h->can_cache = -1; -} - DEFINE_VECTOR_TYPE(string_vector, char *); struct connection { pthread_mutex_t request_lock; diff --git a/server/backend.c b/server/backend.c index cebd55ab..e89f0ab4 100644 --- a/server/backend.c +++ b/server/backend.c @@ -226,9 +226,20 @@ backend_open (struct backend *b, int readonly, const char *exportname) b->name, readonly, exportname, conn->using_tls); assert (conn->contexts[b->i] == NULL); - reset_context (c); - if (readonly) - c->can_write = 0; + c->handle = NULL; + c->b = b; + c->state = 0; + c->exportsize = -1; + c->can_write = readonly ? 0 : -1; + c->can_flush = -1; + c->is_rotational = -1; + c->can_trim = -1; + c->can_zero = -1; + c->can_fast_zero = -1; + c->can_fua = -1; + c->can_multi_conn = -1; + c->can_extents = -1; + c->can_cache = -1; /* Determine the canonical name for default export */ if (!*exportname) { @@ -254,7 +265,6 @@ backend_open (struct backend *b, int readonly, const char *exportname) } c->state |= HANDLE_OPEN; - c->b = b; return c; } -- 2.30.1
Eric Blake
2021-Mar-05 23:31 UTC
[Libguestfs] [nbdkit PATCH v3 07/16] server: Manage contexts by backend, not int
Minor refactoring, since all callers already have a struct backend available when manipulating a context associated with a connection. --- server/internal.h | 21 +++------- server/backend.c | 62 ++++++++++++++-------------- server/connections.c | 17 +++++++- server/filters.c | 2 +- server/protocol-handshake-newstyle.c | 2 +- server/protocol-handshake.c | 2 +- 6 files changed, 55 insertions(+), 51 deletions(-) diff --git a/server/internal.h b/server/internal.h index ff543200..28c65629 100644 --- a/server/internal.h +++ b/server/internal.h @@ -195,10 +195,6 @@ typedef void (*connection_close_function) (void); /* struct context stores data per connection and backend. Primarily * this is the filter or plugin handle, but other state is also stored * here. - * - * Use get_context (conn, 0) to return the struct context for the - * plugin, and get_context (conn, b->i) to return the struct context for - * the i'th backend (if b->i >= 1 then for a filter). */ enum { HANDLE_OPEN = 1, /* Set if .open passed, so .close is needed */ @@ -257,18 +253,11 @@ struct connection { connection_close_function close; }; -static inline struct context * -get_context (struct connection *conn, int i) -{ - return conn->contexts[i]; -} - -static inline void -set_context (struct connection *conn, int i, struct context *context) -{ - conn->contexts[i] = context; -} - +extern struct context *get_context (struct connection *conn, struct backend *b) + __attribute__((__nonnull__(1))); +extern void set_context (struct connection *conn, struct backend *b, + struct context *c) + __attribute__((__nonnull__(1))); extern void handle_single_connection (int sockin, int sockout); extern int connection_get_status (void); extern int connection_set_status (int value); diff --git a/server/backend.c b/server/backend.c index e89f0ab4..c382c71d 100644 --- a/server/backend.c +++ b/server/backend.c @@ -163,7 +163,7 @@ backend_list_exports (struct backend *b, int readonly, struct nbdkit_exports *exports) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); size_t count; controlpath_debug ("%s: list_exports readonly=%d tls=%d", @@ -186,7 +186,7 @@ const char * backend_default_export (struct backend *b, int readonly) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); const char *s; controlpath_debug ("%s: default_export readonly=%d tls=%d", @@ -272,7 +272,7 @@ int backend_prepare (struct backend *b) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); assert (c->handle); assert ((c->state & (HANDLE_OPEN | HANDLE_CONNECTED)) == HANDLE_OPEN); @@ -281,7 +281,7 @@ backend_prepare (struct backend *b) * plugin, similar to typical .open order. But remember that * a filter may skip opening its backend. */ - if (b->i && get_context (conn, b->i-1) != NULL && + if (b->i && get_context (conn, b->next) != NULL && backend_prepare (b->next) == -1) return -1; @@ -297,7 +297,7 @@ int backend_finalize (struct backend *b) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); /* Call these in reverse order to .prepare above, starting from the * filter furthest away from the plugin, and matching .close order. @@ -316,7 +316,7 @@ backend_finalize (struct backend *b) } } - if (b->i && get_context (conn, b->i-1)) + if (b->i && get_context (conn, b->next)) return backend_finalize (b->next); return 0; } @@ -325,7 +325,7 @@ void backend_close (struct backend *b) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); /* outer-to-inner order, opposite .open */ assert (c->handle); @@ -333,8 +333,8 @@ backend_close (struct backend *b) controlpath_debug ("%s: close", b->name); b->close (b, c->handle); free (c); - set_context (conn, b->i, NULL); - if (b->i && get_context (conn, b->i-1)) + set_context (conn, b, NULL); + if (b->i && get_context (conn, b->next)) backend_close (b->next); } @@ -342,7 +342,7 @@ bool backend_valid_range (struct backend *b, uint64_t offset, uint32_t count) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); assert (c->exportsize <= INT64_MAX); /* Guaranteed by negotiation phase */ return count > 0 && offset <= c->exportsize && @@ -360,7 +360,7 @@ backend_reopen (struct backend *b, int readonly, const char *exportname) controlpath_debug ("%s: reopen readonly=%d exportname=\"%s\"", b->name, readonly, exportname); - if (get_context (conn, b->i)) { + if (get_context (conn, b)) { if (backend_finalize (b) == -1) return -1; backend_close (b); @@ -368,7 +368,7 @@ backend_reopen (struct backend *b, int readonly, const char *exportname) h = backend_open (b, readonly, exportname); if (h == NULL) return -1; - set_context (conn, b->i, h); + set_context (conn, b, h); if (backend_prepare (b) == -1) { backend_finalize (b); backend_close (b); @@ -383,7 +383,7 @@ const char * backend_export_description (struct backend *b) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); const char *s; controlpath_debug ("%s: export_description", b->name); @@ -405,7 +405,7 @@ int64_t backend_get_size (struct backend *b) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->exportsize == -1) { @@ -419,7 +419,7 @@ int backend_can_write (struct backend *b) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->can_write == -1) { @@ -433,7 +433,7 @@ int backend_can_flush (struct backend *b) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->can_flush == -1) { @@ -447,7 +447,7 @@ int backend_is_rotational (struct backend *b) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->is_rotational == -1) { @@ -461,7 +461,7 @@ int backend_can_trim (struct backend *b) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); int r; assert (c->handle && (c->state & HANDLE_CONNECTED)); @@ -481,7 +481,7 @@ int backend_can_zero (struct backend *b) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); int r; assert (c->handle && (c->state & HANDLE_CONNECTED)); @@ -501,7 +501,7 @@ int backend_can_fast_zero (struct backend *b) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); int r; assert (c->handle && (c->state & HANDLE_CONNECTED)); @@ -521,7 +521,7 @@ int backend_can_extents (struct backend *b) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->can_extents == -1) { @@ -535,7 +535,7 @@ int backend_can_fua (struct backend *b) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); int r; assert (c->handle && (c->state & HANDLE_CONNECTED)); @@ -555,7 +555,7 @@ int backend_can_multi_conn (struct backend *b) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->can_multi_conn == -1) { @@ -569,7 +569,7 @@ int backend_can_cache (struct backend *b) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->can_cache == -1) { @@ -585,7 +585,7 @@ backend_pread (struct backend *b, uint32_t flags, int *err) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); int r; assert (c->handle && (c->state & HANDLE_CONNECTED)); @@ -606,7 +606,7 @@ backend_pwrite (struct backend *b, uint32_t flags, int *err) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); bool fua = !!(flags & NBDKIT_FLAG_FUA); int r; @@ -630,7 +630,7 @@ backend_flush (struct backend *b, uint32_t flags, int *err) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); int r; assert (c->handle && (c->state & HANDLE_CONNECTED)); @@ -650,7 +650,7 @@ backend_trim (struct backend *b, int *err) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); bool fua = !!(flags & NBDKIT_FLAG_FUA); int r; @@ -676,7 +676,7 @@ backend_zero (struct backend *b, int *err) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); bool fua = !!(flags & NBDKIT_FLAG_FUA); bool fast = !!(flags & NBDKIT_FLAG_FAST_ZERO); int r; @@ -711,7 +711,7 @@ backend_extents (struct backend *b, struct nbdkit_extents *extents, int *err) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); int r; assert (c->handle && (c->state & HANDLE_CONNECTED)); @@ -742,7 +742,7 @@ backend_cache (struct backend *b, uint32_t flags, int *err) { GET_CONN; - struct context *c = get_context (conn, b->i); + struct context *c = get_context (conn, b); int r; assert (c->handle && (c->state & HANDLE_CONNECTED)); diff --git a/server/connections.c b/server/connections.c index e3fdc649..0115875b 100644 --- a/server/connections.c +++ b/server/connections.c @@ -360,7 +360,7 @@ free_connection (struct connection *conn) */ if (!quit) { lock_request (); - if (get_context (conn, top->i)) + if (get_context (conn, top)) backend_close (top); unlock_request (); } @@ -499,3 +499,18 @@ raw_close (void) if (conn->sockout >= 0 && conn->sockin != conn->sockout) closesocket (conn->sockout); } + +struct context * +get_context (struct connection *conn, struct backend *b) +{ + struct context *c = conn->contexts[b->i]; + assert (!c || c->b == b); + return c; +} + +void +set_context (struct connection *conn, struct backend *b, struct context *c) +{ + assert (!c || c->b == b); + conn->contexts[b->i] = c; +} diff --git a/server/filters.c b/server/filters.c index dde36306..fb123670 100644 --- a/server/filters.c +++ b/server/filters.c @@ -268,7 +268,7 @@ next_open (struct backend *b, int readonly, const char *exportname) if (c == NULL) return -1; - set_context (conn, b->i, c); + set_context (conn, b, c); return 0; } diff --git a/server/protocol-handshake-newstyle.c b/server/protocol-handshake-newstyle.c index 015e7f9b..4bc802cc 100644 --- a/server/protocol-handshake-newstyle.c +++ b/server/protocol-handshake-newstyle.c @@ -567,7 +567,7 @@ negotiate_handshake_newstyle_options (void) */ if (finish_newstyle_options (&exportsize, &data[4], exportnamelen) == -1) { - if (get_context (conn, top->i)) { + if (get_context (conn, top)) { if (backend_finalize (top) == -1) return -1; backend_close (top); diff --git a/server/protocol-handshake.c b/server/protocol-handshake.c index 82e7e647..69f8b530 100644 --- a/server/protocol-handshake.c +++ b/server/protocol-handshake.c @@ -84,7 +84,7 @@ protocol_common_open (uint64_t *exportsize, uint16_t *flags, c = backend_open (top, read_only, exportname); if (c == NULL) return -1; - set_context (conn, top->i, c); + set_context (conn, top, c); /* Prepare (for filters), called just after open. */ if (backend_prepare (top) == -1) -- 2.30.1
Eric Blake
2021-Mar-05 23:31 UTC
[Libguestfs] [nbdkit PATCH v3 08/16] backend: Plumb context through internal callbacks
Refactor all internal backend callbacks that take a 'struct backend *'/'void *handle' pair to instead take a 'struct context *'. This serves as a step towards making it easier for filters to create a standalone context independent of the current client connection. --- server/internal.h | 44 ++++++++-------- server/backend.c | 44 ++++++++-------- server/filters.c | 113 ++++++++++++++++++++++++---------------- server/plugins.c | 128 +++++++++++++++++++++++++++------------------- 4 files changed, 186 insertions(+), 143 deletions(-) diff --git a/server/internal.h b/server/internal.h index 28c65629..e8828506 100644 --- a/server/internal.h +++ b/server/internal.h @@ -366,38 +366,38 @@ struct backend { const char *(*default_export) (struct backend *, int readonly, int is_tls); void *(*open) (struct backend *, int readonly, const char *exportname, int is_tls); - int (*prepare) (struct backend *, void *handle, int readonly); - int (*finalize) (struct backend *, void *handle); - void (*close) (struct backend *, void *handle); + int (*prepare) (struct context *, int readonly); + int (*finalize) (struct context *); + void (*close) (struct context *); - const char *(*export_description) (struct backend *, void *handle); - int64_t (*get_size) (struct backend *, void *handle); - int (*can_write) (struct backend *, void *handle); - int (*can_flush) (struct backend *, void *handle); - int (*is_rotational) (struct backend *, void *handle); - int (*can_trim) (struct backend *, void *handle); - int (*can_zero) (struct backend *, void *handle); - int (*can_fast_zero) (struct backend *, void *handle); - int (*can_extents) (struct backend *, void *handle); - int (*can_fua) (struct backend *, void *handle); - int (*can_multi_conn) (struct backend *, void *handle); - int (*can_cache) (struct backend *, void *handle); + const char *(*export_description) (struct context *); + int64_t (*get_size) (struct context *); + int (*can_write) (struct context *); + int (*can_flush) (struct context *); + int (*is_rotational) (struct context *); + int (*can_trim) (struct context *); + int (*can_zero) (struct context *); + int (*can_fast_zero) (struct context *); + int (*can_extents) (struct context *); + int (*can_fua) (struct context *); + int (*can_multi_conn) (struct context *); + int (*can_cache) (struct context *); - int (*pread) (struct backend *, void *handle, + int (*pread) (struct context *, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err); - int (*pwrite) (struct backend *, void *handle, + int (*pwrite) (struct context *, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err); - int (*flush) (struct backend *, void *handle, uint32_t flags, int *err); - int (*trim) (struct backend *, void *handle, + int (*flush) (struct context *, uint32_t flags, int *err); + int (*trim) (struct context *, uint32_t count, uint64_t offset, uint32_t flags, int *err); - int (*zero) (struct backend *, void *handle, + int (*zero) (struct context *, uint32_t count, uint64_t offset, uint32_t flags, int *err); - int (*extents) (struct backend *, void *handle, + int (*extents) (struct context *, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err); - int (*cache) (struct backend *, void *handle, + int (*cache) (struct context *, uint32_t count, uint64_t offset, uint32_t flags, int *err); }; diff --git a/server/backend.c b/server/backend.c index c382c71d..45a6da2f 100644 --- a/server/backend.c +++ b/server/backend.c @@ -287,7 +287,7 @@ backend_prepare (struct backend *b) controlpath_debug ("%s: prepare readonly=%d", b->name, c->can_write == 0); - if (b->prepare (b, c->handle, c->can_write == 0) == -1) + if (b->prepare (c, c->can_write == 0) == -1) return -1; c->state |= HANDLE_CONNECTED; return 0; @@ -310,7 +310,7 @@ backend_finalize (struct backend *b) if (c->state & HANDLE_CONNECTED) { assert (c->state & HANDLE_OPEN && c->handle); controlpath_debug ("%s: finalize", b->name); - if (b->finalize (b, c->handle) == -1) { + if (b->finalize (c) == -1) { c->state |= HANDLE_FAILED; return -1; } @@ -331,7 +331,7 @@ backend_close (struct backend *b) assert (c->handle); assert (c->state & HANDLE_OPEN); controlpath_debug ("%s: close", b->name); - b->close (b, c->handle); + b->close (c); free (c); set_context (conn, b, NULL); if (b->i && get_context (conn, b->next)) @@ -390,7 +390,7 @@ backend_export_description (struct backend *b) assert (c->handle && (c->state & HANDLE_CONNECTED)); /* Caching is not useful for this value. */ - s = b->export_description (b, c->handle); + s = b->export_description (c); /* Ignore over-length strings. XXX Also ignore non-UTF8? */ if (s && strnlen (s, NBD_MAX_STRING + 1) > NBD_MAX_STRING) { @@ -410,7 +410,7 @@ backend_get_size (struct backend *b) assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->exportsize == -1) { controlpath_debug ("%s: get_size", b->name); - c->exportsize = b->get_size (b, c->handle); + c->exportsize = b->get_size (c); } return c->exportsize; } @@ -424,7 +424,7 @@ backend_can_write (struct backend *b) assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->can_write == -1) { controlpath_debug ("%s: can_write", b->name); - c->can_write = b->can_write (b, c->handle); + c->can_write = b->can_write (c); } return c->can_write; } @@ -438,7 +438,7 @@ backend_can_flush (struct backend *b) assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->can_flush == -1) { controlpath_debug ("%s: can_flush", b->name); - c->can_flush = b->can_flush (b, c->handle); + c->can_flush = b->can_flush (c); } return c->can_flush; } @@ -452,7 +452,7 @@ backend_is_rotational (struct backend *b) assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->is_rotational == -1) { controlpath_debug ("%s: is_rotational", b->name); - c->is_rotational = b->is_rotational (b, c->handle); + c->is_rotational = b->is_rotational (c); } return c->is_rotational; } @@ -472,7 +472,7 @@ backend_can_trim (struct backend *b) c->can_trim = 0; return r; } - c->can_trim = b->can_trim (b, c->handle); + c->can_trim = b->can_trim (c); } return c->can_trim; } @@ -492,7 +492,7 @@ backend_can_zero (struct backend *b) c->can_zero = NBDKIT_ZERO_NONE; return r; /* Relies on 0 == NBDKIT_ZERO_NONE */ } - c->can_zero = b->can_zero (b, c->handle); + c->can_zero = b->can_zero (c); } return c->can_zero; } @@ -512,7 +512,7 @@ backend_can_fast_zero (struct backend *b) c->can_fast_zero = 0; return r; /* Relies on 0 == NBDKIT_ZERO_NONE */ } - c->can_fast_zero = b->can_fast_zero (b, c->handle); + c->can_fast_zero = b->can_fast_zero (c); } return c->can_fast_zero; } @@ -526,7 +526,7 @@ backend_can_extents (struct backend *b) assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->can_extents == -1) { controlpath_debug ("%s: can_extents", b->name); - c->can_extents = b->can_extents (b, c->handle); + c->can_extents = b->can_extents (c); } return c->can_extents; } @@ -546,7 +546,7 @@ backend_can_fua (struct backend *b) c->can_fua = NBDKIT_FUA_NONE; return r; /* Relies on 0 == NBDKIT_FUA_NONE */ } - c->can_fua = b->can_fua (b, c->handle); + c->can_fua = b->can_fua (c); } return c->can_fua; } @@ -560,7 +560,7 @@ backend_can_multi_conn (struct backend *b) assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->can_multi_conn == -1) { controlpath_debug ("%s: can_multi_conn", b->name); - c->can_multi_conn = b->can_multi_conn (b, c->handle); + c->can_multi_conn = b->can_multi_conn (c); } return c->can_multi_conn; } @@ -574,7 +574,7 @@ backend_can_cache (struct backend *b) assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->can_cache == -1) { controlpath_debug ("%s: can_cache", b->name); - c->can_cache = b->can_cache (b, c->handle); + c->can_cache = b->can_cache (c); } return c->can_cache; } @@ -594,7 +594,7 @@ backend_pread (struct backend *b, datapath_debug ("%s: pread count=%" PRIu32 " offset=%" PRIu64, b->name, count, offset); - r = b->pread (b, c->handle, buf, count, offset, flags, err); + r = b->pread (c, buf, count, offset, flags, err); if (r == -1) assert (*err); return r; @@ -619,7 +619,7 @@ backend_pwrite (struct backend *b, datapath_debug ("%s: pwrite count=%" PRIu32 " offset=%" PRIu64 " fua=%d", b->name, count, offset, fua); - r = b->pwrite (b, c->handle, buf, count, offset, flags, err); + r = b->pwrite (c, buf, count, offset, flags, err); if (r == -1) assert (*err); return r; @@ -638,7 +638,7 @@ backend_flush (struct backend *b, assert (flags == 0); datapath_debug ("%s: flush", b->name); - r = b->flush (b, c->handle, flags, err); + r = b->flush (c, flags, err); if (r == -1) assert (*err); return r; @@ -664,7 +664,7 @@ backend_trim (struct backend *b, datapath_debug ("%s: trim count=%" PRIu32 " offset=%" PRIu64 " fua=%d", b->name, count, offset, fua); - r = b->trim (b, c->handle, count, offset, flags, err); + r = b->trim (c, count, offset, flags, err); if (r == -1) assert (*err); return r; @@ -696,7 +696,7 @@ backend_zero (struct backend *b, b->name, count, offset, !!(flags & NBDKIT_FLAG_MAY_TRIM), fua, fast); - r = b->zero (b, c->handle, count, offset, flags, err); + r = b->zero (c, count, offset, flags, err); if (r == -1) { assert (*err); if (!fast) @@ -730,7 +730,7 @@ backend_extents (struct backend *b, *err = errno; return r; } - r = b->extents (b, c->handle, count, offset, flags, extents, err); + r = b->extents (c, count, offset, flags, extents, err); if (r == -1) assert (*err); return r; @@ -764,7 +764,7 @@ backend_cache (struct backend *b, } return 0; } - r = b->cache (b, c->handle, count, offset, flags, err); + r = b->cache (c, count, offset, flags, err); if (r == -1) assert (*err); return r; diff --git a/server/filters.c b/server/filters.c index fb123670..7986e56f 100644 --- a/server/filters.c +++ b/server/filters.c @@ -293,12 +293,14 @@ filter_open (struct backend *b, int readonly, const char *exportname, } static void -filter_close (struct backend *b, void *handle) +filter_close (struct context *c) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - if (handle && f->filter.close) - f->filter.close (handle); + assert (c->handle); + if (f->filter.close) + f->filter.close (c->handle); } static struct nbdkit_next_ops next_ops = { @@ -324,236 +326,256 @@ static struct nbdkit_next_ops next_ops = { }; static int -filter_prepare (struct backend *b, void *handle, int readonly) +filter_prepare (struct context *c, int readonly) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.prepare && - f->filter.prepare (&next_ops, b->next, handle, readonly) == -1) + f->filter.prepare (&next_ops, b->next, c->handle, readonly) == -1) return -1; return 0; } static int -filter_finalize (struct backend *b, void *handle) +filter_finalize (struct context *c) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.finalize && - f->filter.finalize (&next_ops, b->next, handle) == -1) + f->filter.finalize (&next_ops, b->next, c->handle) == -1) return -1; return 0; } static const char * -filter_export_description (struct backend *b, void *handle) +filter_export_description (struct context *c) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.export_description) - return f->filter.export_description (&next_ops, b->next, handle); + return f->filter.export_description (&next_ops, b->next, c->handle); else return backend_export_description (b->next); } static int64_t -filter_get_size (struct backend *b, void *handle) +filter_get_size (struct context *c) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.get_size) - return f->filter.get_size (&next_ops, b->next, handle); + return f->filter.get_size (&next_ops, b->next, c->handle); else return backend_get_size (b->next); } static int -filter_can_write (struct backend *b, void *handle) +filter_can_write (struct context *c) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.can_write) - return f->filter.can_write (&next_ops, b->next, handle); + return f->filter.can_write (&next_ops, b->next, c->handle); else return backend_can_write (b->next); } static int -filter_can_flush (struct backend *b, void *handle) +filter_can_flush (struct context *c) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.can_flush) - return f->filter.can_flush (&next_ops, b->next, handle); + return f->filter.can_flush (&next_ops, b->next, c->handle); else return backend_can_flush (b->next); } static int -filter_is_rotational (struct backend *b, void *handle) +filter_is_rotational (struct context *c) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.is_rotational) - return f->filter.is_rotational (&next_ops, b->next, handle); + return f->filter.is_rotational (&next_ops, b->next, c->handle); else return backend_is_rotational (b->next); } static int -filter_can_trim (struct backend *b, void *handle) +filter_can_trim (struct context *c) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.can_trim) - return f->filter.can_trim (&next_ops, b->next, handle); + return f->filter.can_trim (&next_ops, b->next, c->handle); else return backend_can_trim (b->next); } static int -filter_can_zero (struct backend *b, void *handle) +filter_can_zero (struct context *c) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.can_zero) - return f->filter.can_zero (&next_ops, b->next, handle); + return f->filter.can_zero (&next_ops, b->next, c->handle); else return backend_can_zero (b->next); } static int -filter_can_fast_zero (struct backend *b, void *handle) +filter_can_fast_zero (struct context *c) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.can_fast_zero) - return f->filter.can_fast_zero (&next_ops, b->next, handle); + return f->filter.can_fast_zero (&next_ops, b->next, c->handle); else return backend_can_fast_zero (b->next); } static int -filter_can_extents (struct backend *b, void *handle) +filter_can_extents (struct context *c) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.can_extents) - return f->filter.can_extents (&next_ops, b->next, handle); + return f->filter.can_extents (&next_ops, b->next, c->handle); else return backend_can_extents (b->next); } static int -filter_can_fua (struct backend *b, void *handle) +filter_can_fua (struct context *c) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.can_fua) - return f->filter.can_fua (&next_ops, b->next, handle); + return f->filter.can_fua (&next_ops, b->next, c->handle); else return backend_can_fua (b->next); } static int -filter_can_multi_conn (struct backend *b, void *handle) +filter_can_multi_conn (struct context *c) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.can_multi_conn) - return f->filter.can_multi_conn (&next_ops, b->next, handle); + return f->filter.can_multi_conn (&next_ops, b->next, c->handle); else return backend_can_multi_conn (b->next); } static int -filter_can_cache (struct backend *b, void *handle) +filter_can_cache (struct context *c) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.can_cache) - return f->filter.can_cache (&next_ops, b->next, handle); + return f->filter.can_cache (&next_ops, b->next, c->handle); else return backend_can_cache (b->next); } static int -filter_pread (struct backend *b, void *handle, +filter_pread (struct context *c, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.pread) - return f->filter.pread (&next_ops, b->next, handle, + return f->filter.pread (&next_ops, b->next, c->handle, buf, count, offset, flags, err); else return backend_pread (b->next, buf, count, offset, flags, err); } static int -filter_pwrite (struct backend *b, void *handle, +filter_pwrite (struct context *c, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.pwrite) - return f->filter.pwrite (&next_ops, b->next, handle, + return f->filter.pwrite (&next_ops, b->next, c->handle, buf, count, offset, flags, err); else return backend_pwrite (b->next, buf, count, offset, flags, err); } static int -filter_flush (struct backend *b, void *handle, +filter_flush (struct context *c, uint32_t flags, int *err) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.flush) - return f->filter.flush (&next_ops, b->next, handle, flags, err); + return f->filter.flush (&next_ops, b->next, c->handle, flags, err); else return backend_flush (b->next, flags, err); } static int -filter_trim (struct backend *b, void *handle, +filter_trim (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, int *err) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.trim) - return f->filter.trim (&next_ops, b->next, handle, count, offset, + return f->filter.trim (&next_ops, b->next, c->handle, count, offset, flags, err); else return backend_trim (b->next, count, offset, flags, err); } static int -filter_zero (struct backend *b, void *handle, +filter_zero (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, int *err) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.zero) - return f->filter.zero (&next_ops, b->next, handle, + return f->filter.zero (&next_ops, b->next, c->handle, count, offset, flags, err); else return backend_zero (b->next, count, offset, flags, err); } static int -filter_extents (struct backend *b, void *handle, +filter_extents (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.extents) - return f->filter.extents (&next_ops, b->next, handle, + return f->filter.extents (&next_ops, b->next, c->handle, count, offset, flags, extents, err); else @@ -562,14 +584,15 @@ filter_extents (struct backend *b, void *handle, } static int -filter_cache (struct backend *b, void *handle, +filter_cache (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, int *err) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); if (f->filter.cache) - return f->filter.cache (&next_ops, b->next, handle, + return f->filter.cache (&next_ops, b->next, c->handle, count, offset, flags, err); else return backend_cache (b->next, count, offset, flags, err); diff --git a/server/plugins.c b/server/plugins.c index 010595c7..17126ea1 100644 --- a/server/plugins.c +++ b/server/plugins.c @@ -1,5 +1,5 @@ /* nbdkit - * Copyright (C) 2013-2020 Red Hat Inc. + * Copyright (C) 2013-2021 Red Hat Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -347,48 +347,51 @@ plugin_open (struct backend *b, int readonly, const char *exportname, * .close. */ static int -plugin_prepare (struct backend *b, void *handle, - int readonly) +plugin_prepare (struct context *c, int readonly) { return 0; } static int -plugin_finalize (struct backend *b, void *handle) +plugin_finalize (struct context *c) { return 0; } static void -plugin_close (struct backend *b, void *handle) +plugin_close (struct context *c) { GET_CONN; + struct backend *b = c->b; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); - if (handle && p->plugin.close) - p->plugin.close (handle); + assert (c->handle); + if (p->plugin.close) + p->plugin.close (c->handle); conn->exportname = NULL; } static const char * -plugin_export_description (struct backend *b, void *handle) +plugin_export_description (struct context *c) { + struct backend *b = c->b; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); if (p->plugin.export_description) - return p->plugin.export_description (handle); + return p->plugin.export_description (c->handle); else return NULL; } static int64_t -plugin_get_size (struct backend *b, void *handle) +plugin_get_size (struct context *c) { + struct backend *b = c->b; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); assert (p->plugin.get_size != NULL); - return p->plugin.get_size (handle); + return p->plugin.get_size (c->handle); } static int @@ -401,52 +404,57 @@ normalize_bool (int value) } static int -plugin_can_write (struct backend *b, void *handle) +plugin_can_write (struct context *c) { + struct backend *b = c->b; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); if (p->plugin.can_write) - return normalize_bool (p->plugin.can_write (handle)); + return normalize_bool (p->plugin.can_write (c->handle)); else return p->plugin.pwrite || p->plugin._pwrite_v1; } static int -plugin_can_flush (struct backend *b, void *handle) +plugin_can_flush (struct context *c) { + struct backend *b = c->b; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); if (p->plugin.can_flush) - return normalize_bool (p->plugin.can_flush (handle)); + return normalize_bool (p->plugin.can_flush (c->handle)); else return p->plugin.flush || p->plugin._flush_v1; } static int -plugin_is_rotational (struct backend *b, void *handle) +plugin_is_rotational (struct context *c) { + struct backend *b = c->b; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); if (p->plugin.is_rotational) - return normalize_bool (p->plugin.is_rotational (handle)); + return normalize_bool (p->plugin.is_rotational (c->handle)); else return 0; /* assume false */ } static int -plugin_can_trim (struct backend *b, void *handle) +plugin_can_trim (struct context *c) { + struct backend *b = c->b; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); if (p->plugin.can_trim) - return normalize_bool (p->plugin.can_trim (handle)); + return normalize_bool (p->plugin.can_trim (c->handle)); else return p->plugin.trim || p->plugin._trim_v1; } static int -plugin_can_zero (struct backend *b, void *handle) +plugin_can_zero (struct context *c) { + struct backend *b = c->b; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); int r; @@ -455,7 +463,7 @@ plugin_can_zero (struct backend *b, void *handle) * expects .can_zero to return a tri-state on level of support. */ if (p->plugin.can_zero) { - r = p->plugin.can_zero (handle); + r = p->plugin.can_zero (c->handle); if (r == -1) return -1; return r ? NBDKIT_ZERO_NATIVE : NBDKIT_ZERO_EMULATE; @@ -466,13 +474,14 @@ plugin_can_zero (struct backend *b, void *handle) } static int -plugin_can_fast_zero (struct backend *b, void *handle) +plugin_can_fast_zero (struct context *c) { + struct backend *b = c->b; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); int r; if (p->plugin.can_fast_zero) - return normalize_bool (p->plugin.can_fast_zero (handle)); + return normalize_bool (p->plugin.can_fast_zero (c->handle)); /* Advertise support for fast zeroes if no .zero or .can_zero is * false: in those cases, we fail fast instead of using .pwrite. * This also works when v1 plugin has only ._zero_v1. @@ -486,26 +495,28 @@ plugin_can_fast_zero (struct backend *b, void *handle) } static int -plugin_can_extents (struct backend *b, void *handle) +plugin_can_extents (struct context *c) { + struct backend *b = c->b; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); if (p->plugin.can_extents) - return normalize_bool (p->plugin.can_extents (handle)); + return normalize_bool (p->plugin.can_extents (c->handle)); else return p->plugin.extents != NULL; } static int -plugin_can_fua (struct backend *b, void *handle) +plugin_can_fua (struct context *c) { + struct backend *b = c->b; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); int r; /* The plugin must use API version 2 and have .can_fua return NBDKIT_FUA_NATIVE before we will pass the FUA flag on. */ if (p->plugin.can_fua) { - r = p->plugin.can_fua (handle); + r = p->plugin.can_fua (c->handle); if (r > NBDKIT_FUA_EMULATE && p->plugin._api_version == 1) r = NBDKIT_FUA_EMULATE; return r; @@ -517,23 +528,25 @@ plugin_can_fua (struct backend *b, void *handle) } static int -plugin_can_multi_conn (struct backend *b, void *handle) +plugin_can_multi_conn (struct context *c) { + struct backend *b = c->b; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); if (p->plugin.can_multi_conn) - return normalize_bool (p->plugin.can_multi_conn (handle)); + return normalize_bool (p->plugin.can_multi_conn (c->handle)); else return 0; /* assume false */ } static int -plugin_can_cache (struct backend *b, void *handle) +plugin_can_cache (struct context *c) { + struct backend *b = c->b; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); if (p->plugin.can_cache) - return p->plugin.can_cache (handle); + return p->plugin.can_cache (c->handle); if (p->plugin.cache) return NBDKIT_CACHE_NATIVE; return NBDKIT_CACHE_NONE; @@ -561,35 +574,37 @@ get_error (struct backend_plugin *p) } static int -plugin_pread (struct backend *b, void *handle, +plugin_pread (struct context *c, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { + struct backend *b = c->b; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); int r; assert (p->plugin.pread || p->plugin._pread_v1); if (p->plugin.pread) - r = p->plugin.pread (handle, buf, count, offset, 0); + r = p->plugin.pread (c->handle, buf, count, offset, 0); else - r = p->plugin._pread_v1 (handle, buf, count, offset); + r = p->plugin._pread_v1 (c->handle, buf, count, offset); if (r == -1) *err = get_error (p); return r; } static int -plugin_flush (struct backend *b, void *handle, +plugin_flush (struct context *c, uint32_t flags, int *err) { + struct backend *b = c->b; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); int r; if (p->plugin.flush) - r = p->plugin.flush (handle, 0); + r = p->plugin.flush (c->handle, 0); else if (p->plugin._flush_v1) - r = p->plugin._flush_v1 (handle); + r = p->plugin._flush_v1 (c->handle); else { *err = EINVAL; return -1; @@ -600,10 +615,11 @@ plugin_flush (struct backend *b, void *handle, } static int -plugin_pwrite (struct backend *b, void *handle, +plugin_pwrite (struct context *c, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { + struct backend *b = c->b; int r; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); bool fua = flags & NBDKIT_FLAG_FUA; @@ -614,24 +630,25 @@ plugin_pwrite (struct backend *b, void *handle, need_flush = true; } if (p->plugin.pwrite) - r = p->plugin.pwrite (handle, buf, count, offset, flags); + r = p->plugin.pwrite (c->handle, buf, count, offset, flags); else if (p->plugin._pwrite_v1) - r = p->plugin._pwrite_v1 (handle, buf, count, offset); + r = p->plugin._pwrite_v1 (c->handle, buf, count, offset); else { *err = EROFS; return -1; } if (r != -1 && need_flush) - r = plugin_flush (b, handle, 0, err); + r = plugin_flush (c, 0, err); if (r == -1 && !*err) *err = get_error (p); return r; } static int -plugin_trim (struct backend *b, void *handle, +plugin_trim (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, int *err) { + struct backend *b = c->b; int r; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); bool fua = flags & NBDKIT_FLAG_FUA; @@ -642,24 +659,25 @@ plugin_trim (struct backend *b, void *handle, need_flush = true; } if (p->plugin.trim) - r = p->plugin.trim (handle, count, offset, flags); + r = p->plugin.trim (c->handle, count, offset, flags); else if (p->plugin._trim_v1) - r = p->plugin._trim_v1 (handle, count, offset); + r = p->plugin._trim_v1 (c->handle, count, offset); else { *err = EINVAL; return -1; } if (r != -1 && need_flush) - r = plugin_flush (b, handle, 0, err); + r = plugin_flush (c, 0, err); if (r == -1 && !*err) *err = get_error (p); return r; } static int -plugin_zero (struct backend *b, void *handle, +plugin_zero (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, int *err) { + struct backend *b = c->b; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); int r = -1; bool may_trim = flags & NBDKIT_FLAG_MAY_TRIM; @@ -678,13 +696,13 @@ plugin_zero (struct backend *b, void *handle, if (backend_can_zero (b) == NBDKIT_ZERO_NATIVE) { errno = 0; if (p->plugin.zero) - r = p->plugin.zero (handle, count, offset, flags); + r = p->plugin.zero (c->handle, count, offset, flags); else if (p->plugin._zero_v1) { if (fast_zero) { *err = EOPNOTSUPP; return -1; } - r = p->plugin._zero_v1 (handle, count, offset, may_trim); + r = p->plugin._zero_v1 (c->handle, count, offset, may_trim); } else emulate = true; @@ -711,7 +729,7 @@ plugin_zero (struct backend *b, void *handle, static /* const */ char buf[MAX_REQUEST_SIZE]; uint32_t limit = MIN (count, sizeof buf); - r = plugin_pwrite (b, handle, buf, limit, offset, flags, err); + r = plugin_pwrite (c, buf, limit, offset, flags, err); if (r == -1) break; count -= limit; @@ -719,17 +737,18 @@ plugin_zero (struct backend *b, void *handle, done: if (r != -1 && need_flush) - r = plugin_flush (b, handle, 0, err); + r = plugin_flush (c, 0, err); if (r == -1 && !*err) *err = get_error (p); return r; } static int -plugin_extents (struct backend *b, void *handle, +plugin_extents (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err) { + struct backend *b = c->b; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); int r; @@ -738,7 +757,7 @@ plugin_extents (struct backend *b, void *handle, return -1; } - r = p->plugin.extents (handle, count, offset, flags, extents); + r = p->plugin.extents (c->handle, count, offset, flags, extents); if (r >= 0 && nbdkit_extents_count (extents) < 1) { nbdkit_error ("extents: plugin must return at least one extent"); nbdkit_set_error (EINVAL); @@ -750,10 +769,11 @@ plugin_extents (struct backend *b, void *handle, } static int -plugin_cache (struct backend *b, void *handle, +plugin_cache (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, int *err) { + struct backend *b = c->b; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); int r; @@ -762,7 +782,7 @@ plugin_cache (struct backend *b, void *handle, if (!p->plugin.cache) return 0; - r = p->plugin.cache (handle, count, offset, flags); + r = p->plugin.cache (c->handle, count, offset, flags); if (r == -1) *err = get_error (p); return r; -- 2.30.1
Eric Blake
2021-Mar-05 23:31 UTC
[Libguestfs] [nbdkit PATCH v3 09/16] filters: Use struct context for next_ops
Expand the internal work done in an earlier patch to now also affect the public interface exposed to filters. Thankfully, we've already declared filters to not have a stable API/ABI, so this change doesn't hurt. Previously all backend_* functions that got a 'struct backend*' parameter then had to do a connection lookup for the matching handle; now we pass a 'struct context*' that already has the handle. The main impact to this patch is that the connection lookup moves from backend.c to filters.c, but it should be obvious that we are getting closer to the point where a backend context is completely independent of the current client connection. However, while we continue to use 'struct context' in the server, I intentionally exposed the public name as 'nbdkit_next'; the rationale for this is to enable later patches where I merge 'next_ops' and 'nxdata' into a single pointer, all while still being opaque to the filters. Similarly, I kept nbdkit-filter.h rather type-agnostic (typed strongly when used in server/ and the retry filter, but still two indistinguishable void* in all other filters). Later patches will then tighten things up with the needed mechanical churn to all the existing filters, including documentation updates. One oddball is nbdkit_backend_reopen, which now needs to update nxdata after adjusting contexts (in fact, nxdata can now be NULL after a failed reopen has disassociated any previous context from the connection). The fact that all the retry filter tests still pass is a good sign, even though future patches will be working to replace nbdkit_backend_reopen with finer-grained functions usable by more filters. --- include/nbdkit-filter.h | 91 ++++++------- server/internal.h | 48 +++---- server/backend.c | 184 +++++++++++++-------------- server/connections.c | 8 +- server/extents.c | 6 +- server/filters.c | 132 ++++++++++++------- server/plugins.c | 10 +- server/protocol-handshake-newstyle.c | 15 ++- server/protocol-handshake.c | 24 ++-- server/protocol.c | 24 ++-- filters/retry/retry.c | 16 +-- 11 files changed, 302 insertions(+), 256 deletions(-) diff --git a/include/nbdkit-filter.h b/include/nbdkit-filter.h index 0c172936..d16ea330 100644 --- a/include/nbdkit-filter.h +++ b/include/nbdkit-filter.h @@ -50,14 +50,17 @@ extern "C" { #define NBDKIT_ZERO_NATIVE 2 #ifdef NBDKIT_INTERNAL -/* Opaque type encapsulating all information needed for calling into +/* Opaque types encapsulating all information needed for calling into * the next filter or plugin. */ typedef struct backend nbdkit_backend; +typedef struct context nbdkit_next; #elif defined NBDKIT_RETRY_FILTER /* Hack to expose reopen to retry filter */ typedef struct nbdkit_backend nbdkit_backend; +typedef struct nbdkit_next nbdkit_next; #else typedef void nbdkit_backend; +typedef void nbdkit_next; #endif /* Next ops. */ @@ -76,34 +79,34 @@ typedef int nbdkit_next_open (nbdkit_backend *backend, struct nbdkit_next_ops { /* These callbacks are the same as normal plugin operations. */ - int64_t (*get_size) (nbdkit_backend *nxdata); - const char * (*export_description) (nbdkit_backend *nxdata); + int64_t (*get_size) (nbdkit_next *nxdata); + const char * (*export_description) (nbdkit_next *nxdata); - int (*can_write) (nbdkit_backend *nxdata); - int (*can_flush) (nbdkit_backend *nxdata); - int (*is_rotational) (nbdkit_backend *nxdata); - int (*can_trim) (nbdkit_backend *nxdata); - int (*can_zero) (nbdkit_backend *nxdata); - int (*can_fast_zero) (nbdkit_backend *nxdata); - int (*can_extents) (nbdkit_backend *nxdata); - int (*can_fua) (nbdkit_backend *nxdata); - int (*can_multi_conn) (nbdkit_backend *nxdata); - int (*can_cache) (nbdkit_backend *nxdata); + int (*can_write) (nbdkit_next *nxdata); + int (*can_flush) (nbdkit_next *nxdata); + int (*is_rotational) (nbdkit_next *nxdata); + int (*can_trim) (nbdkit_next *nxdata); + int (*can_zero) (nbdkit_next *nxdata); + int (*can_fast_zero) (nbdkit_next *nxdata); + int (*can_extents) (nbdkit_next *nxdata); + int (*can_fua) (nbdkit_next *nxdata); + int (*can_multi_conn) (nbdkit_next *nxdata); + int (*can_cache) (nbdkit_next *nxdata); - int (*pread) (nbdkit_backend *nxdata, + int (*pread) (nbdkit_next *nxdata, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err); - int (*pwrite) (nbdkit_backend *nxdata, + int (*pwrite) (nbdkit_next *nxdata, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err); - int (*flush) (nbdkit_backend *nxdata, uint32_t flags, int *err); - int (*trim) (nbdkit_backend *nxdata, uint32_t count, uint64_t offset, + int (*flush) (nbdkit_next *nxdata, uint32_t flags, int *err); + int (*trim) (nbdkit_next *nxdata, uint32_t count, uint64_t offset, uint32_t flags, int *err); - int (*zero) (nbdkit_backend *nxdata, uint32_t count, uint64_t offset, + int (*zero) (nbdkit_next *nxdata, uint32_t count, uint64_t offset, uint32_t flags, int *err); - int (*extents) (nbdkit_backend *nxdata, uint32_t count, uint64_t offset, + int (*extents) (nbdkit_next *nxdata, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err); - int (*cache) (nbdkit_backend *nxdata, uint32_t count, uint64_t offset, + int (*cache) (nbdkit_next *nxdata, uint32_t count, uint64_t offset, uint32_t flags, int *err); }; @@ -123,12 +126,12 @@ NBDKIT_EXTERN_DECL (struct nbdkit_extent, nbdkit_get_extent, (const struct nbdkit_extents *, size_t)); NBDKIT_EXTERN_DECL (struct nbdkit_extents *, nbdkit_extents_full, (struct nbdkit_next_ops *next_ops, - nbdkit_backend *nxdata, + nbdkit_next *nxdata, uint32_t count, uint64_t offset, uint32_t flags, int *err)); NBDKIT_EXTERN_DECL (int, nbdkit_extents_aligned, (struct nbdkit_next_ops *next_ops, - nbdkit_backend *nxdata, + nbdkit_next *nxdata, uint32_t count, uint64_t offset, uint32_t flags, uint32_t align, struct nbdkit_extents *extents, int *err)); @@ -153,7 +156,7 @@ NBDKIT_EXTERN_DECL (const struct nbdkit_export, nbdkit_get_export, */ NBDKIT_EXTERN_DECL (int, nbdkit_backend_reopen, (nbdkit_backend *backend, int readonly, - const char *exportname, nbdkit_backend **nxdata)); + const char *exportname, nbdkit_next **nxdata)); #endif /* Filter struct. */ @@ -200,56 +203,56 @@ struct nbdkit_filter { int readonly, const char *exportname, int is_tls); void (*close) (void *handle); - int (*prepare) (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, + int (*prepare) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle, int readonly); - int (*finalize) (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, + int (*finalize) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle); - int64_t (*get_size) (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, + int64_t (*get_size) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle); const char * (*export_description) (struct nbdkit_next_ops *next_ops, - nbdkit_backend *nxdata, void *handle); + nbdkit_next *nxdata, void *handle); - int (*can_write) (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, + int (*can_write) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle); - int (*can_flush) (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, + int (*can_flush) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle); int (*is_rotational) (struct nbdkit_next_ops *next_ops, - nbdkit_backend *nxdata, void *handle); - int (*can_trim) (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, + nbdkit_next *nxdata, void *handle); + int (*can_trim) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle); - int (*can_zero) (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, + int (*can_zero) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle); int (*can_fast_zero) (struct nbdkit_next_ops *next_ops, - nbdkit_backend *nxdata, void *handle); - int (*can_extents) (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, + nbdkit_next *nxdata, void *handle); + int (*can_extents) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle); - int (*can_fua) (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, + int (*can_fua) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle); int (*can_multi_conn) (struct nbdkit_next_ops *next_ops, - nbdkit_backend *nxdata, void *handle); - int (*can_cache) (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, + nbdkit_next *nxdata, void *handle); + int (*can_cache) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle); - int (*pread) (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, + int (*pread) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err); - int (*pwrite) (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, + int (*pwrite) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err); - int (*flush) (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, + int (*flush) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle, uint32_t flags, int *err); - int (*trim) (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, + int (*trim) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err); - int (*zero) (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, + int (*zero) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err); - int (*extents) (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, + int (*extents) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err); - int (*cache) (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, + int (*cache) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err); }; diff --git a/server/internal.h b/server/internal.h index e8828506..e5e8f797 100644 --- a/server/internal.h +++ b/server/internal.h @@ -415,8 +415,6 @@ extern int backend_list_exports (struct backend *b, int readonly, __attribute__((__nonnull__ (1, 3))); extern const char *backend_default_export (struct backend *b, int readonly) __attribute__((__nonnull__ (1))); -extern const char *backend_export_description (struct backend *b) - __attribute__((__nonnull__ (1))); /* exportname is only valid for this call and almost certainly will be * freed on return of this function, so backends must save the * exportname if they need to refer to it later. @@ -424,66 +422,68 @@ extern const char *backend_export_description (struct backend *b) extern struct context *backend_open (struct backend *b, int readonly, const char *exportname) __attribute__((__nonnull__ (1, 3))); -extern int backend_prepare (struct backend *b) +extern int backend_prepare (struct context *c) __attribute__((__nonnull__ (1))); -extern int backend_finalize (struct backend *b) +extern int backend_finalize (struct context *c) __attribute__((__nonnull__ (1))); -extern void backend_close (struct backend *b) +extern void backend_close (struct context *c) __attribute__((__nonnull__ (1))); -extern bool backend_valid_range (struct backend *b, +extern bool backend_valid_range (struct context *c, uint64_t offset, uint32_t count) __attribute__((__nonnull__ (1))); extern int backend_reopen (struct backend *b, int readonly, const char *exportname) __attribute__((__nonnull__ (1, 3))); -extern int64_t backend_get_size (struct backend *b) +extern const char *backend_export_description (struct context *c) __attribute__((__nonnull__ (1))); -extern int backend_can_write (struct backend *b) +extern int64_t backend_get_size (struct context *c) __attribute__((__nonnull__ (1))); -extern int backend_can_flush (struct backend *b) +extern int backend_can_write (struct context *c) __attribute__((__nonnull__ (1))); -extern int backend_is_rotational (struct backend *b) +extern int backend_can_flush (struct context *c) __attribute__((__nonnull__ (1))); -extern int backend_can_trim (struct backend *b) +extern int backend_is_rotational (struct context *c) __attribute__((__nonnull__ (1))); -extern int backend_can_zero (struct backend *b) +extern int backend_can_trim (struct context *c) __attribute__((__nonnull__ (1))); -extern int backend_can_fast_zero (struct backend *b) +extern int backend_can_zero (struct context *c) __attribute__((__nonnull__ (1))); -extern int backend_can_extents (struct backend *b) +extern int backend_can_fast_zero (struct context *c) __attribute__((__nonnull__ (1))); -extern int backend_can_fua (struct backend *b) +extern int backend_can_extents (struct context *c) __attribute__((__nonnull__ (1))); -extern int backend_can_multi_conn (struct backend *b) +extern int backend_can_fua (struct context *c) __attribute__((__nonnull__ (1))); -extern int backend_can_cache (struct backend *b) +extern int backend_can_multi_conn (struct context *c) + __attribute__((__nonnull__ (1))); +extern int backend_can_cache (struct context *c) __attribute__((__nonnull__ (1))); -extern int backend_pread (struct backend *b, +extern int backend_pread (struct context *c, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) __attribute__((__nonnull__ (1, 2, 6))); -extern int backend_pwrite (struct backend *b, +extern int backend_pwrite (struct context *c, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) __attribute__((__nonnull__ (1, 2, 6))); -extern int backend_flush (struct backend *b, +extern int backend_flush (struct context *c, uint32_t flags, int *err) __attribute__((__nonnull__ (1, 3))); -extern int backend_trim (struct backend *b, +extern int backend_trim (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, int *err) __attribute__((__nonnull__ (1, 5))); -extern int backend_zero (struct backend *b, +extern int backend_zero (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, int *err) __attribute__((__nonnull__ (1, 5))); -extern int backend_extents (struct backend *b, +extern int backend_extents (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err) __attribute__((__nonnull__ (1, 5, 6))); -extern int backend_cache (struct backend *b, +extern int backend_cache (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, int *err) __attribute__((__nonnull__ (1, 5))); diff --git a/server/backend.c b/server/backend.c index 45a6da2f..94ff0caa 100644 --- a/server/backend.c +++ b/server/backend.c @@ -258,8 +258,11 @@ backend_open (struct backend *b, int readonly, const char *exportname) controlpath_debug ("%s: open returned handle %p", b->name, c->handle); if (c->handle == NULL) { - if (b->i) /* Do not strand backend if this layer failed */ - backend_close (b->next); + if (b->i) { /* Do not strand backend if this layer failed */ + struct context *c2 = get_context (conn, b->next); + if (c2 != NULL) + backend_close (c2); + } free (c); return NULL; } @@ -269,10 +272,10 @@ backend_open (struct backend *b, int readonly, const char *exportname) } int -backend_prepare (struct backend *b) +backend_prepare (struct context *c) { GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; assert (c->handle); assert ((c->state & (HANDLE_OPEN | HANDLE_CONNECTED)) == HANDLE_OPEN); @@ -281,9 +284,11 @@ backend_prepare (struct backend *b) * plugin, similar to typical .open order. But remember that * a filter may skip opening its backend. */ - if (b->i && get_context (conn, b->next) != NULL && - backend_prepare (b->next) == -1) - return -1; + if (b->i) { + struct context *c2 = get_context (conn, b->next); + if (c2 != NULL && backend_prepare (c2) == -1) + return -1; + } controlpath_debug ("%s: prepare readonly=%d", b->name, c->can_write == 0); @@ -294,10 +299,10 @@ backend_prepare (struct backend *b) } int -backend_finalize (struct backend *b) +backend_finalize (struct context *c) { GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; /* Call these in reverse order to .prepare above, starting from the * filter furthest away from the plugin, and matching .close order. @@ -316,16 +321,19 @@ backend_finalize (struct backend *b) } } - if (b->i && get_context (conn, b->next)) - return backend_finalize (b->next); + if (b->i) { + struct context *c2 = get_context (conn, b->next); + if (c2 != NULL) + return backend_finalize (c2); + } return 0; } void -backend_close (struct backend *b) +backend_close (struct context *c) { GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; /* outer-to-inner order, opposite .open */ assert (c->handle); @@ -334,16 +342,16 @@ backend_close (struct backend *b) b->close (c); free (c); set_context (conn, b, NULL); - if (b->i && get_context (conn, b->next)) - backend_close (b->next); + if (b->i) { + struct context *c2 = get_context (conn, b->next); + if (c2 != NULL) + backend_close (c2); + } } bool -backend_valid_range (struct backend *b, uint64_t offset, uint32_t count) +backend_valid_range (struct context *c, uint64_t offset, uint32_t count) { - GET_CONN; - struct context *c = get_context (conn, b); - assert (c->exportsize <= INT64_MAX); /* Guaranteed by negotiation phase */ return count > 0 && offset <= c->exportsize && offset + count <= c->exportsize; @@ -355,23 +363,24 @@ int backend_reopen (struct backend *b, int readonly, const char *exportname) { GET_CONN; - struct context *h; + struct context *c; controlpath_debug ("%s: reopen readonly=%d exportname=\"%s\"", b->name, readonly, exportname); - if (get_context (conn, b)) { - if (backend_finalize (b) == -1) + c = get_context (conn, b); + if (c) { + if (backend_finalize (c) == -1) return -1; - backend_close (b); + backend_close (c); } - h = backend_open (b, readonly, exportname); - if (h == NULL) + c = backend_open (b, readonly, exportname); + if (c == NULL) return -1; - set_context (conn, b, h); - if (backend_prepare (b) == -1) { - backend_finalize (b); - backend_close (b); + set_context (conn, b, c); + if (backend_prepare (c) == -1) { + backend_finalize (c); + backend_close (c); return -1; } return 0; @@ -380,10 +389,9 @@ backend_reopen (struct backend *b, int readonly, const char *exportname) /* Wrappers for all callbacks in a filter's struct nbdkit_next_ops. */ const char * -backend_export_description (struct backend *b) +backend_export_description (struct context *c) { - GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; const char *s; controlpath_debug ("%s: export_description", b->name); @@ -402,10 +410,9 @@ backend_export_description (struct backend *b) } int64_t -backend_get_size (struct backend *b) +backend_get_size (struct context *c) { - GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->exportsize == -1) { @@ -416,10 +423,9 @@ backend_get_size (struct backend *b) } int -backend_can_write (struct backend *b) +backend_can_write (struct context *c) { - GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->can_write == -1) { @@ -430,10 +436,9 @@ backend_can_write (struct backend *b) } int -backend_can_flush (struct backend *b) +backend_can_flush (struct context *c) { - GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->can_flush == -1) { @@ -444,10 +449,9 @@ backend_can_flush (struct backend *b) } int -backend_is_rotational (struct backend *b) +backend_is_rotational (struct context *c) { - GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->is_rotational == -1) { @@ -458,16 +462,15 @@ backend_is_rotational (struct backend *b) } int -backend_can_trim (struct backend *b) +backend_can_trim (struct context *c) { - GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; int r; assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->can_trim == -1) { controlpath_debug ("%s: can_trim", b->name); - r = backend_can_write (b); + r = backend_can_write (c); if (r != 1) { c->can_trim = 0; return r; @@ -478,16 +481,15 @@ backend_can_trim (struct backend *b) } int -backend_can_zero (struct backend *b) +backend_can_zero (struct context *c) { - GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; int r; assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->can_zero == -1) { controlpath_debug ("%s: can_zero", b->name); - r = backend_can_write (b); + r = backend_can_write (c); if (r != 1) { c->can_zero = NBDKIT_ZERO_NONE; return r; /* Relies on 0 == NBDKIT_ZERO_NONE */ @@ -498,16 +500,15 @@ backend_can_zero (struct backend *b) } int -backend_can_fast_zero (struct backend *b) +backend_can_fast_zero (struct context *c) { - GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; int r; assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->can_fast_zero == -1) { controlpath_debug ("%s: can_fast_zero", b->name); - r = backend_can_zero (b); + r = backend_can_zero (c); if (r < NBDKIT_ZERO_EMULATE) { c->can_fast_zero = 0; return r; /* Relies on 0 == NBDKIT_ZERO_NONE */ @@ -518,10 +519,9 @@ backend_can_fast_zero (struct backend *b) } int -backend_can_extents (struct backend *b) +backend_can_extents (struct context *c) { - GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->can_extents == -1) { @@ -532,16 +532,15 @@ backend_can_extents (struct backend *b) } int -backend_can_fua (struct backend *b) +backend_can_fua (struct context *c) { - GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; int r; assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->can_fua == -1) { controlpath_debug ("%s: can_fua", b->name); - r = backend_can_write (b); + r = backend_can_write (c); if (r != 1) { c->can_fua = NBDKIT_FUA_NONE; return r; /* Relies on 0 == NBDKIT_FUA_NONE */ @@ -552,10 +551,9 @@ backend_can_fua (struct backend *b) } int -backend_can_multi_conn (struct backend *b) +backend_can_multi_conn (struct context *c) { - GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->can_multi_conn == -1) { @@ -566,10 +564,9 @@ backend_can_multi_conn (struct backend *b) } int -backend_can_cache (struct backend *b) +backend_can_cache (struct context *c) { - GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; assert (c->handle && (c->state & HANDLE_CONNECTED)); if (c->can_cache == -1) { @@ -580,16 +577,15 @@ backend_can_cache (struct backend *b) } int -backend_pread (struct backend *b, +backend_pread (struct context *c, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { - GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; int r; assert (c->handle && (c->state & HANDLE_CONNECTED)); - assert (backend_valid_range (b, offset, count)); + assert (backend_valid_range (c, offset, count)); assert (flags == 0); datapath_debug ("%s: pread count=%" PRIu32 " offset=%" PRIu64, b->name, count, offset); @@ -601,18 +597,17 @@ backend_pread (struct backend *b, } int -backend_pwrite (struct backend *b, +backend_pwrite (struct context *c, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { - GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; bool fua = !!(flags & NBDKIT_FLAG_FUA); int r; assert (c->handle && (c->state & HANDLE_CONNECTED)); assert (c->can_write == 1); - assert (backend_valid_range (b, offset, count)); + assert (backend_valid_range (c, offset, count)); assert (!(flags & ~NBDKIT_FLAG_FUA)); if (fua) assert (c->can_fua > NBDKIT_FUA_NONE); @@ -626,11 +621,10 @@ backend_pwrite (struct backend *b, } int -backend_flush (struct backend *b, +backend_flush (struct context *c, uint32_t flags, int *err) { - GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; int r; assert (c->handle && (c->state & HANDLE_CONNECTED)); @@ -645,19 +639,18 @@ backend_flush (struct backend *b, } int -backend_trim (struct backend *b, +backend_trim (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, int *err) { - GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; bool fua = !!(flags & NBDKIT_FLAG_FUA); int r; assert (c->handle && (c->state & HANDLE_CONNECTED)); assert (c->can_write == 1); assert (c->can_trim == 1); - assert (backend_valid_range (b, offset, count)); + assert (backend_valid_range (c, offset, count)); assert (!(flags & ~NBDKIT_FLAG_FUA)); if (fua) assert (c->can_fua > NBDKIT_FUA_NONE); @@ -671,12 +664,11 @@ backend_trim (struct backend *b, } int -backend_zero (struct backend *b, +backend_zero (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, int *err) { - GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; bool fua = !!(flags & NBDKIT_FLAG_FUA); bool fast = !!(flags & NBDKIT_FLAG_FAST_ZERO); int r; @@ -684,7 +676,7 @@ backend_zero (struct backend *b, assert (c->handle && (c->state & HANDLE_CONNECTED)); assert (c->can_write == 1); assert (c->can_zero > NBDKIT_ZERO_NONE); - assert (backend_valid_range (b, offset, count)); + assert (backend_valid_range (c, offset, count)); assert (!(flags & ~(NBDKIT_FLAG_MAY_TRIM | NBDKIT_FLAG_FUA | NBDKIT_FLAG_FAST_ZERO))); if (fua) @@ -706,17 +698,16 @@ backend_zero (struct backend *b, } int -backend_extents (struct backend *b, +backend_extents (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err) { - GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; int r; assert (c->handle && (c->state & HANDLE_CONNECTED)); assert (c->can_extents >= 0); - assert (backend_valid_range (b, offset, count)); + assert (backend_valid_range (c, offset, count)); assert (!(flags & ~NBDKIT_FLAG_REQ_ONE)); datapath_debug ("%s: extents count=%" PRIu32 " offset=%" PRIu64 " req_one=%d", b->name, count, offset, !!(flags & NBDKIT_FLAG_REQ_ONE)); @@ -737,17 +728,16 @@ backend_extents (struct backend *b, } int -backend_cache (struct backend *b, +backend_cache (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, int *err) { - GET_CONN; - struct context *c = get_context (conn, b); + struct backend *b = c->b; int r; assert (c->handle && (c->state & HANDLE_CONNECTED)); assert (c->can_cache > NBDKIT_CACHE_NONE); - assert (backend_valid_range (b, offset, count)); + assert (backend_valid_range (c, offset, count)); assert (flags == 0); datapath_debug ("%s: cache count=%" PRIu32 " offset=%" PRIu64, b->name, count, offset); @@ -758,7 +748,7 @@ backend_cache (struct backend *b, while (count) { limit = MIN (count, sizeof buf); - if (backend_pread (b, buf, limit, offset, flags, err) == -1) + if (backend_pread (c, buf, limit, offset, flags, err) == -1) return -1; count -= limit; } diff --git a/server/connections.c b/server/connections.c index 0115875b..930491a6 100644 --- a/server/connections.c +++ b/server/connections.c @@ -224,7 +224,7 @@ handle_single_connection (int sockin, int sockout) /* Finalize (for filters), called just before close. */ lock_request (); - r = backend_finalize (top); + r = backend_finalize (get_context (conn, top)); unlock_request (); if (r == -1) goto done; @@ -348,6 +348,7 @@ static void free_connection (struct connection *conn) { struct backend *b; + struct context *c; if (!conn) return; @@ -360,8 +361,9 @@ free_connection (struct connection *conn) */ if (!quit) { lock_request (); - if (get_context (conn, top)) - backend_close (top); + c = get_context (conn, top); + if (c) + backend_close (c); unlock_request (); } diff --git a/server/extents.c b/server/extents.c index cbc0f0dd..9699fe6a 100644 --- a/server/extents.c +++ b/server/extents.c @@ -1,5 +1,5 @@ /* nbdkit - * Copyright (C) 2019-2020 Red Hat Inc. + * Copyright (C) 2019-2021 Red Hat Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -213,7 +213,7 @@ nbdkit_add_extent (struct nbdkit_extents *exts, /* Compute aligned extents on behalf of a filter. */ int nbdkit_extents_aligned (struct nbdkit_next_ops *next_ops, - nbdkit_backend *nxdata, + nbdkit_next *nxdata, uint32_t count, uint64_t offset, uint32_t flags, uint32_t align, struct nbdkit_extents *exts, int *err) @@ -298,7 +298,7 @@ nbdkit_extents_aligned (struct nbdkit_next_ops *next_ops, * covering the region [offset..offset+count-1]. */ struct nbdkit_extents * -nbdkit_extents_full (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, +nbdkit_extents_full (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, uint32_t count, uint64_t offset, uint32_t flags, int *err) { diff --git a/server/filters.c b/server/filters.c index 7986e56f..5f2087d1 100644 --- a/server/filters.c +++ b/server/filters.c @@ -328,11 +328,13 @@ static struct nbdkit_next_ops next_ops = { static int filter_prepare (struct context *c, int readonly) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.prepare && - f->filter.prepare (&next_ops, b->next, c->handle, readonly) == -1) + f->filter.prepare (&next_ops, c_next, c->handle, readonly) == -1) return -1; return 0; @@ -341,11 +343,13 @@ filter_prepare (struct context *c, int readonly) static int filter_finalize (struct context *c) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.finalize && - f->filter.finalize (&next_ops, b->next, c->handle) == -1) + f->filter.finalize (&next_ops, c_next, c->handle) == -1) return -1; return 0; } @@ -353,145 +357,169 @@ filter_finalize (struct context *c) static const char * filter_export_description (struct context *c) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.export_description) - return f->filter.export_description (&next_ops, b->next, c->handle); + return f->filter.export_description (&next_ops, c_next, c->handle); else - return backend_export_description (b->next); + return backend_export_description (c_next); } static int64_t filter_get_size (struct context *c) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.get_size) - return f->filter.get_size (&next_ops, b->next, c->handle); + return f->filter.get_size (&next_ops, c_next, c->handle); else - return backend_get_size (b->next); + return backend_get_size (c_next); } static int filter_can_write (struct context *c) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.can_write) - return f->filter.can_write (&next_ops, b->next, c->handle); + return f->filter.can_write (&next_ops, c_next, c->handle); else - return backend_can_write (b->next); + return backend_can_write (c_next); } static int filter_can_flush (struct context *c) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.can_flush) - return f->filter.can_flush (&next_ops, b->next, c->handle); + return f->filter.can_flush (&next_ops, c_next, c->handle); else - return backend_can_flush (b->next); + return backend_can_flush (c_next); } static int filter_is_rotational (struct context *c) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.is_rotational) - return f->filter.is_rotational (&next_ops, b->next, c->handle); + return f->filter.is_rotational (&next_ops, c_next, c->handle); else - return backend_is_rotational (b->next); + return backend_is_rotational (c_next); } static int filter_can_trim (struct context *c) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.can_trim) - return f->filter.can_trim (&next_ops, b->next, c->handle); + return f->filter.can_trim (&next_ops, c_next, c->handle); else - return backend_can_trim (b->next); + return backend_can_trim (c_next); } static int filter_can_zero (struct context *c) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.can_zero) - return f->filter.can_zero (&next_ops, b->next, c->handle); + return f->filter.can_zero (&next_ops, c_next, c->handle); else - return backend_can_zero (b->next); + return backend_can_zero (c_next); } static int filter_can_fast_zero (struct context *c) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.can_fast_zero) - return f->filter.can_fast_zero (&next_ops, b->next, c->handle); + return f->filter.can_fast_zero (&next_ops, c_next, c->handle); else - return backend_can_fast_zero (b->next); + return backend_can_fast_zero (c_next); } static int filter_can_extents (struct context *c) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.can_extents) - return f->filter.can_extents (&next_ops, b->next, c->handle); + return f->filter.can_extents (&next_ops, c_next, c->handle); else - return backend_can_extents (b->next); + return backend_can_extents (c_next); } static int filter_can_fua (struct context *c) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.can_fua) - return f->filter.can_fua (&next_ops, b->next, c->handle); + return f->filter.can_fua (&next_ops, c_next, c->handle); else - return backend_can_fua (b->next); + return backend_can_fua (c_next); } static int filter_can_multi_conn (struct context *c) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.can_multi_conn) - return f->filter.can_multi_conn (&next_ops, b->next, c->handle); + return f->filter.can_multi_conn (&next_ops, c_next, c->handle); else - return backend_can_multi_conn (b->next); + return backend_can_multi_conn (c_next); } static int filter_can_cache (struct context *c) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.can_cache) - return f->filter.can_cache (&next_ops, b->next, c->handle); + return f->filter.can_cache (&next_ops, c_next, c->handle); else - return backend_can_cache (b->next); + return backend_can_cache (c_next); } static int @@ -499,14 +527,16 @@ filter_pread (struct context *c, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.pread) - return f->filter.pread (&next_ops, b->next, c->handle, + return f->filter.pread (&next_ops, c_next, c->handle, buf, count, offset, flags, err); else - return backend_pread (b->next, buf, count, offset, flags, err); + return backend_pread (c_next, buf, count, offset, flags, err); } static int @@ -514,27 +544,31 @@ filter_pwrite (struct context *c, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.pwrite) - return f->filter.pwrite (&next_ops, b->next, c->handle, + return f->filter.pwrite (&next_ops, c_next, c->handle, buf, count, offset, flags, err); else - return backend_pwrite (b->next, buf, count, offset, flags, err); + return backend_pwrite (c_next, buf, count, offset, flags, err); } static int filter_flush (struct context *c, uint32_t flags, int *err) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.flush) - return f->filter.flush (&next_ops, b->next, c->handle, flags, err); + return f->filter.flush (&next_ops, c_next, c->handle, flags, err); else - return backend_flush (b->next, flags, err); + return backend_flush (c_next, flags, err); } static int @@ -542,28 +576,32 @@ filter_trim (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, int *err) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.trim) - return f->filter.trim (&next_ops, b->next, c->handle, count, offset, + return f->filter.trim (&next_ops, c_next, c->handle, count, offset, flags, err); else - return backend_trim (b->next, count, offset, flags, err); + return backend_trim (c_next, count, offset, flags, err); } static int filter_zero (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, int *err) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.zero) - return f->filter.zero (&next_ops, b->next, c->handle, + return f->filter.zero (&next_ops, c_next, c->handle, count, offset, flags, err); else - return backend_zero (b->next, count, offset, flags, err); + return backend_zero (c_next, count, offset, flags, err); } static int @@ -571,15 +609,17 @@ filter_extents (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.extents) - return f->filter.extents (&next_ops, b->next, c->handle, + return f->filter.extents (&next_ops, c_next, c->handle, count, offset, flags, extents, err); else - return backend_extents (b->next, count, offset, flags, + return backend_extents (c_next, count, offset, flags, extents, err); } @@ -588,14 +628,16 @@ filter_cache (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, int *err) { + GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); + struct context *c_next = get_context (conn, b->next); if (f->filter.cache) - return f->filter.cache (&next_ops, b->next, c->handle, + return f->filter.cache (&next_ops, c_next, c->handle, count, offset, flags, err); else - return backend_cache (b->next, count, offset, flags, err); + return backend_cache (c_next, count, offset, flags, err); } static struct backend filter_functions = { @@ -696,9 +738,11 @@ filter_register (struct backend *next, size_t index, const char *filename, int nbdkit_backend_reopen (struct backend *b, int readonly, - const char *exportname, struct backend **nxdata) + const char *exportname, struct context **nxdata) { - /* For now, we don't need to update nxdata. */ - assert (b == *nxdata); - return backend_reopen (b, readonly, exportname); + GET_CONN; + int r = backend_reopen (b, readonly, exportname); + + *nxdata = get_context (conn, b); + return r; } diff --git a/server/plugins.c b/server/plugins.c index 17126ea1..9144cdae 100644 --- a/server/plugins.c +++ b/server/plugins.c @@ -488,7 +488,7 @@ plugin_can_fast_zero (struct context *c) */ if (p->plugin.zero == NULL) return 1; - r = backend_can_zero (b); + r = backend_can_zero (c); if (r == -1) return -1; return !r; @@ -625,7 +625,7 @@ plugin_pwrite (struct context *c, bool fua = flags & NBDKIT_FLAG_FUA; bool need_flush = false; - if (fua && backend_can_fua (b) != NBDKIT_FUA_NATIVE) { + if (fua && backend_can_fua (c) != NBDKIT_FUA_NATIVE) { flags &= ~NBDKIT_FLAG_FUA; need_flush = true; } @@ -654,7 +654,7 @@ plugin_trim (struct context *c, bool fua = flags & NBDKIT_FLAG_FUA; bool need_flush = false; - if (fua && backend_can_fua (b) != NBDKIT_FUA_NATIVE) { + if (fua && backend_can_fua (c) != NBDKIT_FUA_NATIVE) { flags &= ~NBDKIT_FLAG_FUA; need_flush = true; } @@ -686,14 +686,14 @@ plugin_zero (struct context *c, bool emulate = false; bool need_flush = false; - if (fua && backend_can_fua (b) != NBDKIT_FUA_NATIVE) { + if (fua && backend_can_fua (c) != NBDKIT_FUA_NATIVE) { flags &= ~NBDKIT_FLAG_FUA; need_flush = true; } if (!count) return 0; - if (backend_can_zero (b) == NBDKIT_ZERO_NATIVE) { + if (backend_can_zero (c) == NBDKIT_ZERO_NATIVE) { errno = 0; if (p->plugin.zero) r = p->plugin.zero (c->handle, count, offset, flags); diff --git a/server/protocol-handshake-newstyle.c b/server/protocol-handshake-newstyle.c index 4bc802cc..cfcd090d 100644 --- a/server/protocol-handshake-newstyle.c +++ b/server/protocol-handshake-newstyle.c @@ -341,6 +341,7 @@ negotiate_handshake_newstyle_options (void) const char *optname; uint64_t exportsize; struct backend *b; + struct context *c; for (nr_options = MAX_NR_OPTIONS; nr_options > 0; --nr_options) { CLEANUP_FREE char *data = NULL; @@ -567,10 +568,11 @@ negotiate_handshake_newstyle_options (void) */ if (finish_newstyle_options (&exportsize, &data[4], exportnamelen) == -1) { - if (get_context (conn, top)) { - if (backend_finalize (top) == -1) + c = get_context (conn, top); + if (c) { + if (backend_finalize (c) == -1) return -1; - backend_close (top); + backend_close (c); } if (send_newstyle_option_reply (option, NBD_REP_ERR_UNKNOWN) == -1) return -1; @@ -588,6 +590,7 @@ negotiate_handshake_newstyle_options (void) * NBD_INFO_EXPORT if it was requested, because we replied * already above). */ + c = get_context (conn, top); for (i = 0; i < nrinfos; ++i) { memcpy (&info, &data[4 + exportnamelen + 2 + i*2], 2); info = be16toh (info); @@ -616,7 +619,7 @@ negotiate_handshake_newstyle_options (void) break; case NBD_INFO_DESCRIPTION: { - const char *desc = backend_export_description (top); + const char *desc = backend_export_description (c); if (!desc) { debug ("newstyle negotiation: %s: " @@ -647,9 +650,9 @@ negotiate_handshake_newstyle_options (void) return -1; if (option == NBD_OPT_INFO) { - if (backend_finalize (top) == -1) + if (backend_finalize (c) == -1) return -1; - backend_close (top); + backend_close (c); } break; diff --git a/server/protocol-handshake.c b/server/protocol-handshake.c index 69f8b530..61521d43 100644 --- a/server/protocol-handshake.c +++ b/server/protocol-handshake.c @@ -87,10 +87,10 @@ protocol_common_open (uint64_t *exportsize, uint16_t *flags, set_context (conn, top, c); /* Prepare (for filters), called just after open. */ - if (backend_prepare (top) == -1) + if (backend_prepare (c) == -1) return -1; - size = backend_get_size (top); + size = backend_get_size (c); if (size == -1) return -1; if (size < 0) { @@ -102,56 +102,56 @@ protocol_common_open (uint64_t *exportsize, uint16_t *flags, /* Check all flags even if they won't be advertised, to prime the * cache and make later request validation easier. */ - fl = backend_can_write (top); + fl = backend_can_write (c); if (fl == -1) return -1; if (!fl) eflags |= NBD_FLAG_READ_ONLY; - fl = backend_can_zero (top); + fl = backend_can_zero (c); if (fl == -1) return -1; if (fl) eflags |= NBD_FLAG_SEND_WRITE_ZEROES; - fl = backend_can_fast_zero (top); + fl = backend_can_fast_zero (c); if (fl == -1) return -1; if (fl) eflags |= NBD_FLAG_SEND_FAST_ZERO; - fl = backend_can_trim (top); + fl = backend_can_trim (c); if (fl == -1) return -1; if (fl) eflags |= NBD_FLAG_SEND_TRIM; - fl = backend_can_fua (top); + fl = backend_can_fua (c); if (fl == -1) return -1; if (fl) eflags |= NBD_FLAG_SEND_FUA; - fl = backend_can_flush (top); + fl = backend_can_flush (c); if (fl == -1) return -1; if (fl) eflags |= NBD_FLAG_SEND_FLUSH; - fl = backend_is_rotational (top); + fl = backend_is_rotational (c); if (fl == -1) return -1; if (fl) eflags |= NBD_FLAG_ROTATIONAL; /* multi-conn is useless if parallel connections are not allowed. */ - fl = backend_can_multi_conn (top); + fl = backend_can_multi_conn (c); if (fl == -1) return -1; if (fl && (thread_model > NBDKIT_THREAD_MODEL_SERIALIZE_CONNECTIONS)) eflags |= NBD_FLAG_CAN_MULTI_CONN; - fl = backend_can_cache (top); + fl = backend_can_cache (c); if (fl == -1) return -1; if (fl) @@ -162,7 +162,7 @@ protocol_common_open (uint64_t *exportsize, uint16_t *flags, * not have to worry about errors, and makes test-layers easier to * write. */ - fl = backend_can_extents (top); + fl = backend_can_extents (c); if (fl == -1) return -1; diff --git a/server/protocol.c b/server/protocol.c index e7ba4bf1..fedc701a 100644 --- a/server/protocol.c +++ b/server/protocol.c @@ -1,5 +1,5 @@ /* nbdkit - * Copyright (C) 2013-2020 Red Hat Inc. + * Copyright (C) 2013-2021 Red Hat Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -53,6 +53,7 @@ validate_request (uint16_t cmd, uint16_t flags, uint64_t offset, uint32_t count, uint32_t *error) { GET_CONN; + struct context *c = get_context (conn, top); /* Readonly connection? */ if (conn->eflags & NBD_FLAG_READ_ONLY && @@ -72,7 +73,7 @@ validate_request (uint16_t cmd, uint16_t flags, uint64_t offset, uint32_t count, case NBD_CMD_TRIM: case NBD_CMD_WRITE_ZEROES: case NBD_CMD_BLOCK_STATUS: - if (!backend_valid_range (top, offset, count)) { + if (!backend_valid_range (c, offset, count)) { /* XXX Allow writes to extend the disk? */ nbdkit_error ("invalid request: %s: offset and count are out of range: " "offset=%" PRIu64 " count=%" PRIu32, @@ -229,6 +230,8 @@ static uint32_t handle_request (uint16_t cmd, uint16_t flags, uint64_t offset, uint32_t count, void *buf, struct nbdkit_extents *extents) { + GET_CONN; + struct context *c = get_context (conn, top); uint32_t f = 0; int err = 0; @@ -238,31 +241,31 @@ handle_request (uint16_t cmd, uint16_t flags, uint64_t offset, uint32_t count, switch (cmd) { case NBD_CMD_READ: - if (backend_pread (top, buf, count, offset, 0, &err) == -1) + if (backend_pread (c, buf, count, offset, 0, &err) == -1) return err; break; case NBD_CMD_WRITE: if (flags & NBD_CMD_FLAG_FUA) f |= NBDKIT_FLAG_FUA; - if (backend_pwrite (top, buf, count, offset, f, &err) == -1) + if (backend_pwrite (c, buf, count, offset, f, &err) == -1) return err; break; case NBD_CMD_FLUSH: - if (backend_flush (top, 0, &err) == -1) + if (backend_flush (c, 0, &err) == -1) return err; break; case NBD_CMD_TRIM: if (flags & NBD_CMD_FLAG_FUA) f |= NBDKIT_FLAG_FUA; - if (backend_trim (top, count, offset, f, &err) == -1) + if (backend_trim (c, count, offset, f, &err) == -1) return err; break; case NBD_CMD_CACHE: - if (backend_cache (top, count, offset, 0, &err) == -1) + if (backend_cache (c, count, offset, 0, &err) == -1) return err; break; @@ -273,14 +276,14 @@ handle_request (uint16_t cmd, uint16_t flags, uint64_t offset, uint32_t count, f |= NBDKIT_FLAG_FUA; if (flags & NBD_CMD_FLAG_FAST_ZERO) f |= NBDKIT_FLAG_FAST_ZERO; - if (backend_zero (top, count, offset, f, &err) == -1) + if (backend_zero (c, count, offset, f, &err) == -1) return err; break; case NBD_CMD_BLOCK_STATUS: if (flags & NBD_CMD_FLAG_REQ_ONE) f |= NBDKIT_FLAG_REQ_ONE; - if (backend_extents (top, count, offset, f, + if (backend_extents (c, count, offset, f, extents, &err) == -1) return err; break; @@ -683,7 +686,8 @@ protocol_recv_request_send_reply (void) /* Allocate the extents list for block status only. */ if (cmd == NBD_CMD_BLOCK_STATUS) { - extents = nbdkit_extents_new (offset, backend_get_size (top)); + struct context *c = get_context (conn, top); + extents = nbdkit_extents_new (offset, backend_get_size (c)); if (extents == NULL) { error = ENOMEM; goto send_reply; diff --git a/filters/retry/retry.c b/filters/retry/retry.c index abd49eb8..8decee6a 100644 --- a/filters/retry/retry.c +++ b/filters/retry/retry.c @@ -176,7 +176,7 @@ valid_range (struct nbdkit_next_ops *next_ops, void *nxdata, static bool do_retry (struct retry_handle *h, struct retry_data *data, - nbdkit_backend **nxdata, const char *method, int *err) + nbdkit_next **nxdata, const char *method, int *err) { /* If it's the first retry, initialize the other fields in *data. */ if (data->retry == 0) @@ -225,7 +225,7 @@ do_retry (struct retry_handle *h, struct retry_data *data, } static int -retry_pread (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, +retry_pread (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -246,7 +246,7 @@ retry_pread (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, /* Write. */ static int -retry_pwrite (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, +retry_pwrite (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -281,7 +281,7 @@ retry_pwrite (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, /* Trim. */ static int -retry_trim (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, +retry_trim (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -316,7 +316,7 @@ retry_trim (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, /* Flush. */ static int -retry_flush (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, +retry_flush (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle, uint32_t flags, int *err) { @@ -341,7 +341,7 @@ retry_flush (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, /* Zero. */ static int -retry_zero (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, +retry_zero (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -381,7 +381,7 @@ retry_zero (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, /* Extents. */ static int -retry_extents (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, +retry_extents (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err) @@ -429,7 +429,7 @@ retry_extents (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, /* Cache. */ static int -retry_cache (struct nbdkit_next_ops *next_ops, nbdkit_backend *nxdata, +retry_cache (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) -- 2.30.1
Eric Blake
2021-Mar-05 23:31 UTC
[Libguestfs] [nbdkit PATCH v3 10/16] server: Store nbdkit_next_ops in struct context
Time to take advantage of C typing rules. First, make 'struct context' a derived class with 'struct nbdkit_next_ops' as its first member, so that a pointer to one is now the same pointer to the other at the ABI level. Next, note that all entries in filters.h's next_ops are backend_* functions, so we can move that static list into backend.h instead, and populate next_ops as part of backend_open. Since filters still see 'nbdkit_context*' typedef'd to 'void*', they are none the wiser, even though filters.c is now passing the same pointer to two different parameters (since &c_next->next == c_next). Yes, that means that next_ops->FOO(nxdata) can now be equally spelled as next_ops->FOO(next_ops). The oddball (once again) is the retry filter; since nbdkit_backend_reopen only affects one of the two pointers, the filter is now updated to ignore one parameter in favor of the other. A later patch will then do the mechanical change to all the remaining filters to be fully type-safe at the same time we reduce the parameter duplication to just pass a single copy of context. The upshot of this refactoring is that it also becomes easier to introduce a new function for opening a context from a filter, which can return a single pointer containing everything the filter needs to call into the plugin. --- include/nbdkit-filter.h | 2 +- server/internal.h | 2 + server/backend.c | 23 +++++++++++ server/filters.c | 64 ++++++++++------------------- filters/retry/retry.c | 84 +++++++++++++++++++------------------- tests/test-layers-filter.c | 1 + 6 files changed, 90 insertions(+), 86 deletions(-) diff --git a/include/nbdkit-filter.h b/include/nbdkit-filter.h index d16ea330..b47e78c3 100644 --- a/include/nbdkit-filter.h +++ b/include/nbdkit-filter.h @@ -57,7 +57,7 @@ typedef struct backend nbdkit_backend; typedef struct context nbdkit_next; #elif defined NBDKIT_RETRY_FILTER /* Hack to expose reopen to retry filter */ typedef struct nbdkit_backend nbdkit_backend; -typedef struct nbdkit_next nbdkit_next; +typedef struct nbdkit_next_ops nbdkit_next; #else typedef void nbdkit_backend; typedef void nbdkit_next; diff --git a/server/internal.h b/server/internal.h index e5e8f797..23639bcd 100644 --- a/server/internal.h +++ b/server/internal.h @@ -203,6 +203,8 @@ enum { }; struct context { + struct nbdkit_next_ops next; /* Must be first member, for ABI reasons */ + void *handle; /* Plugin or filter handle. */ struct backend *b; /* Backend that provided handle. */ diff --git a/server/backend.c b/server/backend.c index 94ff0caa..58d10a3f 100644 --- a/server/backend.c +++ b/server/backend.c @@ -211,6 +211,28 @@ backend_default_export (struct backend *b, int readonly) return conn->default_exportname[b->i]; } +static struct nbdkit_next_ops next_ops = { + .export_description = backend_export_description, + .get_size = backend_get_size, + .can_write = backend_can_write, + .can_flush = backend_can_flush, + .is_rotational = backend_is_rotational, + .can_trim = backend_can_trim, + .can_zero = backend_can_zero, + .can_fast_zero = backend_can_fast_zero, + .can_extents = backend_can_extents, + .can_fua = backend_can_fua, + .can_multi_conn = backend_can_multi_conn, + .can_cache = backend_can_cache, + .pread = backend_pread, + .pwrite = backend_pwrite, + .flush = backend_flush, + .trim = backend_trim, + .zero = backend_zero, + .extents = backend_extents, + .cache = backend_cache, +}; + struct context * backend_open (struct backend *b, int readonly, const char *exportname) { @@ -226,6 +248,7 @@ backend_open (struct backend *b, int readonly, const char *exportname) b->name, readonly, exportname, conn->using_tls); assert (conn->contexts[b->i] == NULL); + c->next = next_ops; c->handle = NULL; c->b = b; c->state = 0; diff --git a/server/filters.c b/server/filters.c index 5f2087d1..a200d61b 100644 --- a/server/filters.c +++ b/server/filters.c @@ -303,28 +303,6 @@ filter_close (struct context *c) f->filter.close (c->handle); } -static struct nbdkit_next_ops next_ops = { - .export_description = backend_export_description, - .get_size = backend_get_size, - .can_write = backend_can_write, - .can_flush = backend_can_flush, - .is_rotational = backend_is_rotational, - .can_trim = backend_can_trim, - .can_zero = backend_can_zero, - .can_fast_zero = backend_can_fast_zero, - .can_extents = backend_can_extents, - .can_fua = backend_can_fua, - .can_multi_conn = backend_can_multi_conn, - .can_cache = backend_can_cache, - .pread = backend_pread, - .pwrite = backend_pwrite, - .flush = backend_flush, - .trim = backend_trim, - .zero = backend_zero, - .extents = backend_extents, - .cache = backend_cache, -}; - static int filter_prepare (struct context *c, int readonly) { @@ -334,7 +312,7 @@ filter_prepare (struct context *c, int readonly) struct context *c_next = get_context (conn, b->next); if (f->filter.prepare && - f->filter.prepare (&next_ops, c_next, c->handle, readonly) == -1) + f->filter.prepare (&c_next->next, c_next, c->handle, readonly) == -1) return -1; return 0; @@ -349,7 +327,7 @@ filter_finalize (struct context *c) struct context *c_next = get_context (conn, b->next); if (f->filter.finalize && - f->filter.finalize (&next_ops, c_next, c->handle) == -1) + f->filter.finalize (&c_next->next, c_next, c->handle) == -1) return -1; return 0; } @@ -363,7 +341,7 @@ filter_export_description (struct context *c) struct context *c_next = get_context (conn, b->next); if (f->filter.export_description) - return f->filter.export_description (&next_ops, c_next, c->handle); + return f->filter.export_description (&c_next->next, c_next, c->handle); else return backend_export_description (c_next); } @@ -377,7 +355,7 @@ filter_get_size (struct context *c) struct context *c_next = get_context (conn, b->next); if (f->filter.get_size) - return f->filter.get_size (&next_ops, c_next, c->handle); + return f->filter.get_size (&c_next->next, c_next, c->handle); else return backend_get_size (c_next); } @@ -391,7 +369,7 @@ filter_can_write (struct context *c) struct context *c_next = get_context (conn, b->next); if (f->filter.can_write) - return f->filter.can_write (&next_ops, c_next, c->handle); + return f->filter.can_write (&c_next->next, c_next, c->handle); else return backend_can_write (c_next); } @@ -405,7 +383,7 @@ filter_can_flush (struct context *c) struct context *c_next = get_context (conn, b->next); if (f->filter.can_flush) - return f->filter.can_flush (&next_ops, c_next, c->handle); + return f->filter.can_flush (&c_next->next, c_next, c->handle); else return backend_can_flush (c_next); } @@ -419,7 +397,7 @@ filter_is_rotational (struct context *c) struct context *c_next = get_context (conn, b->next); if (f->filter.is_rotational) - return f->filter.is_rotational (&next_ops, c_next, c->handle); + return f->filter.is_rotational (&c_next->next, c_next, c->handle); else return backend_is_rotational (c_next); } @@ -433,7 +411,7 @@ filter_can_trim (struct context *c) struct context *c_next = get_context (conn, b->next); if (f->filter.can_trim) - return f->filter.can_trim (&next_ops, c_next, c->handle); + return f->filter.can_trim (&c_next->next, c_next, c->handle); else return backend_can_trim (c_next); } @@ -447,7 +425,7 @@ filter_can_zero (struct context *c) struct context *c_next = get_context (conn, b->next); if (f->filter.can_zero) - return f->filter.can_zero (&next_ops, c_next, c->handle); + return f->filter.can_zero (&c_next->next, c_next, c->handle); else return backend_can_zero (c_next); } @@ -461,7 +439,7 @@ filter_can_fast_zero (struct context *c) struct context *c_next = get_context (conn, b->next); if (f->filter.can_fast_zero) - return f->filter.can_fast_zero (&next_ops, c_next, c->handle); + return f->filter.can_fast_zero (&c_next->next, c_next, c->handle); else return backend_can_fast_zero (c_next); } @@ -475,7 +453,7 @@ filter_can_extents (struct context *c) struct context *c_next = get_context (conn, b->next); if (f->filter.can_extents) - return f->filter.can_extents (&next_ops, c_next, c->handle); + return f->filter.can_extents (&c_next->next, c_next, c->handle); else return backend_can_extents (c_next); } @@ -489,7 +467,7 @@ filter_can_fua (struct context *c) struct context *c_next = get_context (conn, b->next); if (f->filter.can_fua) - return f->filter.can_fua (&next_ops, c_next, c->handle); + return f->filter.can_fua (&c_next->next, c_next, c->handle); else return backend_can_fua (c_next); } @@ -503,7 +481,7 @@ filter_can_multi_conn (struct context *c) struct context *c_next = get_context (conn, b->next); if (f->filter.can_multi_conn) - return f->filter.can_multi_conn (&next_ops, c_next, c->handle); + return f->filter.can_multi_conn (&c_next->next, c_next, c->handle); else return backend_can_multi_conn (c_next); } @@ -517,7 +495,7 @@ filter_can_cache (struct context *c) struct context *c_next = get_context (conn, b->next); if (f->filter.can_cache) - return f->filter.can_cache (&next_ops, c_next, c->handle); + return f->filter.can_cache (&c_next->next, c_next, c->handle); else return backend_can_cache (c_next); } @@ -533,7 +511,7 @@ filter_pread (struct context *c, struct context *c_next = get_context (conn, b->next); if (f->filter.pread) - return f->filter.pread (&next_ops, c_next, c->handle, + return f->filter.pread (&c_next->next, c_next, c->handle, buf, count, offset, flags, err); else return backend_pread (c_next, buf, count, offset, flags, err); @@ -550,7 +528,7 @@ filter_pwrite (struct context *c, struct context *c_next = get_context (conn, b->next); if (f->filter.pwrite) - return f->filter.pwrite (&next_ops, c_next, c->handle, + return f->filter.pwrite (&c_next->next, c_next, c->handle, buf, count, offset, flags, err); else return backend_pwrite (c_next, buf, count, offset, flags, err); @@ -566,7 +544,7 @@ filter_flush (struct context *c, struct context *c_next = get_context (conn, b->next); if (f->filter.flush) - return f->filter.flush (&next_ops, c_next, c->handle, flags, err); + return f->filter.flush (&c_next->next, c_next, c->handle, flags, err); else return backend_flush (c_next, flags, err); } @@ -582,7 +560,7 @@ filter_trim (struct context *c, struct context *c_next = get_context (conn, b->next); if (f->filter.trim) - return f->filter.trim (&next_ops, c_next, c->handle, count, offset, + return f->filter.trim (&c_next->next, c_next, c->handle, count, offset, flags, err); else return backend_trim (c_next, count, offset, flags, err); @@ -598,7 +576,7 @@ filter_zero (struct context *c, struct context *c_next = get_context (conn, b->next); if (f->filter.zero) - return f->filter.zero (&next_ops, c_next, c->handle, + return f->filter.zero (&c_next->next, c_next, c->handle, count, offset, flags, err); else return backend_zero (c_next, count, offset, flags, err); @@ -615,7 +593,7 @@ filter_extents (struct context *c, struct context *c_next = get_context (conn, b->next); if (f->filter.extents) - return f->filter.extents (&next_ops, c_next, c->handle, + return f->filter.extents (&c_next->next, c_next, c->handle, count, offset, flags, extents, err); else @@ -634,7 +612,7 @@ filter_cache (struct context *c, struct context *c_next = get_context (conn, b->next); if (f->filter.cache) - return f->filter.cache (&next_ops, c_next, c->handle, + return f->filter.cache (&c_next->next, c_next, c->handle, count, offset, flags, err); else return backend_cache (c_next, count, offset, flags, err); diff --git a/filters/retry/retry.c b/filters/retry/retry.c index 8decee6a..a2b5dc66 100644 --- a/filters/retry/retry.c +++ b/filters/retry/retry.c @@ -164,10 +164,10 @@ struct retry_data { }; static bool -valid_range (struct nbdkit_next_ops *next_ops, void *nxdata, +valid_range (struct nbdkit_next_ops *next, uint32_t count, uint64_t offset, bool is_write, int *err) { - if ((int64_t) offset + count > next_ops->get_size (nxdata)) { + if ((int64_t) offset + count > next->get_size (next)) { *err = is_write ? ENOSPC : EIO; return false; } @@ -176,7 +176,7 @@ valid_range (struct nbdkit_next_ops *next_ops, void *nxdata, static bool do_retry (struct retry_handle *h, struct retry_data *data, - nbdkit_next **nxdata, const char *method, int *err) + nbdkit_next **next, const char *method, int *err) { /* If it's the first retry, initialize the other fields in *data. */ if (data->retry == 0) @@ -210,7 +210,7 @@ do_retry (struct retry_handle *h, struct retry_data *data, /* Reopen the connection. */ h->reopens++; if (nbdkit_backend_reopen (h->backend, h->readonly || force_readonly, - h->exportname, nxdata) == -1) { + h->exportname, next) == -1) { /* If the reopen fails we treat it the same way as a command * failing. */ @@ -225,7 +225,7 @@ do_retry (struct retry_handle *h, struct retry_data *data, } static int -retry_pread (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, +retry_pread (struct nbdkit_next_ops *next_ops, nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -234,11 +234,11 @@ retry_pread (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, int r; again: - if (! (h->open && valid_range (next_ops, nxdata, count, offset, false, err))) + if (! (h->open && valid_range (next, count, offset, false, err))) r = -1; else - r = next_ops->pread (nxdata, buf, count, offset, flags, err); - if (r == -1 && do_retry (h, &data, &nxdata, "pread", err)) + r = next->pread (next, buf, count, offset, flags, err); + if (r == -1 && do_retry (h, &data, &next, "pread", err)) goto again; return r; @@ -246,7 +246,7 @@ retry_pread (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, /* Write. */ static int -retry_pwrite (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, +retry_pwrite (struct nbdkit_next_ops *next_ops, nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -260,20 +260,20 @@ retry_pwrite (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, *err = EROFS; return -1; } - if (! (h->open && valid_range (next_ops, nxdata, count, offset, true, err))) + if (! (h->open && valid_range (next, count, offset, true, err))) r = -1; - else if (next_ops->can_write (nxdata) != 1) { + else if (next->can_write (next) != 1) { *err = EROFS; r = -1; } else if (flags & NBDKIT_FLAG_FUA && - next_ops->can_fua (nxdata) <= NBDKIT_FUA_NONE) { + next->can_fua (next) <= NBDKIT_FUA_NONE) { *err = EIO; r = -1; } else - r = next_ops->pwrite (nxdata, buf, count, offset, flags, err); - if (r == -1 && do_retry (h, &data, &nxdata, "pwrite", err)) + r = next->pwrite (next, buf, count, offset, flags, err); + if (r == -1 && do_retry (h, &data, &next, "pwrite", err)) goto again; return r; @@ -281,7 +281,7 @@ retry_pwrite (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, /* Trim. */ static int -retry_trim (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, +retry_trim (struct nbdkit_next_ops *next_ops, nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -295,20 +295,20 @@ retry_trim (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, *err = EROFS; return -1; } - if (! (h->open && valid_range (next_ops, nxdata, count, offset, true, err))) + if (! (h->open && valid_range (next, count, offset, true, err))) r = -1; - else if (next_ops->can_trim (nxdata) != 1) { + else if (next->can_trim (next) != 1) { *err = EROFS; r = -1; } else if (flags & NBDKIT_FLAG_FUA && - next_ops->can_fua (nxdata) <= NBDKIT_FUA_NONE) { + next->can_fua (next) <= NBDKIT_FUA_NONE) { *err = EIO; r = -1; } else - r = next_ops->trim (nxdata, count, offset, flags, err); - if (r == -1 && do_retry (h, &data, &nxdata, "trim", err)) + r = next->trim (next, count, offset, flags, err); + if (r == -1 && do_retry (h, &data, &next, "trim", err)) goto again; return r; @@ -316,7 +316,7 @@ retry_trim (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, /* Flush. */ static int -retry_flush (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, +retry_flush (struct nbdkit_next_ops *next_ops, nbdkit_next *next, void *handle, uint32_t flags, int *err) { @@ -327,13 +327,13 @@ retry_flush (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, again: if (! h->open) r = -1; - else if (next_ops->can_flush (nxdata) != 1) { + else if (next->can_flush (next) != 1) { *err = EIO; r = -1; } else - r = next_ops->flush (nxdata, flags, err); - if (r == -1 && do_retry (h, &data, &nxdata, "flush", err)) + r = next->flush (next, flags, err); + if (r == -1 && do_retry (h, &data, &next, "flush", err)) goto again; return r; @@ -341,7 +341,7 @@ retry_flush (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, /* Zero. */ static int -retry_zero (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, +retry_zero (struct nbdkit_next_ops *next_ops, nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -356,24 +356,24 @@ retry_zero (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, return -1; } if (flags & NBDKIT_FLAG_FAST_ZERO && - (! h->open || next_ops->can_fast_zero (nxdata) != 1)) { + (! h->open || next->can_fast_zero (next) != 1)) { *err = EOPNOTSUPP; return -1; } - if (! (h->open && valid_range (next_ops, nxdata, count, offset, true, err))) + if (! (h->open && valid_range (next, count, offset, true, err))) r = -1; - else if (next_ops->can_zero (nxdata) <= NBDKIT_ZERO_NONE) { + else if (next->can_zero (next) <= NBDKIT_ZERO_NONE) { *err = EROFS; r = -1; } else if (flags & NBDKIT_FLAG_FUA && - next_ops->can_fua (nxdata) <= NBDKIT_FUA_NONE) { + next->can_fua (next) <= NBDKIT_FUA_NONE) { *err = EIO; r = -1; } else - r = next_ops->zero (nxdata, count, offset, flags, err); - if (r == -1 && do_retry (h, &data, &nxdata, "zero", err)) + r = next->zero (next, count, offset, flags, err); + if (r == -1 && do_retry (h, &data, &next, "zero", err)) goto again; return r; @@ -381,7 +381,7 @@ retry_zero (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, /* Extents. */ static int -retry_extents (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, +retry_extents (struct nbdkit_next_ops *next_ops, nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err) @@ -393,23 +393,23 @@ retry_extents (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, size_t i; again: - if (! (h->open && valid_range (next_ops, nxdata, count, offset, false, err))) + if (! (h->open && valid_range (next, count, offset, false, err))) r = -1; - else if (next_ops->can_extents (nxdata) != 1) { + else if (next->can_extents (next) != 1) { *err = EIO; r = -1; } else { /* Each retry must begin with extents reset to the right beginning. */ nbdkit_extents_free (extents2); - extents2 = nbdkit_extents_new (offset, next_ops->get_size (nxdata)); + extents2 = nbdkit_extents_new (offset, next->get_size (next)); if (extents2 == NULL) { *err = errno; return -1; /* Not worth a retry after ENOMEM. */ } - r = next_ops->extents (nxdata, count, offset, flags, extents2, err); + r = next->extents (next, count, offset, flags, extents2, err); } - if (r == -1 && do_retry (h, &data, &nxdata, "extents", err)) + if (r == -1 && do_retry (h, &data, &next, "extents", err)) goto again; if (r == 0) { @@ -429,7 +429,7 @@ retry_extents (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, /* Cache. */ static int -retry_cache (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, +retry_cache (struct nbdkit_next_ops *next_ops, nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -439,15 +439,15 @@ retry_cache (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, int r; again: - if (! (h->open && valid_range (next_ops, nxdata, count, offset, false, err))) + if (! (h->open && valid_range (next, count, offset, false, err))) r = -1; - else if (next_ops->can_cache (nxdata) <= NBDKIT_CACHE_NONE) { + else if (next->can_cache (next) <= NBDKIT_CACHE_NONE) { *err = EIO; r = -1; } else - r = next_ops->cache (nxdata, count, offset, flags, err); - if (r == -1 && do_retry (h, &data, &nxdata, "cache", err)) + r = next->cache (next, count, offset, flags, err); + if (r == -1 && do_retry (h, &data, &next, "cache", err)) goto again; return r; diff --git a/tests/test-layers-filter.c b/tests/test-layers-filter.c index fc2fcbfd..ed06a008 100644 --- a/tests/test-layers-filter.c +++ b/tests/test-layers-filter.c @@ -164,6 +164,7 @@ test_layers_filter_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, assert (h->next_ops == NULL); h->next_ops = next_ops; h->nxdata = nxdata; + assert (next_ops == nxdata); DEBUG_FUNCTION; return 0; } -- 2.30.1
Eric Blake
2021-Mar-05 23:31 UTC
[Libguestfs] [nbdkit PATCH v3 11/16] filters: Use context rather than connection to track c_next
This is another API/ABI change to filters, but that doesn't matter. Instead of having a 1:1 correspondence of automatic backend context to the current connection (which means filters.c has to consult GET_CONN on every action), switch things so that a given context tracks the next context. This requires another signature change to the internal backend_open and backend_reopen functions, as well as a public change to the type of the argument handed to filter .open calls. A given connection now only needs to track the top_context, and we no longer need get_context()/set_context(). Internally, nbdkit_context and nbdkit_next are the same type, but the public interface for filters keeps them separate for type-safety reasons (assigning a backend handle to the current filter's context is different than calling into the backend via next_ops/nxdata as the backend's context). A few filters were already using the typedef name 'nbdkit_backend *' instead of 'void *'; while they would still compile as-is, updating their type makes it look nicer. A later patch will force type-safety on all the remaining filters, but it's better to save that mechanical churn separately from this ABI change. Also, with this in place, an upcoming patch can finally allow filters to open up a context independently of the current client connection. --- docs/nbdkit-filter.pod | 12 ++-- include/nbdkit-filter.h | 9 ++- server/internal.h | 12 ++-- server/backend.c | 70 +++++++++------------- server/connections.c | 33 ++--------- server/filters.c | 87 +++++++++++----------------- server/plugins.c | 3 +- server/protocol-handshake-newstyle.c | 17 +++--- server/protocol-handshake.c | 30 +++++----- server/protocol.c | 9 ++- filters/checkwrite/checkwrite.c | 2 +- filters/exitlast/exitlast.c | 2 +- filters/exitwhen/exitwhen.c | 2 +- filters/gzip/gzip.c | 2 +- filters/limit/limit.c | 2 +- filters/retry/retry.c | 4 +- filters/tar/tar.c | 2 +- 17 files changed, 116 insertions(+), 182 deletions(-) diff --git a/docs/nbdkit-filter.pod b/docs/nbdkit-filter.pod index e801965d..0b120efe 100644 --- a/docs/nbdkit-filter.pod +++ b/docs/nbdkit-filter.pod @@ -132,7 +132,7 @@ C<nbdkit_next_after_fork>, C<nbdkit_next_preconnect>, C<nbdkit_next_list_exports>, C<nbdkit_next_default_export>, C<nbdkit_next_open>) and a structure called C<struct nbdkit_next_ops>. These abstract the next plugin or filter in the chain. There is also -an opaque pointer C<backend> or C<nxdata> which must be passed along +an opaque pointer C<context> or C<nxdata> which must be passed along when calling these functions. The value of C<nxdata> passed to C<.prepare> has a stable lifetime that lasts to the corresponding C<.finalize>, with all intermediate functions (such as C<.pread>) @@ -141,7 +141,7 @@ is not reused are C<.config>, C<.config_complete>, C<.get_ready>, and C<.after_fork>, which are called during initialization outside any connections, and C<.preconnect>, C<.list_exports>, C<.default_export>, and C<.open> which are called based on client connections but prior to -the stable lifetime of C<.prepare>. The value of C<backend> passed to +the stable lifetime of C<.prepare>. The value of C<context> passed to C<.open> has a lifetime that lasts until the matching C<.close> for use by C<nbdkit_backend_reopen>. @@ -429,7 +429,7 @@ C<next> because it cannot be altered. =head2 C<.open> - void * (*open) (nbdkit_next_open *next, nbdkit_backend *backend, + void * (*open) (nbdkit_next_open *next, nbdkit_context *context, int readonly, const char *exportname, int is_tls); This is called when a new client connection is opened and can be used @@ -471,7 +471,7 @@ outer filter to the plugin will be in reverse. Skipping a call to C<next> is acceptable if the filter will not access C<next_ops> during any of the remaining callbacks reached on the same connection. -The value of C<backend> in this call has a lifetime that lasts until +The value of C<context> in this call has a lifetime that lasts until the counterpart C<.close>, and it is this value (and not the distinct C<nxdata> of C<.pread> and friends) that must be passed as the first parameter to C<nbdkit_backend_reopen> by a filter attempting to retry @@ -481,14 +481,14 @@ a connection into the backend. Filters have access to a function for reopening the backend: - int (nbdkit_backend *backend, int readonly, const char *exportname, + int (nbdkit_context *context, int readonly, const char *exportname, void **nxdata); This function is used by L<nbdkit-retry-filter(1)> to close and reopen the underlying plugin, with possible changes to the C<readonly> and C<exportname> parameters in relation to the original opening. It should be used with caution because it is difficult to use safely. -The C<backend> parameter to this function should be the C<backend> +The C<context> parameter to this function should be the C<context> parameter originally passed in to C<.open>; while the C<nxdata> pointer should be the address of C<nxdata> from any function with a C<next_ops> parameter (such as C<.pread>) that wants to call into the diff --git a/include/nbdkit-filter.h b/include/nbdkit-filter.h index b47e78c3..3f3f61cd 100644 --- a/include/nbdkit-filter.h +++ b/include/nbdkit-filter.h @@ -54,12 +54,15 @@ extern "C" { * the next filter or plugin. */ typedef struct backend nbdkit_backend; +typedef struct context nbdkit_context; typedef struct context nbdkit_next; #elif defined NBDKIT_RETRY_FILTER /* Hack to expose reopen to retry filter */ typedef struct nbdkit_backend nbdkit_backend; +typedef struct nbdkit_context nbdkit_context; typedef struct nbdkit_next_ops nbdkit_next; #else typedef void nbdkit_backend; +typedef void nbdkit_context; typedef void nbdkit_next; #endif @@ -74,7 +77,7 @@ typedef int nbdkit_next_list_exports (nbdkit_backend *nxdata, int readonly, struct nbdkit_exports *exports); typedef const char *nbdkit_next_default_export (nbdkit_backend *nxdata, int readonly); -typedef int nbdkit_next_open (nbdkit_backend *backend, +typedef int nbdkit_next_open (nbdkit_context *context, int readonly, const char *exportname); struct nbdkit_next_ops { @@ -155,7 +158,7 @@ NBDKIT_EXTERN_DECL (const struct nbdkit_export, nbdkit_get_export, * Used by the retry filter. */ NBDKIT_EXTERN_DECL (int, nbdkit_backend_reopen, - (nbdkit_backend *backend, int readonly, + (nbdkit_context *context, int readonly, const char *exportname, nbdkit_next **nxdata)); #endif @@ -199,7 +202,7 @@ struct nbdkit_filter { nbdkit_backend *nxdata, int readonly, int is_tls); - void * (*open) (nbdkit_next_open *next, nbdkit_backend *backend, + void * (*open) (nbdkit_next_open *next, nbdkit_context *context, int readonly, const char *exportname, int is_tls); void (*close) (void *handle); diff --git a/server/internal.h b/server/internal.h index 23639bcd..b944e56d 100644 --- a/server/internal.h +++ b/server/internal.h @@ -207,6 +207,7 @@ struct context { void *handle; /* Plugin or filter handle. */ struct backend *b; /* Backend that provided handle. */ + struct context *c_next; /* Underlying context, only when b->next != NULL. */ unsigned char state; /* Bitmask of HANDLE_* values */ @@ -235,7 +236,7 @@ struct connection { void *crypto_session; int nworkers; - struct context **contexts; /* One per plugin and filter. */ + struct context *top_context; /* The context tied to 'top'. */ char **default_exportname; /* One per plugin and filter. */ uint32_t cflags; @@ -255,11 +256,6 @@ struct connection { connection_close_function close; }; -extern struct context *get_context (struct connection *conn, struct backend *b) - __attribute__((__nonnull__(1))); -extern void set_context (struct connection *conn, struct backend *b, - struct context *c) - __attribute__((__nonnull__(1))); extern void handle_single_connection (int sockin, int sockout); extern int connection_get_status (void); extern int connection_set_status (int value); @@ -366,7 +362,7 @@ struct backend { int (*list_exports) (struct backend *, int readonly, int is_tls, struct nbdkit_exports *exports); const char *(*default_export) (struct backend *, int readonly, int is_tls); - void *(*open) (struct backend *, int readonly, const char *exportname, + void *(*open) (struct context *, int readonly, const char *exportname, int is_tls); int (*prepare) (struct context *, int readonly); int (*finalize) (struct context *); @@ -434,7 +430,7 @@ extern bool backend_valid_range (struct context *c, uint64_t offset, uint32_t count) __attribute__((__nonnull__ (1))); -extern int backend_reopen (struct backend *b, +extern int backend_reopen (struct context *c, int readonly, const char *exportname) __attribute__((__nonnull__ (1, 3))); extern const char *backend_export_description (struct context *c) diff --git a/server/backend.c b/server/backend.c index 58d10a3f..1c78556f 100644 --- a/server/backend.c +++ b/server/backend.c @@ -163,13 +163,12 @@ backend_list_exports (struct backend *b, int readonly, struct nbdkit_exports *exports) { GET_CONN; - struct context *c = get_context (conn, b); size_t count; controlpath_debug ("%s: list_exports readonly=%d tls=%d", b->name, readonly, conn->using_tls); - assert (c == NULL); + assert (conn->top_context == NULL); if (b->list_exports (b, readonly, conn->using_tls, exports) == -1 || exports_resolve_default (exports, b, readonly) == -1) { @@ -186,14 +185,13 @@ const char * backend_default_export (struct backend *b, int readonly) { GET_CONN; - struct context *c = get_context (conn, b); const char *s; controlpath_debug ("%s: default_export readonly=%d tls=%d", b->name, readonly, conn->using_tls); if (conn->default_exportname[b->i] == NULL) { - assert (c == NULL); + assert (conn->top_context == NULL); s = b->default_export (b, readonly, conn->using_tls); /* Ignore over-length strings. XXX Also ignore non-UTF8? */ if (s && strnlen (s, NBD_MAX_STRING + 1) > NBD_MAX_STRING) { @@ -247,10 +245,10 @@ backend_open (struct backend *b, int readonly, const char *exportname) controlpath_debug ("%s: open readonly=%d exportname=\"%s\" tls=%d", b->name, readonly, exportname, conn->using_tls); - assert (conn->contexts[b->i] == NULL); c->next = next_ops; c->handle = NULL; c->b = b; + c->c_next = NULL; c->state = 0; c->exportsize = -1; c->can_write = readonly ? 0 : -1; @@ -277,15 +275,12 @@ backend_open (struct backend *b, int readonly, const char *exportname) /* Most filters will call next_open first, resulting in * inner-to-outer ordering. */ - c->handle = b->open (b, readonly, exportname, conn->using_tls); + c->handle = b->open (c, readonly, exportname, conn->using_tls); controlpath_debug ("%s: open returned handle %p", b->name, c->handle); if (c->handle == NULL) { - if (b->i) { /* Do not strand backend if this layer failed */ - struct context *c2 = get_context (conn, b->next); - if (c2 != NULL) - backend_close (c2); - } + if (b->i && c->c_next != NULL) + backend_close (c->c_next); free (c); return NULL; } @@ -297,7 +292,6 @@ backend_open (struct backend *b, int readonly, const char *exportname) int backend_prepare (struct context *c) { - GET_CONN; struct backend *b = c->b; assert (c->handle); @@ -307,11 +301,8 @@ backend_prepare (struct context *c) * plugin, similar to typical .open order. But remember that * a filter may skip opening its backend. */ - if (b->i) { - struct context *c2 = get_context (conn, b->next); - if (c2 != NULL && backend_prepare (c2) == -1) - return -1; - } + if (b->i && c->c_next != NULL && backend_prepare (c->c_next) == -1) + return -1; controlpath_debug ("%s: prepare readonly=%d", b->name, c->can_write == 0); @@ -324,7 +315,6 @@ backend_prepare (struct context *c) int backend_finalize (struct context *c) { - GET_CONN; struct backend *b = c->b; /* Call these in reverse order to .prepare above, starting from the @@ -344,19 +334,16 @@ backend_finalize (struct context *c) } } - if (b->i) { - struct context *c2 = get_context (conn, b->next); - if (c2 != NULL) - return backend_finalize (c2); - } + if (b->i && c->c_next != NULL) + return backend_finalize (c->c_next); return 0; } void backend_close (struct context *c) { - GET_CONN; struct backend *b = c->b; + struct context *c_next = c->c_next; /* outer-to-inner order, opposite .open */ assert (c->handle); @@ -364,12 +351,8 @@ backend_close (struct context *c) controlpath_debug ("%s: close", b->name); b->close (c); free (c); - set_context (conn, b, NULL); - if (b->i) { - struct context *c2 = get_context (conn, b->next); - if (c2 != NULL) - backend_close (c2); - } + if (c_next != NULL) + backend_close (c_next); } bool @@ -383,27 +366,26 @@ backend_valid_range (struct context *c, uint64_t offset, uint32_t count) /* Core functionality of nbdkit_backend_reopen for retry filter */ int -backend_reopen (struct backend *b, int readonly, const char *exportname) +backend_reopen (struct context *c, int readonly, const char *exportname) { - GET_CONN; - struct context *c; + struct backend *b = c->b; controlpath_debug ("%s: reopen readonly=%d exportname=\"%s\"", - b->name, readonly, exportname); + b->next->name, readonly, exportname); - c = get_context (conn, b); - if (c) { - if (backend_finalize (c) == -1) + if (c->c_next) { + if (backend_finalize (c->c_next) == -1) return -1; - backend_close (c); + backend_close (c->c_next); + c->c_next = NULL; } - c = backend_open (b, readonly, exportname); - if (c == NULL) + c->c_next = backend_open (b->next, readonly, exportname); + if (c->c_next == NULL) return -1; - set_context (conn, b, c); - if (backend_prepare (c) == -1) { - backend_finalize (c); - backend_close (c); + if (backend_prepare (c->c_next) == -1) { + backend_finalize (c->c_next); + backend_close (c->c_next); + c->c_next = NULL; return -1; } return 0; diff --git a/server/connections.c b/server/connections.c index 930491a6..aca4b24b 100644 --- a/server/connections.c +++ b/server/connections.c @@ -224,7 +224,7 @@ handle_single_connection (int sockin, int sockout) /* Finalize (for filters), called just before close. */ lock_request (); - r = backend_finalize (get_context (conn, top)); + r = backend_finalize (conn->top_context); unlock_request (); if (r == -1) goto done; @@ -253,16 +253,10 @@ new_connection (int sockin, int sockout, int nworkers) pthread_mutex_init (&conn->write_lock, NULL); pthread_mutex_init (&conn->status_lock, NULL); - conn->contexts = calloc (top->i + 1, sizeof *conn->contexts); - if (conn->contexts == NULL) { - perror ("malloc"); - goto error1; - } conn->default_exportname = calloc (top->i + 1, sizeof *conn->default_exportname); if (conn->default_exportname == NULL) { perror ("malloc"); - free (conn->contexts); goto error1; } @@ -332,7 +326,6 @@ new_connection (int sockin, int sockout, int nworkers) close (conn->status_pipe[0]); if (conn->status_pipe[1] >= 0) close (conn->status_pipe[1]); - free (conn->contexts); free (conn->default_exportname); error1: @@ -348,7 +341,6 @@ static void free_connection (struct connection *conn) { struct backend *b; - struct context *c; if (!conn) return; @@ -361,9 +353,10 @@ free_connection (struct connection *conn) */ if (!quit) { lock_request (); - c = get_context (conn, top); - if (c) - backend_close (c); + if (conn->top_context) { + backend_close (conn->top_context); + conn->top_context = NULL; + } unlock_request (); } @@ -383,7 +376,6 @@ free_connection (struct connection *conn) for_each_backend (b) free (conn->default_exportname[b->i]); free (conn->default_exportname); - free (conn->contexts); free (conn); threadlocal_set_conn (NULL); @@ -501,18 +493,3 @@ raw_close (void) if (conn->sockout >= 0 && conn->sockin != conn->sockout) closesocket (conn->sockout); } - -struct context * -get_context (struct connection *conn, struct backend *b) -{ - struct context *c = conn->contexts[b->i]; - assert (!c || c->b == b); - return c; -} - -void -set_context (struct connection *conn, struct backend *b, struct context *c) -{ - assert (!c || c->b == b); - conn->contexts[b->i] = c; -} diff --git a/server/filters.c b/server/filters.c index a200d61b..228e2610 100644 --- a/server/filters.c +++ b/server/filters.c @@ -261,21 +261,22 @@ filter_default_export (struct backend *b, int readonly, int is_tls) } static int -next_open (struct backend *b, int readonly, const char *exportname) +next_open (struct context *c, int readonly, const char *exportname) { - GET_CONN; - struct context *c = backend_open (b, readonly, exportname); + struct backend *b = c->b; + struct context *c_next = backend_open (b->next, readonly, exportname); - if (c == NULL) + if (c_next == NULL) return -1; - set_context (conn, b, c); + c->c_next = c_next; return 0; } static void * -filter_open (struct backend *b, int readonly, const char *exportname, +filter_open (struct context *c, int readonly, const char *exportname, int is_tls) { + struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); void *handle; @@ -283,9 +284,9 @@ filter_open (struct backend *b, int readonly, const char *exportname, * inner-to-outer ordering. */ if (f->filter.open) - handle = f->filter.open (next_open, b->next, readonly, exportname, + handle = f->filter.open (next_open, c, readonly, exportname, is_tls); - else if (next_open (b->next, readonly, exportname) == -1) + else if (next_open (c, readonly, exportname) == -1) handle = NULL; else handle = NBDKIT_HANDLE_NOT_NEEDED; @@ -306,10 +307,9 @@ filter_close (struct context *c) static int filter_prepare (struct context *c, int readonly) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.prepare && f->filter.prepare (&c_next->next, c_next, c->handle, readonly) == -1) @@ -321,10 +321,9 @@ filter_prepare (struct context *c, int readonly) static int filter_finalize (struct context *c) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.finalize && f->filter.finalize (&c_next->next, c_next, c->handle) == -1) @@ -335,10 +334,9 @@ filter_finalize (struct context *c) static const char * filter_export_description (struct context *c) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.export_description) return f->filter.export_description (&c_next->next, c_next, c->handle); @@ -349,10 +347,9 @@ filter_export_description (struct context *c) static int64_t filter_get_size (struct context *c) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.get_size) return f->filter.get_size (&c_next->next, c_next, c->handle); @@ -363,10 +360,9 @@ filter_get_size (struct context *c) static int filter_can_write (struct context *c) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.can_write) return f->filter.can_write (&c_next->next, c_next, c->handle); @@ -377,10 +373,9 @@ filter_can_write (struct context *c) static int filter_can_flush (struct context *c) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.can_flush) return f->filter.can_flush (&c_next->next, c_next, c->handle); @@ -391,10 +386,9 @@ filter_can_flush (struct context *c) static int filter_is_rotational (struct context *c) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.is_rotational) return f->filter.is_rotational (&c_next->next, c_next, c->handle); @@ -405,10 +399,9 @@ filter_is_rotational (struct context *c) static int filter_can_trim (struct context *c) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.can_trim) return f->filter.can_trim (&c_next->next, c_next, c->handle); @@ -419,10 +412,9 @@ filter_can_trim (struct context *c) static int filter_can_zero (struct context *c) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.can_zero) return f->filter.can_zero (&c_next->next, c_next, c->handle); @@ -433,10 +425,9 @@ filter_can_zero (struct context *c) static int filter_can_fast_zero (struct context *c) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.can_fast_zero) return f->filter.can_fast_zero (&c_next->next, c_next, c->handle); @@ -447,10 +438,9 @@ filter_can_fast_zero (struct context *c) static int filter_can_extents (struct context *c) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.can_extents) return f->filter.can_extents (&c_next->next, c_next, c->handle); @@ -461,10 +451,9 @@ filter_can_extents (struct context *c) static int filter_can_fua (struct context *c) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.can_fua) return f->filter.can_fua (&c_next->next, c_next, c->handle); @@ -475,10 +464,9 @@ filter_can_fua (struct context *c) static int filter_can_multi_conn (struct context *c) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.can_multi_conn) return f->filter.can_multi_conn (&c_next->next, c_next, c->handle); @@ -489,10 +477,9 @@ filter_can_multi_conn (struct context *c) static int filter_can_cache (struct context *c) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.can_cache) return f->filter.can_cache (&c_next->next, c_next, c->handle); @@ -505,10 +492,9 @@ filter_pread (struct context *c, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.pread) return f->filter.pread (&c_next->next, c_next, c->handle, @@ -522,10 +508,9 @@ filter_pwrite (struct context *c, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.pwrite) return f->filter.pwrite (&c_next->next, c_next, c->handle, @@ -538,10 +523,9 @@ static int filter_flush (struct context *c, uint32_t flags, int *err) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.flush) return f->filter.flush (&c_next->next, c_next, c->handle, flags, err); @@ -554,10 +538,9 @@ filter_trim (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, int *err) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.trim) return f->filter.trim (&c_next->next, c_next, c->handle, count, offset, @@ -570,10 +553,9 @@ static int filter_zero (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, int *err) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.zero) return f->filter.zero (&c_next->next, c_next, c->handle, @@ -587,10 +569,9 @@ filter_extents (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.extents) return f->filter.extents (&c_next->next, c_next, c->handle, @@ -606,10 +587,9 @@ filter_cache (struct context *c, uint32_t count, uint64_t offset, uint32_t flags, int *err) { - GET_CONN; struct backend *b = c->b; struct backend_filter *f = container_of (b, struct backend_filter, backend); - struct context *c_next = get_context (conn, b->next); + struct context *c_next = c->c_next; if (f->filter.cache) return f->filter.cache (&c_next->next, c_next, c->handle, @@ -715,12 +695,11 @@ filter_register (struct backend *next, size_t index, const char *filename, } int -nbdkit_backend_reopen (struct backend *b, int readonly, +nbdkit_backend_reopen (struct context *c, int readonly, const char *exportname, struct context **nxdata) { - GET_CONN; - int r = backend_reopen (b, readonly, exportname); + int r = backend_reopen (c, readonly, exportname); - *nxdata = get_context (conn, b); + *nxdata = c->c_next; return r; } diff --git a/server/plugins.c b/server/plugins.c index 9144cdae..b5cb5971 100644 --- a/server/plugins.c +++ b/server/plugins.c @@ -310,10 +310,11 @@ plugin_default_export (struct backend *b, int readonly, int is_tls) } static void * -plugin_open (struct backend *b, int readonly, const char *exportname, +plugin_open (struct context *c, int readonly, const char *exportname, int is_tls) { GET_CONN; + struct backend *b = c->b; struct backend_plugin *p = container_of (b, struct backend_plugin, backend); void *r; diff --git a/server/protocol-handshake-newstyle.c b/server/protocol-handshake-newstyle.c index cfcd090d..a2c89c9a 100644 --- a/server/protocol-handshake-newstyle.c +++ b/server/protocol-handshake-newstyle.c @@ -341,7 +341,6 @@ negotiate_handshake_newstyle_options (void) const char *optname; uint64_t exportsize; struct backend *b; - struct context *c; for (nr_options = MAX_NR_OPTIONS; nr_options > 0; --nr_options) { CLEANUP_FREE char *data = NULL; @@ -568,11 +567,11 @@ negotiate_handshake_newstyle_options (void) */ if (finish_newstyle_options (&exportsize, &data[4], exportnamelen) == -1) { - c = get_context (conn, top); - if (c) { - if (backend_finalize (c) == -1) + if (conn->top_context) { + if (backend_finalize (conn->top_context) == -1) return -1; - backend_close (c); + backend_close (conn->top_context); + conn->top_context = NULL; } if (send_newstyle_option_reply (option, NBD_REP_ERR_UNKNOWN) == -1) return -1; @@ -590,7 +589,6 @@ negotiate_handshake_newstyle_options (void) * NBD_INFO_EXPORT if it was requested, because we replied * already above). */ - c = get_context (conn, top); for (i = 0; i < nrinfos; ++i) { memcpy (&info, &data[4 + exportnamelen + 2 + i*2], 2); info = be16toh (info); @@ -619,7 +617,7 @@ negotiate_handshake_newstyle_options (void) break; case NBD_INFO_DESCRIPTION: { - const char *desc = backend_export_description (c); + const char *desc = backend_export_description (conn->top_context); if (!desc) { debug ("newstyle negotiation: %s: " @@ -650,9 +648,10 @@ negotiate_handshake_newstyle_options (void) return -1; if (option == NBD_OPT_INFO) { - if (backend_finalize (c) == -1) + if (backend_finalize (conn->top_context) == -1) return -1; - backend_close (c); + backend_close (conn->top_context); + conn->top_context = NULL; } break; diff --git a/server/protocol-handshake.c b/server/protocol-handshake.c index 61521d43..e0183173 100644 --- a/server/protocol-handshake.c +++ b/server/protocol-handshake.c @@ -79,18 +79,16 @@ protocol_common_open (uint64_t *exportsize, uint16_t *flags, int64_t size; uint16_t eflags = NBD_FLAG_HAS_FLAGS; int fl; - struct context *c; - c = backend_open (top, read_only, exportname); - if (c == NULL) + conn->top_context = backend_open (top, read_only, exportname); + if (conn->top_context == NULL) return -1; - set_context (conn, top, c); /* Prepare (for filters), called just after open. */ - if (backend_prepare (c) == -1) + if (backend_prepare (conn->top_context) == -1) return -1; - size = backend_get_size (c); + size = backend_get_size (conn->top_context); if (size == -1) return -1; if (size < 0) { @@ -102,56 +100,56 @@ protocol_common_open (uint64_t *exportsize, uint16_t *flags, /* Check all flags even if they won't be advertised, to prime the * cache and make later request validation easier. */ - fl = backend_can_write (c); + fl = backend_can_write (conn->top_context); if (fl == -1) return -1; if (!fl) eflags |= NBD_FLAG_READ_ONLY; - fl = backend_can_zero (c); + fl = backend_can_zero (conn->top_context); if (fl == -1) return -1; if (fl) eflags |= NBD_FLAG_SEND_WRITE_ZEROES; - fl = backend_can_fast_zero (c); + fl = backend_can_fast_zero (conn->top_context); if (fl == -1) return -1; if (fl) eflags |= NBD_FLAG_SEND_FAST_ZERO; - fl = backend_can_trim (c); + fl = backend_can_trim (conn->top_context); if (fl == -1) return -1; if (fl) eflags |= NBD_FLAG_SEND_TRIM; - fl = backend_can_fua (c); + fl = backend_can_fua (conn->top_context); if (fl == -1) return -1; if (fl) eflags |= NBD_FLAG_SEND_FUA; - fl = backend_can_flush (c); + fl = backend_can_flush (conn->top_context); if (fl == -1) return -1; if (fl) eflags |= NBD_FLAG_SEND_FLUSH; - fl = backend_is_rotational (c); + fl = backend_is_rotational (conn->top_context); if (fl == -1) return -1; if (fl) eflags |= NBD_FLAG_ROTATIONAL; /* multi-conn is useless if parallel connections are not allowed. */ - fl = backend_can_multi_conn (c); + fl = backend_can_multi_conn (conn->top_context); if (fl == -1) return -1; if (fl && (thread_model > NBDKIT_THREAD_MODEL_SERIALIZE_CONNECTIONS)) eflags |= NBD_FLAG_CAN_MULTI_CONN; - fl = backend_can_cache (c); + fl = backend_can_cache (conn->top_context); if (fl == -1) return -1; if (fl) @@ -162,7 +160,7 @@ protocol_common_open (uint64_t *exportsize, uint16_t *flags, * not have to worry about errors, and makes test-layers easier to * write. */ - fl = backend_can_extents (c); + fl = backend_can_extents (conn->top_context); if (fl == -1) return -1; diff --git a/server/protocol.c b/server/protocol.c index fedc701a..2ac77055 100644 --- a/server/protocol.c +++ b/server/protocol.c @@ -53,7 +53,6 @@ validate_request (uint16_t cmd, uint16_t flags, uint64_t offset, uint32_t count, uint32_t *error) { GET_CONN; - struct context *c = get_context (conn, top); /* Readonly connection? */ if (conn->eflags & NBD_FLAG_READ_ONLY && @@ -73,7 +72,7 @@ validate_request (uint16_t cmd, uint16_t flags, uint64_t offset, uint32_t count, case NBD_CMD_TRIM: case NBD_CMD_WRITE_ZEROES: case NBD_CMD_BLOCK_STATUS: - if (!backend_valid_range (c, offset, count)) { + if (!backend_valid_range (conn->top_context, offset, count)) { /* XXX Allow writes to extend the disk? */ nbdkit_error ("invalid request: %s: offset and count are out of range: " "offset=%" PRIu64 " count=%" PRIu32, @@ -231,7 +230,7 @@ handle_request (uint16_t cmd, uint16_t flags, uint64_t offset, uint32_t count, void *buf, struct nbdkit_extents *extents) { GET_CONN; - struct context *c = get_context (conn, top); + struct context *c = conn->top_context; uint32_t f = 0; int err = 0; @@ -686,8 +685,8 @@ protocol_recv_request_send_reply (void) /* Allocate the extents list for block status only. */ if (cmd == NBD_CMD_BLOCK_STATUS) { - struct context *c = get_context (conn, top); - extents = nbdkit_extents_new (offset, backend_get_size (c)); + extents = nbdkit_extents_new (offset, + backend_get_size (conn->top_context)); if (extents == NULL) { error = ENOMEM; goto send_reply; diff --git a/filters/checkwrite/checkwrite.c b/filters/checkwrite/checkwrite.c index bbd7f1cd..2dc93ab1 100644 --- a/filters/checkwrite/checkwrite.c +++ b/filters/checkwrite/checkwrite.c @@ -44,7 +44,7 @@ #include "minmax.h" static void * -checkwrite_open (nbdkit_next_open *next, nbdkit_backend *nxdata, +checkwrite_open (nbdkit_next_open *next, nbdkit_context *nxdata, int readonly, const char *exportname, int is_tls) { /* Ignore readonly flag passed in, open the plugin readonly. */ diff --git a/filters/exitlast/exitlast.c b/filters/exitlast/exitlast.c index 4c879cc9..12571242 100644 --- a/filters/exitlast/exitlast.c +++ b/filters/exitlast/exitlast.c @@ -50,7 +50,7 @@ static _Atomic unsigned connections; static void * -exitlast_open (nbdkit_next_open *next, nbdkit_backend *nxdata, +exitlast_open (nbdkit_next_open *next, nbdkit_context *nxdata, int readonly, const char *exportname, int is_tls) { if (next (nxdata, readonly, exportname) == -1) diff --git a/filters/exitwhen/exitwhen.c b/filters/exitwhen/exitwhen.c index ca199a8c..67e87dde 100644 --- a/filters/exitwhen/exitwhen.c +++ b/filters/exitwhen/exitwhen.c @@ -482,7 +482,7 @@ exitwhen_preconnect (nbdkit_next_preconnect *next, void *nxdata, int readonly) } static void * -exitwhen_open (nbdkit_next_open *next, nbdkit_backend *nxdata, +exitwhen_open (nbdkit_next_open *next, nbdkit_context *nxdata, int readonly, const char *exportname, int is_tls) { if (next (nxdata, readonly, exportname) == -1) diff --git a/filters/gzip/gzip.c b/filters/gzip/gzip.c index 03e023e5..0b3f48b7 100644 --- a/filters/gzip/gzip.c +++ b/filters/gzip/gzip.c @@ -75,7 +75,7 @@ gzip_thread_model (void) } static void * -gzip_open (nbdkit_next_open *next, nbdkit_backend *nxdata, +gzip_open (nbdkit_next_open *next, nbdkit_context *nxdata, int readonly, const char *exportname, int is_tls) { /* Always pass readonly=1 to the underlying plugin. */ diff --git a/filters/limit/limit.c b/filters/limit/limit.c index fb862df7..dc07f436 100644 --- a/filters/limit/limit.c +++ b/filters/limit/limit.c @@ -90,7 +90,7 @@ limit_preconnect (nbdkit_next_preconnect *next, nbdkit_backend *nxdata, } static void * -limit_open (nbdkit_next_open *next, nbdkit_backend *nxdata, +limit_open (nbdkit_next_open *next, nbdkit_context *nxdata, int readonly, const char *exportname, int is_tls) { if (next (nxdata, readonly, exportname) == -1) diff --git a/filters/retry/retry.c b/filters/retry/retry.c index a2b5dc66..cfaea7d4 100644 --- a/filters/retry/retry.c +++ b/filters/retry/retry.c @@ -109,13 +109,13 @@ retry_config (nbdkit_next_config *next, nbdkit_backend *nxdata, struct retry_handle { int readonly; /* Save original readonly setting. */ char *exportname; /* Client exportname. */ - nbdkit_backend *backend; /* Backend learned during .open. */ + nbdkit_context *backend; /* Backend learned during .open. */ unsigned reopens; bool open; }; static void * -retry_open (nbdkit_next_open *next, nbdkit_backend *nxdata, +retry_open (nbdkit_next_open *next, nbdkit_context *nxdata, int readonly, const char *exportname, int is_tls) { struct retry_handle *h; diff --git a/filters/tar/tar.c b/filters/tar/tar.c index fa4b61dc..7cf2cd26 100644 --- a/filters/tar/tar.c +++ b/filters/tar/tar.c @@ -112,7 +112,7 @@ struct handle { }; static void * -tar_open (nbdkit_next_open *next, nbdkit_backend *nxdata, +tar_open (nbdkit_next_open *next, nbdkit_context *nxdata, int readonly, const char *exportname, int is_tls) { struct handle *h; -- 2.30.1
Eric Blake
2021-Mar-05 23:31 UTC
[Libguestfs] [nbdkit PATCH v3 12/16] filters: New API for plugin context management
As promised in an earlier patch, get rid of the temporary nbdkit_backend_reopen, and replace it with the finer-grained combination of nbdkit_context_get_backend, nbdkit_context_next_open, nbdkit_context_next_close, and nbdkit_context_set_next. Update the retry filter to use the new API. Change the (temporary) preprocessor guard from NBDKIT_RETRY_FILTER to NBDKIT_TYPESAFE (will be dropped later once more filters are converted). Drop the now-unused backend_reopen() function. Expose .prepare and .finalize callbacks into struct nbdkit_next_ops for use during manual context manipulation. With this in place, it is now possible for a filter to open more than one context into the backend from a single connection (shown here in the retry filter), and conversely to share a single backend context across multiple connections (an upcoming patch will demonstrate this in the ext2 filter, although TODO mentions a few more steps we need to get there). --- docs/nbdkit-filter.pod | 207 ++++++++++++++++++++++++++++------------ include/nbdkit-filter.h | 27 ++++-- server/internal.h | 3 - server/backend.c | 30 +----- server/filters.c | 43 +++++++-- server/nbdkit.syms | 11 ++- filters/retry/retry.c | 42 ++++++-- TODO | 36 +++---- 8 files changed, 260 insertions(+), 139 deletions(-) diff --git a/docs/nbdkit-filter.pod b/docs/nbdkit-filter.pod index 0b120efe..d13ac1d7 100644 --- a/docs/nbdkit-filter.pod +++ b/docs/nbdkit-filter.pod @@ -132,25 +132,33 @@ C<nbdkit_next_after_fork>, C<nbdkit_next_preconnect>, C<nbdkit_next_list_exports>, C<nbdkit_next_default_export>, C<nbdkit_next_open>) and a structure called C<struct nbdkit_next_ops>. These abstract the next plugin or filter in the chain. There is also -an opaque pointer C<context> or C<nxdata> which must be passed along -when calling these functions. The value of C<nxdata> passed to -C<.prepare> has a stable lifetime that lasts to the corresponding -C<.finalize>, with all intermediate functions (such as C<.pread>) -receiving the same value for convenience. Functions where C<nxdata> -is not reused are C<.config>, C<.config_complete>, C<.get_ready>, and -C<.after_fork>, which are called during initialization outside any -connections, and C<.preconnect>, C<.list_exports>, C<.default_export>, -and C<.open> which are called based on client connections but prior to -the stable lifetime of C<.prepare>. The value of C<context> passed to -C<.open> has a lifetime that lasts until the matching C<.close> for -use by C<nbdkit_backend_reopen>. +an opaque pointer C<backend>, C<context> or C<nxdata> which must be +passed along when calling these functions. The value of C<backend> is +stable between C<.after_fork>, C<.preconnect>, C<.list_exports>, and +C<.default_export>, and can also be obtained by using +C<nbdkit_context_get_backend> on the C<context> parameter to C<.open>. + +Meanwhile, if the filter does not use C<nbdkit_context_set_next>, the +value of C<nxdata> passed to C<.prepare> has a stable lifetime that +lasts to the corresponding C<.finalize>, with all intermediate +functions (such as C<.pread>) receiving the same value for +convenience. Functions where C<nxdata> is not reused are C<.config>, +C<.config_complete>, C<.get_ready>, and C<.after_fork>, which are +called during initialization outside any connections, and +C<.preconnect>, C<.list_exports>, C<.default_export>, and C<.open> +which are called based on client connections but prior to the stable +lifetime of C<.prepare>. The value of C<context> passed to C<.open> +has a lifetime that lasts until the matching C<.close> for use by +C<nbdkit_context_get_backend>. =head2 Next config, open and close The filter?s C<.config>, C<.config_complete>, C<.get_ready>, -C<.after_fork> and C<.open> methods may only call the next C<.config>, -C<.config_complete>, C<.get_ready>, C<.after_fork> and C<.open> method -in the chain (optionally for C<.config>). +C<.after_fork>, C<.preconnect>, C<.list_exports>, C<.default_export> +and C<.open> methods may only call the next C<.config>, +C<.config_complete>, C<.get_ready>, C<.after_fork>, C<.preconnect>, +C<.list_exports>, C<.default_export> and C<.open> method in the chain +(optionally for C<.config> and C<.open>). The filter?s C<.close> method is called when an old connection closed, and this has no C<next> parameter because it cannot be @@ -158,15 +166,98 @@ short-circuited. =head2 C<next_ops> -The filter?s other methods like C<.prepare>, C<.get_size>, C<.pread> -etc ? always called in the context of a connection ? are passed a -pointer to C<struct nbdkit_next_ops> which contains a comparable set -of accessors to plugin methods that can be called during a connection. -The C<next_ops> parameter is stable between C<.prepare> and -C<.finalize>; intermediate functions (such as C<.pread>) receive the -same value for convenience. - -It is possible for a filter to issue (for example) extra +The filter generally needs to call into the underlying plugin, which +is done via a pointer to C<struct nbdkit_next_ops>. The most common +behavior is to create a next context per connection by calling the +C<next_open> parameter during C<.open>, at which point the next +context will be automatically provided to the filter?s other methods +like C<.prepare>, C<.get_size>, C<.pread> etc. The C<next_ops> struct +contains a comparable set of accessors to plugin methods that can be +called during a connection. When using automatic registration, the +C<next_ops> parameter is stable between C<.prepare> and C<.finalize>, +and nbdkit automatically prepares, finalizes, and closes the next +context at the right point in the filter connection lifecycle. + +Alternatively, the filter can manage plugin contexts manually, whether +to multiplex multiple client connections through a single context into +the plugin, or to open multiple plugin contexts to perform retries or +otherwise service a single client connection more efficiently. In +this mode of operation, the filter uses C<nbdkit_next_context_open> to +open a plugin context using the C<backend> parameter passed to +C<.after_fork>, C<.preconnect>, C<.list_exports>, C<.default_export>, +or obtained from using C<nbdkit_context_get_backend> on the C<context> +parameter to C<.open>. The resulting next context has a lifecycle +under manual control, where the filter must use C<next-E<gt>prepare +(next)> before using any other function pointers within the next +context, and must reclaim the memory using C<next-E<gt>finalize +(next)> and C<nbdkit_next_context_close> when done. A filter using +manual lifecycle management may use C<nbdkit_context_set_next> to +associate the next context into the current connection, which lets +nbdkit then pass that context as the C<next_ops> parameter to future +connection-related functions like C<.pread> and take over lifecycle +responsibility. + +=head3 C<nbdkit_context_get_backend> + +=head3 C<nbdkit_next_context_open> + +=head3 C<nbdkit_next_context_close> + +=head3 C<nbdkit_context_set_next> + + nbdkit_backend *nbdkit_context_get_backend (nbdkit_context *context); + +Obtains the backend pointer from the C<context> parameter to C<.open>, +matching the backend pointer available to C<.after_fork>, +C<.preconnect>, C<.list_exports>, and C<.default_export>. This +backend pointer has a stable lifetime from the time of C<.after_fork> +until C<.unload>. + + nbdkit_next *nbdkit_next_context_open (nbdkit_backend *backend, + int readonly, const char *exportname); + +This function attempts to open a new context into the plugin in +relation to the filter's current C<backend>. The C<readonly> and +C<exportname> parameters behave the same as documented in C<.open>. +The resulting context will be under the filter's manual lifecycle +control unless the filter associates it into the connection with +C<nbdkit_context_set_next>. The filter should be careful to not +violate any threading model restrictions of the plugin if it opens +more than one context. + + void nbdkit_next_context_close (nbdkit_next *next); + +This function closes a context into the plugin. If the context has +previously been prepared, it should first be finalized before using +this function. This function does not need to be called for a plugin +context that has been associated with the filter connection via +C<nbdkit_context_set_next> prior to the C<.close> callback. + + nbdkit_next *nbdkit_context_set_next (nbdkit_context *context, + nbdkit_next *next); + +This function associates a plugin context with the filter's current +connection context, given by the C<context> parameter to C<.open>. +Once associated, this plugin context will be given as the C<next_ops> +parameter to all other connection-specific callbacks. If associated +during C<.open>, nbdkit will take care of preparing the context prior +to C<.prepare>; if still associated before C<.finalize>, nbdkit will +take care of finalizing the context, and also for closing it. A +filter may also pass C<NULL> for C<next>, to remove any association; +if no plugin context is associated with the connection, then filter +callbacks such as C<.pread> will receive C<NULL> for their C<next_ops> +parameter. + +This function returns the previous context that had been associated +with the connection prior to switching the association to C<next>; +this result will be C<NULL> if there was no previous association. The +filter assumes manual responsibility for any remaining lifecycle +functions that must be called on the returned context. + +=head2 Using C<next_ops> + +Regardless of whether the plugin context is managed automatically or +manually, it is possible for a filter to issue (for example) extra C<next_ops-E<gt>pread> calls in response to a single C<.pwrite> call. Note that the semantics of the functions in C<struct nbdkit_next_ops> @@ -177,6 +268,9 @@ C<nbdkit_set_error> or setting C<errno>), whereas C<next_ops-E<gt>pread> exposes this via an explicit parameter, allowing a filter to learn or modify this error if desired. +Use of C<next_ops-E<gt>prepare> and C<next_ops-E<gt>finalize> is only +needed when manually managing the plugin context lifetime. + =head2 Other considerations You can modify parameters when you call the C<next> function. However @@ -189,7 +283,8 @@ for avoiding a memory leak while still obeying lifecycle constraints. Note that if your filter registers a callback but in that callback it doesn't call the C<next> function then the corresponding method in the plugin will never be called. In particular, your C<.open> method, if -you have one, B<must> call the C<.next> method. +you have one, B<must> call the C<next> method if you want the +underlying plugin to be available to all further C<next_ops> use. =head1 CALLBACKS @@ -468,31 +563,21 @@ C<nbdkit_is_tls>. The filter should generally call C<next> as its first step, to allocate from the plugin outwards, so that C<.close> running from the outer filter to the plugin will be in reverse. Skipping a call to -C<next> is acceptable if the filter will not access C<next_ops> -during any of the remaining callbacks reached on the same connection. +C<next> is acceptable if the filter will not access C<next_ops> during +any of the remaining callbacks reached on the same connection. The +C<next> function is provided for convenience; the same functionality +can be obtained manually (other than error checking) by using the +following: + + nbdkit_context_set_next (context, nbdkit_next_context_open + (nbdkit_context_get_backend (context), readonly, exportname)); The value of C<context> in this call has a lifetime that lasts until -the counterpart C<.close>, and it is this value (and not the distinct -C<nxdata> of C<.pread> and friends) that must be passed as the first -parameter to C<nbdkit_backend_reopen> by a filter attempting to retry -a connection into the backend. - -=head3 Reopening the backend - -Filters have access to a function for reopening the backend: - - int (nbdkit_context *context, int readonly, const char *exportname, - void **nxdata); - -This function is used by L<nbdkit-retry-filter(1)> to close and reopen -the underlying plugin, with possible changes to the C<readonly> and -C<exportname> parameters in relation to the original opening. It -should be used with caution because it is difficult to use safely. -The C<context> parameter to this function should be the C<context> -parameter originally passed in to C<.open>; while the C<nxdata> -pointer should be the address of C<nxdata> from any function with a -C<next_ops> parameter (such as C<.pread>) that wants to call into the -plugin after the reopen. +the counterpart C<.close>, and it is this value that may be passed to +C<nbdkit_context_get_backend> to obtain the C<backend> parameter used +to open a plugin context with C<nbdkit_next_context_open>, as well as +the C<context> parameter used to associate a plugin context into the +current connection with C<nbdkit_context_set_next>. =head2 C<.close> @@ -524,7 +609,8 @@ the plugin's C<.get_size> and C<.pread> methods via C<next_ops>). Or if you need to cleanly update superblock data in the image on close you can do it in your C<.finalize> method (calling the plugin's C<.pwrite> method). Doing these things in the filter's C<.open> or -C<.close> method is not possible. +C<.close> method is not possible without using manual context +lifecycle management. For C<.prepare>, the value of C<readonly> is the same as was passed to C<.open>, declaring how this filter will be used. @@ -541,17 +627,18 @@ overrides query functions or makes I/O calls into the plugin before handshaking is complete, where the filter needs to make those prerequisite calls manually during C<.prepare>. -There is no C<next_ops-E<gt>prepare> or C<next_ops-E<gt>finalize>. -Unlike other filter methods, prepare and finalize are not chained -through the C<next_ops> structure. Instead the core nbdkit server -calls the prepare and finalize methods of all filters. Prepare -methods are called starting with the filter closest to the plugin and -proceeding outwards (matching the order of C<.open> if all filters -call C<next> before doing anything locally), and only when an outer -filter did not skip the C<next> call during C<.open>. Finalize -methods are called in the reverse order of prepare methods, with the -outermost filter first (and matching the order of C<.close>), and only -if the prepare method succeeded. +While there are C<next_ops-E<gt>prepare> and C<next_ops-E<gt>finalize> +functions, these are different from other filter methods, in that any +plugin context associated with the current connection (via the C<next> +parameter to C<.open>, or via C<nbdkit_context_set_next>, is prepared +and finalized automatically by nbdkit, so they are only used during +manual lifecycle management. Prepare methods are called starting with +the filter closest to the plugin and proceeding outwards (matching the +order of C<.open> if all filters call C<next> before doing anything +locally), and only when an outer filter did not skip the C<next> call +during C<.open>. Finalize methods are called in the reverse order of +prepare methods, with the outermost filter first (and matching the +order of C<.close>), and only if the prepare method succeeded. If there is an error, both callbacks should call C<nbdkit_error> with an error message and return C<-1>. An error in C<.prepare> is diff --git a/include/nbdkit-filter.h b/include/nbdkit-filter.h index 3f3f61cd..a8819c9b 100644 --- a/include/nbdkit-filter.h +++ b/include/nbdkit-filter.h @@ -56,7 +56,7 @@ extern "C" { typedef struct backend nbdkit_backend; typedef struct context nbdkit_context; typedef struct context nbdkit_next; -#elif defined NBDKIT_RETRY_FILTER /* Hack to expose reopen to retry filter */ +#elif defined NBDKIT_TYPESAFE /* Temporary define while converting filters */ typedef struct nbdkit_backend nbdkit_backend; typedef struct nbdkit_context nbdkit_context; typedef struct nbdkit_next_ops nbdkit_next; @@ -81,6 +81,12 @@ typedef int nbdkit_next_open (nbdkit_context *context, int readonly, const char *exportname); struct nbdkit_next_ops { + /* These callbacks are only needed when managing the backend manually + * rather than via nbdkit_next_open. + */ + int (*prepare) (nbdkit_next *nxdata); + int (*finalize) (nbdkit_next *nxdata); + /* These callbacks are the same as normal plugin operations. */ int64_t (*get_size) (nbdkit_next *nxdata); const char * (*export_description) (nbdkit_next *nxdata); @@ -120,7 +126,7 @@ struct nbdkit_extent { uint32_t type; }; -NBDKIT_EXTERN_DECL (struct nbdkit_extents *,nbdkit_extents_new, +NBDKIT_EXTERN_DECL (struct nbdkit_extents *, nbdkit_extents_new, (uint64_t start, uint64_t end)); NBDKIT_EXTERN_DECL (void, nbdkit_extents_free, (struct nbdkit_extents *)); NBDKIT_EXTERN_DECL (size_t, nbdkit_extents_count, @@ -153,14 +159,15 @@ NBDKIT_EXTERN_DECL (size_t, nbdkit_exports_count, NBDKIT_EXTERN_DECL (const struct nbdkit_export, nbdkit_get_export, (const struct nbdkit_exports *, size_t)); -#ifdef NBDKIT_RETRY_FILTER -/* Performs close + open on the underlying chain. - * Used by the retry filter. - */ -NBDKIT_EXTERN_DECL (int, nbdkit_backend_reopen, - (nbdkit_context *context, int readonly, - const char *exportname, nbdkit_next **nxdata)); -#endif +/* Manual management of backend access. */ +NBDKIT_EXTERN_DECL (nbdkit_backend *, nbdkit_context_get_backend, + (nbdkit_context *context)); +NBDKIT_EXTERN_DECL (nbdkit_next *, nbdkit_next_context_open, + (nbdkit_backend *backend, int readonly, + const char *exportname)); +NBDKIT_EXTERN_DECL (void, nbdkit_next_context_close, (nbdkit_next *next)); +NBDKIT_EXTERN_DECL (nbdkit_next *, nbdkit_context_set_next, + (nbdkit_context *context, nbdkit_next *next)); /* Filter struct. */ struct nbdkit_filter { diff --git a/server/internal.h b/server/internal.h index b944e56d..849edbf8 100644 --- a/server/internal.h +++ b/server/internal.h @@ -430,9 +430,6 @@ extern bool backend_valid_range (struct context *c, uint64_t offset, uint32_t count) __attribute__((__nonnull__ (1))); -extern int backend_reopen (struct context *c, - int readonly, const char *exportname) - __attribute__((__nonnull__ (1, 3))); extern const char *backend_export_description (struct context *c) __attribute__((__nonnull__ (1))); extern int64_t backend_get_size (struct context *c) diff --git a/server/backend.c b/server/backend.c index 1c78556f..69625597 100644 --- a/server/backend.c +++ b/server/backend.c @@ -210,6 +210,8 @@ backend_default_export (struct backend *b, int readonly) } static struct nbdkit_next_ops next_ops = { + .prepare = backend_prepare, + .finalize = backend_finalize, .export_description = backend_export_description, .get_size = backend_get_size, .can_write = backend_can_write, @@ -363,34 +365,6 @@ backend_valid_range (struct context *c, uint64_t offset, uint32_t count) offset + count <= c->exportsize; } -/* Core functionality of nbdkit_backend_reopen for retry filter */ - -int -backend_reopen (struct context *c, int readonly, const char *exportname) -{ - struct backend *b = c->b; - - controlpath_debug ("%s: reopen readonly=%d exportname=\"%s\"", - b->next->name, readonly, exportname); - - if (c->c_next) { - if (backend_finalize (c->c_next) == -1) - return -1; - backend_close (c->c_next); - c->c_next = NULL; - } - c->c_next = backend_open (b->next, readonly, exportname); - if (c->c_next == NULL) - return -1; - if (backend_prepare (c->c_next) == -1) { - backend_finalize (c->c_next); - backend_close (c->c_next); - c->c_next = NULL; - return -1; - } - return 0; -} - /* Wrappers for all callbacks in a filter's struct nbdkit_next_ops. */ const char * diff --git a/server/filters.c b/server/filters.c index 228e2610..d40c928a 100644 --- a/server/filters.c +++ b/server/filters.c @@ -263,12 +263,14 @@ filter_default_export (struct backend *b, int readonly, int is_tls) static int next_open (struct context *c, int readonly, const char *exportname) { - struct backend *b = c->b; - struct context *c_next = backend_open (b->next, readonly, exportname); + struct backend *b = nbdkit_context_get_backend (c); + struct context *c_next = nbdkit_next_context_open (b, readonly, exportname); + struct context *old; if (c_next == NULL) return -1; - c->c_next = c_next; + old = nbdkit_context_set_next (c, c_next); + assert (old == NULL); return 0; } @@ -694,12 +696,35 @@ filter_register (struct backend *next, size_t index, const char *filename, return (struct backend *) f; } -int -nbdkit_backend_reopen (struct context *c, int readonly, - const char *exportname, struct context **nxdata) +struct backend * +nbdkit_context_get_backend (struct context *c) { - int r = backend_reopen (c, readonly, exportname); + assert (c); + return c->b; +} + +struct context * +nbdkit_next_context_open (struct backend *b, + int readonly, const char *exportname) +{ + assert (b); + return backend_open (b->next, readonly, exportname); +} + +void +nbdkit_next_context_close (struct context *c) +{ + if (c) + backend_close (c); +} + +struct context * +nbdkit_context_set_next (struct context *c, struct context *next) +{ + struct context *old; - *nxdata = c->c_next; - return r; + assert (c); + old = c->c_next; + c->c_next = next; + return old; } diff --git a/server/nbdkit.syms b/server/nbdkit.syms index 50411d27..143c4ebf 100644 --- a/server/nbdkit.syms +++ b/server/nbdkit.syms @@ -41,33 +41,36 @@ nbdkit_absolute_path; nbdkit_add_export; nbdkit_add_extent; - nbdkit_backend_reopen; + nbdkit_context_get_backend; + nbdkit_context_set_next; nbdkit_debug; nbdkit_error; nbdkit_export_name; nbdkit_exports_count; nbdkit_exports_free; nbdkit_exports_new; - nbdkit_get_export; nbdkit_extents_aligned; nbdkit_extents_count; nbdkit_extents_free; nbdkit_extents_full; nbdkit_extents_new; + nbdkit_get_export; nbdkit_get_extent; nbdkit_is_tls; nbdkit_nanosleep; + nbdkit_next_context_close; + nbdkit_next_context_open; nbdkit_parse_bool; - nbdkit_parse_int8_t; nbdkit_parse_int16_t; nbdkit_parse_int32_t; nbdkit_parse_int64_t; + nbdkit_parse_int8_t; nbdkit_parse_int; nbdkit_parse_size; - nbdkit_parse_uint8_t; nbdkit_parse_uint16_t; nbdkit_parse_uint32_t; nbdkit_parse_uint64_t; + nbdkit_parse_uint8_t; nbdkit_parse_unsigned; nbdkit_peer_gid; nbdkit_peer_name; diff --git a/filters/retry/retry.c b/filters/retry/retry.c index cfaea7d4..22527c7d 100644 --- a/filters/retry/retry.c +++ b/filters/retry/retry.c @@ -40,7 +40,7 @@ #include <string.h> #include <sys/time.h> -#define NBDKIT_RETRY_FILTER /* Hack to expose reopen */ +#define NBDKIT_TYPESAFE /* Hack to expose context APIs */ #include <nbdkit-filter.h> #include "cleanup.h" @@ -109,7 +109,7 @@ retry_config (nbdkit_next_config *next, nbdkit_backend *nxdata, struct retry_handle { int readonly; /* Save original readonly setting. */ char *exportname; /* Client exportname. */ - nbdkit_context *backend; /* Backend learned during .open. */ + nbdkit_context *context; /* Context learned during .open. */ unsigned reopens; bool open; }; @@ -131,7 +131,7 @@ retry_open (nbdkit_next_open *next, nbdkit_context *nxdata, h->readonly = readonly; h->exportname = strdup (exportname); - h->backend = nxdata; + h->context = nxdata; if (h->exportname == NULL) { nbdkit_error ("strdup: %m"); free (h); @@ -178,6 +178,8 @@ static bool do_retry (struct retry_handle *h, struct retry_data *data, nbdkit_next **next, const char *method, int *err) { + nbdkit_next *new_next, *old_next; + /* If it's the first retry, initialize the other fields in *data. */ if (data->retry == 0) data->delay = initial_delay; @@ -207,17 +209,39 @@ do_retry (struct retry_handle *h, struct retry_data *data, if (exponential_backoff) data->delay *= 2; - /* Reopen the connection. */ + /* Close the old connection. */ h->reopens++; - if (nbdkit_backend_reopen (h->backend, h->readonly || force_readonly, - h->exportname, next) == -1) { - /* If the reopen fails we treat it the same way as a command - * failing. + h->open = false; + if (*next != NULL) { + /* Failure to finalize a connection indicates permanent data loss, + * which we treat the same as the original command failing. */ - h->open = false; + if ((*next)->finalize (*next) == -1) { + *err = ESHUTDOWN; + goto again; + } + nbdkit_next_context_close (*next); + old_next = nbdkit_context_set_next (h->context, NULL); + assert (old_next == *next); + *next = NULL; + } + /* Open a new connection. */ + new_next = nbdkit_next_context_open (nbdkit_context_get_backend (h->context), + h->readonly || force_readonly, + h->exportname); + if (new_next == NULL) { + *err = ESHUTDOWN; + goto again; + } + if (new_next->prepare (new_next) == -1) { + new_next->finalize (new_next); + nbdkit_next_context_close (new_next); *err = ESHUTDOWN; goto again; } + old_next = nbdkit_context_set_next (h->context, new_next); + assert (old_next == NULL); + *next = new_next; h->open = true; /* Retry the data command. */ diff --git a/TODO b/TODO index c96a8b22..2bde2478 100644 --- a/TODO +++ b/TODO @@ -73,22 +73,13 @@ General ideas for improvements * Background thread for filters. Some filters (readahead, cache and proposed scan filter - see below) could be more effective if they - were able to defer work to a background thread. However it's not as - simple as just creating a background thread, because you only have - access to the connection / next_ops from the context of a filter - callback. (Also you can't "save" next_ops because it becomes - invalid outside the callback). The background thread would need to - have its own connection to the plugin, which would be independent of - any client connection, and this requires some care because it breaks - an existing assumption. - -* Add scan filter. This would be placed on top of cache filters and - would scan (read) the whole disk in the background, ensuring it is - copied into the cache. Useful if you have a slow plugin, limited - size device, and lots of local disk space, especially if you know - that the NBD clients will eventually read all of the device. RWMJ - wrote an implementation of this but it doesn't work well without a - background thread. + were able to defer work to a background thread. We finally have + nbdkit_next_context_open and friends for allowing a background + thread to have access into the plugin, but still need to worry about + thread-safety (how much must the filter do vs. nbdkit, to avoid + calling into the plugin too many times at once) and cleanup + (spawning the thread during .after_fork is viable, but cleaning it + up during .unload is too late). * "nbdkit.so": nbdkit as a loadable shared library. The aim of nbdkit is to make it reusable from other programs (see nbdkit-captive(1)). @@ -196,6 +187,19 @@ Python: Suggestions for filters ----------------------- +* Add scan filter. This would be placed on top of cache filters and + would scan (read) the whole disk in the background, ensuring it is + copied into the cache. Useful if you have a slow plugin, limited + size device, and lots of local disk space, especially if you know + that the NBD clients will eventually read all of the device. RWMJ + wrote an implementation of this but it doesn't work well without a + background thread. + +* Add shared filter. Take advantage of filter context APIs to open a + single context into the backend shared among multiple client + connections. This may even allow a filter to offer a more parallel + threading model than the underlying plugin. + * LUKS encrypt/decrypt filter, bonus points if compatible with qemu LUKS-encrypted disk images -- 2.30.1
Eric Blake
2021-Mar-05 23:31 UTC
[Libguestfs] [nbdkit PATCH v3 13/16] ext2: Simplify use of next_ops
We no longer need a 'struct nbdkit_next' now that a single pointer is sufficient for calling into the backend. There's still more to do with the filter to allow multiple client plugins to share a single context into the plugin, but that requires a bit more work (for starters, we need a way to clean up that single context; .unload is too late, but doing it in .close requires tracking how many open client connections there are). --- filters/ext2/io.h | 12 +++----- filters/ext2/ext2.c | 43 +++++++++++++------------- filters/ext2/io.c | 73 ++++++++++++++++++++++----------------------- 3 files changed, 61 insertions(+), 67 deletions(-) diff --git a/filters/ext2/io.h b/filters/ext2/io.h index da286812..2112e541 100644 --- a/filters/ext2/io.h +++ b/filters/ext2/io.h @@ -1,5 +1,5 @@ /* nbdkit - * Copyright (C) 2020 Red Hat Inc. + * Copyright (C) 2020-2021 Red Hat Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -35,19 +35,15 @@ #include <ext2_io.h> +#define NBDKIT_TYPESAFE /* HACK to get type-safe parameters. */ #include <nbdkit-filter.h> #define EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL EXT2_ET_MAGIC_RESERVED_19 -struct nbdkit_next { - struct nbdkit_next_ops *next_ops; - void *nxdata; -}; - /* Utility functions for encoding nbdkit_next as a name usable by ext2fs */ -extern char *nbdkit_io_encode(const struct nbdkit_next *next) +extern char *nbdkit_io_encode(const nbdkit_next *next) __attribute__ ((__nonnull__ (1))); -extern int nbdkit_io_decode(const char *name, struct nbdkit_next *out) +extern int nbdkit_io_decode(const char *name, nbdkit_next **out) __attribute__ ((__nonnull__ (1, 2))); /* Custom io manager that performs all ext2fs I/O on the next nbdkit layer */ diff --git a/filters/ext2/ext2.c b/filters/ext2/ext2.c index 1151effd..9a6eec94 100644 --- a/filters/ext2/ext2.c +++ b/filters/ext2/ext2.c @@ -45,6 +45,7 @@ #define NBDKIT_API_VERSION 2 +#define NBDKIT_TYPESAFE /* HACK to get type-safe parameters. */ #include <nbdkit-filter.h> #include "cleanup.h" @@ -62,7 +63,7 @@ ext2_load (void) } static int -ext2_config (nbdkit_next_config *next, void *nxdata, +ext2_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { if (strcmp (key, "ext2file") == 0) { @@ -78,7 +79,7 @@ ext2_config (nbdkit_next_config *next, void *nxdata, } static int -ext2_config_complete (nbdkit_next_config_complete *next, void *nxdata) +ext2_config_complete (nbdkit_next_config_complete *next, nbdkit_backend *nxdata) { if (file == NULL) { nbdkit_error ("you must supply ext2file=<FILE> parameter " @@ -106,12 +107,12 @@ struct handle { ext2_filsys fs; /* Filesystem handle. */ ext2_ino_t ino; /* Inode of open file. */ ext2_file_t file; /* File handle. */ - struct nbdkit_next next; /* "name" parameter to ext2fs_open. */ + nbdkit_next *next; /* "name" parameter to ext2fs_open. */ }; /* Export list. */ static int -ext2_list_exports (nbdkit_next_list_exports *next, void *nxdata, +ext2_list_exports (nbdkit_next_list_exports *next, nbdkit_backend *nxdata, int readonly, int is_tls, struct nbdkit_exports *exports) { /* If we are honoring export names, the default export "" won't @@ -133,7 +134,7 @@ ext2_list_exports (nbdkit_next_list_exports *next, void *nxdata, /* Default export. */ static const char * -ext2_default_export (nbdkit_next_default_export *next, void *nxdata, +ext2_default_export (nbdkit_next_default_export *next, nbdkit_backend *nxdata, int readonly, int is_tls) { /* If we are honoring exports, "" will fail (even if we resolve to @@ -152,7 +153,7 @@ ext2_default_export (nbdkit_next_default_export *next, void *nxdata, /* Create the per-connection handle. */ static void * -ext2_open (nbdkit_next_open *next, void *nxdata, +ext2_open (nbdkit_next_open *next, nbdkit_context *nxdata, int readonly, const char *exportname, int is_tls) { struct handle *h; @@ -185,7 +186,7 @@ ext2_open (nbdkit_next_open *next, void *nxdata, } static int -ext2_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, +ext2_prepare (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle, int readonly) { struct handle *h = handle; @@ -214,9 +215,8 @@ ext2_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, if (!readonly) fs_flags |= EXT2_FLAG_RW; - h->next.next_ops = next_ops; - h->next.nxdata = nxdata; - name = nbdkit_io_encode (&h->next); + h->next = next_ops; + name = nbdkit_io_encode (next_ops); if (!name) { nbdkit_error ("nbdkit_io_encode: %m"); return -1; @@ -293,20 +293,20 @@ ext2_close (void *handle) } static int -ext2_can_fua (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) +ext2_can_fua (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle) { return NBDKIT_FUA_NATIVE; } static int -ext2_can_cache (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) +ext2_can_cache (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle) { /* Let nbdkit call pread to populate the file system cache. */ return NBDKIT_CACHE_EMULATE; } static int -ext2_can_multi_conn (struct nbdkit_next_ops *next_ops, void *nxdata, +ext2_can_multi_conn (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle) { /* Since we do not permit parallel connections, it does not matter @@ -320,7 +320,8 @@ ext2_can_multi_conn (struct nbdkit_next_ops *next_ops, void *nxdata, } static int -ext2_can_flush (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) +ext2_can_flush (nbdkit_next *next_ops, nbdkit_next *nxdata, + void *handle) { /* Regardless of the underlying plugin, we handle flush at the level * of the filesystem. However, we also need to cache the underlying @@ -337,7 +338,7 @@ ext2_can_flush (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) * is very obscure. */ static int -ext2_can_zero (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) +ext2_can_zero (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle) { /* For now, tell nbdkit to call .pwrite instead of any optimization. * However, we also want to cache the underlying plugin support. @@ -348,7 +349,7 @@ ext2_can_zero (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) } static int -ext2_can_trim (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) +ext2_can_trim (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle) { /* For now, tell nbdkit to never call .trim. However, we also want * to cache the underlying plugin support. @@ -377,7 +378,7 @@ static int ext2_thread_model (void) /* Description. */ static const char * -ext2_export_description (struct nbdkit_next_ops *next_ops, void *nxdata, +ext2_export_description (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle) { struct handle *h = handle; @@ -393,7 +394,7 @@ ext2_export_description (struct nbdkit_next_ops *next_ops, void *nxdata, /* Get the disk size. */ static int64_t -ext2_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) +ext2_get_size (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle) { struct handle *h = handle; errcode_t err; @@ -409,7 +410,7 @@ ext2_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) /* Read data. */ static int -ext2_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +ext2_pread (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *errp) { @@ -446,7 +447,7 @@ ext2_pread (struct nbdkit_next_ops *next_ops, void *nxdata, /* Write data to the file. */ static int -ext2_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +ext2_pwrite (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *errp) { @@ -487,7 +488,7 @@ ext2_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, } static int -ext2_flush (struct nbdkit_next_ops *next_ops, void *nxdata, +ext2_flush (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle, uint32_t flags, int *errp) { struct handle *h = handle; diff --git a/filters/ext2/io.c b/filters/ext2/io.c index 32c50683..e2f7e43e 100644 --- a/filters/ext2/io.c +++ b/filters/ext2/io.c @@ -60,8 +60,7 @@ struct io_private_data { int magic; - struct nbdkit_next_ops *next_ops; - void *nxdata; + nbdkit_next *next; ext2_loff_t offset; struct struct_io_stats io_stats; }; @@ -103,7 +102,7 @@ raw_read_blk (io_channel channel, location = ((ext2_loff_t) block * channel->block_size) + data->offset; /* TODO is 32-bit overflow ever likely to be a problem? */ - if (data->next_ops->pread (data->nxdata, buf, size, location, 0, &errno) == 0) + if (data->next->pread (data->next, buf, size, location, 0, &errno) == 0) return 0; retval = errno; @@ -138,8 +137,8 @@ raw_write_blk (io_channel channel, location = ((ext2_loff_t) block * channel->block_size) + data->offset; /* TODO is 32-bit overflow ever likely to be a problem? */ - if (data->next_ops->pwrite (data->nxdata, buf, size, location, 0, - &errno) == 0) + if (data->next->pwrite (data->next, buf, size, location, 0, + &errno) == 0) return 0; retval = errno; @@ -150,22 +149,21 @@ raw_write_blk (io_channel channel, } char * -nbdkit_io_encode (const struct nbdkit_next *next) +nbdkit_io_encode (const nbdkit_next *next) { char *ret; - if (asprintf (&ret, "nbdkit:%p:%p", next->next_ops, next->nxdata) < 0) + if (asprintf (&ret, "nbdkit:%p", next) < 0) return NULL; return ret; } int -nbdkit_io_decode (const char *name, struct nbdkit_next *next) +nbdkit_io_decode (const char *name, nbdkit_next **next) { int n; - if (sscanf (name, "nbdkit:%p:%p%n", &next->next_ops, &next->nxdata, - &n) != 2 || n != strlen (name)) + if (sscanf (name, "nbdkit:%p%n", next, &n) != 1 || n != strlen (name)) return -1; return 0; } @@ -174,7 +172,7 @@ static errcode_t io_open (const char *name, int flags, io_channel *channel) { - struct nbdkit_next next; + nbdkit_next *next; io_channel io = NULL; struct io_private_data *data = NULL; errcode_t retval; @@ -206,14 +204,13 @@ io_open (const char *name, int flags, memset (data, 0, sizeof (struct io_private_data)); data->magic = EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL; data->io_stats.num_fields = 2; - data->next_ops = next.next_ops; - data->nxdata = next.nxdata; + data->next = next; - /* Too bad NBD doesn't tell us if next_ops->trim guarantees read as zero. */ - /* if (next_ops-> XXX (...) + /* Too bad NBD doesn't tell us if next->trim guarantees read as zero. */ + /* if (next-> XXX (...) io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES; */ - if (flags & IO_FLAG_RW && next.next_ops->can_write (next.nxdata) != 1) { + if (flags & IO_FLAG_RW && next->can_write (next) != 1) { retval = EPERM; goto cleanup; } @@ -310,13 +307,13 @@ io_cache_readahead (io_channel channel, data = (struct io_private_data *)channel->private_data; EXT2_CHECK_MAGIC (data, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL); - if (data->next_ops->can_cache (data->nxdata) == NBDKIT_CACHE_NATIVE) { + if (data->next->can_cache (data->next) == NBDKIT_CACHE_NATIVE) { /* TODO is 32-bit overflow ever likely to be a problem? */ - if (data->next_ops->cache (data->nxdata, - (ext2_loff_t)count * channel->block_size, - ((ext2_loff_t)block * channel->block_size + - data->offset), - 0, &errno) == -1) + if (data->next->cache (data->next, + (ext2_loff_t)count * channel->block_size, + ((ext2_loff_t)block * channel->block_size + + data->offset), + 0, &errno) == -1) return errno; return 0; } @@ -342,8 +339,8 @@ io_write_byte (io_channel channel, unsigned long offset, data = (struct io_private_data *) channel->private_data; EXT2_CHECK_MAGIC (data, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL); - if (data->next_ops->pwrite (data->nxdata, buf, size, - offset + data->offset, 0, &errno) == -1) + if (data->next->pwrite (data->next, buf, size, + offset + data->offset, 0, &errno) == -1) return errno; return 0; @@ -362,8 +359,8 @@ io_flush (io_channel channel) data = (struct io_private_data *) channel->private_data; EXT2_CHECK_MAGIC (data, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL); - if (data->next_ops->can_flush (data->nxdata) == 1) - if (data->next_ops->flush (data->nxdata, 0, &errno) == -1) + if (data->next->can_flush (data->next) == 1) + if (data->next->flush (data->next, 0, &errno) == -1) return errno; return retval; } @@ -405,13 +402,13 @@ io_discard (io_channel channel, unsigned long long block, data = (struct io_private_data *) channel->private_data; EXT2_CHECK_MAGIC (data, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL); - if (data->next_ops->can_trim (data->nxdata) == 1) { + if (data->next->can_trim (data->next) == 1) { /* TODO is 32-bit overflow ever likely to be a problem? */ - if (data->next_ops->trim (data->nxdata, - (off_t)(count) * channel->block_size, - ((off_t)(block) * channel->block_size + - data->offset), - 0, &errno) == 0) + if (data->next->trim (data->next, + (off_t)(count) * channel->block_size, + ((off_t)(block) * channel->block_size + + data->offset), + 0, &errno) == 0) return 0; if (errno == EOPNOTSUPP) goto unimplemented; @@ -433,13 +430,13 @@ io_zeroout (io_channel channel, unsigned long long block, data = (struct io_private_data *) channel->private_data; EXT2_CHECK_MAGIC (data, EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL); - if (data->next_ops->can_zero (data->nxdata) > NBDKIT_ZERO_NONE) { + if (data->next->can_zero (data->next) > NBDKIT_ZERO_NONE) { /* TODO is 32-bit overflow ever likely to be a problem? */ - if (data->next_ops->zero (data->nxdata, - (off_t)(count) * channel->block_size, - ((off_t)(block) * channel->block_size + - data->offset), - NBDKIT_FLAG_MAY_TRIM, &errno) == 0) + if (data->next->zero (data->next, + (off_t)(count) * channel->block_size, + ((off_t)(block) * channel->block_size + + data->offset), + NBDKIT_FLAG_MAY_TRIM, &errno) == 0) return 0; if (errno == EOPNOTSUPP) goto unimplemented; -- 2.30.1
Eric Blake
2021-Mar-05 23:31 UTC
[Libguestfs] [nbdkit PATCH v3 14/16] filters: Adjust API for type-safety and merged next_ops/nxdata
As promised in several previous patches, this is a mechanical change that does two things to every filter: instead of using void* for callback parameters, we now use an actual opaque type (which helps avoid errors of passing the wrong pointer around), and instead of passing identical pointers for next_ops and nxdata, we pass a single parameter. The changes in docs and server are manual, but the bulk of the changes in filters were driven by: $ cat s.cocci @rule1@ identifier fn, next_ops, nxdata; typedef nbdkit_next; @@ fn( - struct nbdkit_next_ops *next_ops, void *nxdata + nbdkit_next *next ,...) { ... } @@ identifier rule1.next_ops, rule1.nxdata; identifier op; expression list args; expression exp; @@ ( -next_ops->op (nxdata, args) +next->op (next, args) | -exp (next_ops, nxdata, args) +exp (next, args) ) @@ identifier fn, next, nxdata; @@ -fn(struct nbdkit_next_open *next, void *nxdata +fn(struct nbdkit_next_open *next, nbdkit_context *nxdata ,...) { ... } @@ identifier fn, next; identifier nxdata != handle; type nbdkit_foo; @@ fn( - nbdkit_foo *next, void *nxdata + nbdkit_foo *next, nbdkit_backend *nxdata , ...) { ... } $ spatch --sp-file s.cocci --in-place --no-show-diff \ filters/ tests/test-layers-filter.c $ git grep -l 'next->[a-z_]*(' filters/ | \ xargs sed -i 's/next->\([a-z_]*\)(/next->\1 (/g' Followed by manual touchups until everything compiled. --- docs/nbdkit-filter.pod | 219 ++++++++++++++-------------- include/nbdkit-filter.h | 58 +++----- server/extents.c | 19 +-- server/filters.c | 42 +++--- filters/cache/blk.h | 16 +- filters/cow/blk.h | 8 +- filters/ext2/io.h | 1 - filters/partition/partition.h | 4 +- filters/xz/xzfile.h | 6 +- filters/blocksize/blocksize.c | 76 +++++----- filters/cache/blk.c | 16 +- filters/cache/cache.c | 94 ++++++------ filters/cacheextents/cacheextents.c | 16 +- filters/checkwrite/checkwrite.c | 30 ++-- filters/cow/blk.c | 10 +- filters/cow/cow.c | 80 +++++----- filters/ddrescue/ddrescue.c | 10 +- filters/delay/delay.c | 30 ++-- filters/error/error.c | 26 ++-- filters/exitwhen/exitwhen.c | 9 +- filters/exportname/exportname.c | 14 +- filters/ext2/ext2.c | 45 +++--- filters/extentlist/extentlist.c | 11 +- filters/fua/fua.c | 38 ++--- filters/gzip/gzip.c | 30 ++-- filters/ip/ip.c | 7 +- filters/log/log.c | 63 ++++---- filters/nocache/nocache.c | 6 +- filters/noextents/noextents.c | 2 +- filters/noparallel/noparallel.c | 2 +- filters/nozero/nozero.c | 22 +-- filters/offset/offset.c | 33 ++--- filters/partition/partition-gpt.c | 7 +- filters/partition/partition-mbr.c | 5 +- filters/partition/partition.c | 52 +++---- filters/pause/pause.c | 31 ++-- filters/rate/rate.c | 15 +- filters/readahead/readahead.c | 39 +++-- filters/retry/retry.c | 17 +-- filters/stats/stats.c | 36 ++--- filters/swab/swab.c | 32 ++-- filters/tar/tar.c | 49 ++++--- filters/tls-fallback/tls-fallback.c | 50 ++++--- filters/truncate/truncate.c | 50 +++---- filters/xz/xz.c | 28 ++-- filters/xz/xzfile.c | 45 +++--- tests/test-truncate4.sh | 2 +- tests/test-layers-filter.c | 148 +++++++++---------- 48 files changed, 814 insertions(+), 835 deletions(-) diff --git a/docs/nbdkit-filter.pod b/docs/nbdkit-filter.pod index d13ac1d7..a06f4e37 100644 --- a/docs/nbdkit-filter.pod +++ b/docs/nbdkit-filter.pod @@ -139,17 +139,19 @@ C<.default_export>, and can also be obtained by using C<nbdkit_context_get_backend> on the C<context> parameter to C<.open>. Meanwhile, if the filter does not use C<nbdkit_context_set_next>, the -value of C<nxdata> passed to C<.prepare> has a stable lifetime that +value of C<next> passed to C<.prepare> has a stable lifetime that lasts to the corresponding C<.finalize>, with all intermediate functions (such as C<.pread>) receiving the same value for convenience. Functions where C<nxdata> is not reused are C<.config>, -C<.config_complete>, C<.get_ready>, and C<.after_fork>, which are -called during initialization outside any connections, and -C<.preconnect>, C<.list_exports>, C<.default_export>, and C<.open> -which are called based on client connections but prior to the stable -lifetime of C<.prepare>. The value of C<context> passed to C<.open> -has a lifetime that lasts until the matching C<.close> for use by -C<nbdkit_context_get_backend>. +C<.config_complete>, and C<.get_ready>, which are all called during +initialization outside any connections. The value of C<backend> +passed to C<.after_fork> also occurs without connections, but is +shared with C<.preconnect>, C<.list_exports>, and C<.default_export>, +and can also be obtained from the C<context> passed to C<.open>, and +has a lifetime that lasts to C<.unload> for use by +C<nbdkit_context_next_open>. In turn, the value of C<context> passed +to C<.open> has a lifetime that lasts until the matching C<.close> for +use by C<nbdkit_context_get_backend>. =head2 Next config, open and close @@ -164,19 +166,20 @@ The filter?s C<.close> method is called when an old connection closed, and this has no C<next> parameter because it cannot be short-circuited. -=head2 C<next_ops> +=head2 C<nbdkit_next> The filter generally needs to call into the underlying plugin, which -is done via a pointer to C<struct nbdkit_next_ops>. The most common -behavior is to create a next context per connection by calling the -C<next_open> parameter during C<.open>, at which point the next -context will be automatically provided to the filter?s other methods -like C<.prepare>, C<.get_size>, C<.pread> etc. The C<next_ops> struct -contains a comparable set of accessors to plugin methods that can be -called during a connection. When using automatic registration, the -C<next_ops> parameter is stable between C<.prepare> and C<.finalize>, -and nbdkit automatically prepares, finalizes, and closes the next -context at the right point in the filter connection lifecycle. +is done via a pointer to C<struct nbdkit_next_ops>, also available as +the typedef C<nbdkit_next>. The most common behavior is to create a +next context per connection by calling the C<next_open> parameter +during C<.open>, at which point the next context will be automatically +provided to the filter?s other methods like C<.prepare>, C<.get_size>, +C<.pread> etc. The C<nbdkit_next> struct contains a comparable set of +accessors to plugin methods that can be called during a connection. +When using automatic registration, the C<next> parameter is stable +between C<.prepare> and C<.finalize>, and nbdkit automatically +prepares, finalizes, and closes the next context at the right point in +the filter connection lifecycle. Alternatively, the filter can manage plugin contexts manually, whether to multiplex multiple client connections through a single context into @@ -193,7 +196,7 @@ context, and must reclaim the memory using C<next-E<gt>finalize (next)> and C<nbdkit_next_context_close> when done. A filter using manual lifecycle management may use C<nbdkit_context_set_next> to associate the next context into the current connection, which lets -nbdkit then pass that context as the C<next_ops> parameter to future +nbdkit then pass that context as the C<next> parameter to future connection-related functions like C<.pread> and take over lifecycle responsibility. @@ -238,14 +241,14 @@ C<nbdkit_context_set_next> prior to the C<.close> callback. This function associates a plugin context with the filter's current connection context, given by the C<context> parameter to C<.open>. -Once associated, this plugin context will be given as the C<next_ops> +Once associated, this plugin context will be given as the C<next> parameter to all other connection-specific callbacks. If associated during C<.open>, nbdkit will take care of preparing the context prior to C<.prepare>; if still associated before C<.finalize>, nbdkit will take care of finalizing the context, and also for closing it. A filter may also pass C<NULL> for C<next>, to remove any association; if no plugin context is associated with the connection, then filter -callbacks such as C<.pread> will receive C<NULL> for their C<next_ops> +callbacks such as C<.pread> will receive C<NULL> for their C<next> parameter. This function returns the previous context that had been associated @@ -254,21 +257,29 @@ this result will be C<NULL> if there was no previous association. The filter assumes manual responsibility for any remaining lifecycle functions that must be called on the returned context. -=head2 Using C<next_ops> +=head2 Using C<nbdkit_next> Regardless of whether the plugin context is managed automatically or manually, it is possible for a filter to issue (for example) extra -C<next_ops-E<gt>pread> calls in response to a single C<.pwrite> call. +C<next-E<gt>pread> calls in response to a single C<.pwrite> call. + +The C<next> parameter serves two purposes: it serves as the struct +to access the pointers to all the plugin connection functions, and it +serves as the opaque data that must be passed as the first parameter +to those functions. For example, calling the plugin's can_flush +functionality would be done via + + next-E<gt>can_flush (next) Note that the semantics of the functions in C<struct nbdkit_next_ops> are slightly different from what a plugin implements: for example, when a plugin's C<.pread> returns -1 on error, the error value to advertise to the client is implicit (via the plugin calling C<nbdkit_set_error> or setting C<errno>), whereas -C<next_ops-E<gt>pread> exposes this via an explicit parameter, +C<next-E<gt>pread> exposes this via an explicit parameter, allowing a filter to learn or modify this error if desired. -Use of C<next_ops-E<gt>prepare> and C<next_ops-E<gt>finalize> is only +Use of C<next-E<gt>prepare> and C<next-E<gt>finalize> is only needed when manually managing the plugin context lifetime. =head2 Other considerations @@ -284,7 +295,7 @@ Note that if your filter registers a callback but in that callback it doesn't call the C<next> function then the corresponding method in the plugin will never be called. In particular, your C<.open> method, if you have one, B<must> call the C<next> method if you want the -underlying plugin to be available to all further C<next_ops> use. +underlying plugin to be available to all further C<nbdkit_next> use. =head1 CALLBACKS @@ -412,7 +423,7 @@ an error message and return C<-1>. =head2 C<.after_fork> - int (*after_fork) (nbdkit_next_after_fork *next, void *nxdata); + int (*after_fork) (nbdkit_next_after_fork *next, nbdkit_backend *nxdata); This intercepts the plugin C<.after_fork> method and can be used by the filter to start background threads (although these have limited @@ -423,7 +434,7 @@ an error message and return C<-1>. =head2 C<.preconnect> - int (*preconnect) (nbdkit_next_preconnect *next, void *nxdata, + int (*preconnect) (nbdkit_next_preconnect *next, nbdkit_backend *nxdata, int readonly); This intercepts the plugin C<.preconnect> method and can be used to @@ -434,7 +445,7 @@ an error message and return C<-1>. =head2 C<.list_exports> - int (*list_exports) (nbdkit_next_list_exports *next, void *nxdata, + int (*list_exports) (nbdkit_next_list_exports *next, nbdkit_backend *nxdata, int readonly, int is_tls, struct nbdkit_exports *exports); @@ -510,7 +521,8 @@ Returns a copy of the C<i>'th export. =head2 C<.default_export> - const char *default_export (nbdkit_next_default_export *next, void *nxdata, + const char *default_export (nbdkit_next_default_export *next, + nbdkit_backend *nxdata, int readonly, int is_tls) This intercepts the plugin C<.default_export> method and can be used to @@ -563,11 +575,11 @@ C<nbdkit_is_tls>. The filter should generally call C<next> as its first step, to allocate from the plugin outwards, so that C<.close> running from the outer filter to the plugin will be in reverse. Skipping a call to -C<next> is acceptable if the filter will not access C<next_ops> during -any of the remaining callbacks reached on the same connection. The -C<next> function is provided for convenience; the same functionality -can be obtained manually (other than error checking) by using the -following: +C<next> is acceptable if the filter will not access C<nbdkit_next> +during any of the remaining callbacks reached on the same connection. +The C<next> function is provided for convenience; the same +functionality can be obtained manually (other than error checking) by +using the following: nbdkit_context_set_next (context, nbdkit_next_context_open (nbdkit_context_get_backend (context), readonly, exportname)); @@ -594,10 +606,8 @@ cannot report failures or access the underlying plugin. =head2 C<.finalize> - int (*prepare) (struct nbdkit_next_ops *next_ops, void *nxdata, - void *handle, int readonly); - int (*finalize) (struct nbdkit_next_ops *next_ops, void *nxdata, - void *handle); + int (*prepare) (nbdkit_next *next, void *handle, int readonly); + int (*finalize) (nbdkit_next *next, void *handle); These two methods can be used to perform any necessary operations just after opening the connection (C<.prepare>) or just before closing the @@ -605,7 +615,7 @@ connection (C<.finalize>). For example if you need to scan the underlying disk to check for a partition table, you could do it in your C<.prepare> method (calling -the plugin's C<.get_size> and C<.pread> methods via C<next_ops>). Or +the plugin's C<.get_size> and C<.pread> methods via C<next>). Or if you need to cleanly update superblock data in the image on close you can do it in your C<.finalize> method (calling the plugin's C<.pwrite> method). Doing these things in the filter's C<.open> or @@ -616,18 +626,18 @@ For C<.prepare>, the value of C<readonly> is the same as was passed to C<.open>, declaring how this filter will be used. Note that nbdkit performs sanity checking on requests made to the -underlying plugin; for example, C<next_ops-E<gt>pread> cannot be -called on a given connection unless C<next_ops-E<gt>get_size> has +underlying plugin; for example, C<next-E<gt>pread> cannot be +called on a given connection unless C<next-E<gt>get_size> has first been called at least once in the same connection (to ensure the -read requests are in bounds), and C<next_ops-E<gt>pwrite> further -requires an earlier successful call to C<next_ops-E<gt>can_write>. In +read requests are in bounds), and C<next-E<gt>pwrite> further +requires an earlier successful call to C<next-E<gt>can_write>. In many filters, these prerequisites will be automatically called during the client negotiation phase, but there are cases where a filter overrides query functions or makes I/O calls into the plugin before handshaking is complete, where the filter needs to make those prerequisite calls manually during C<.prepare>. -While there are C<next_ops-E<gt>prepare> and C<next_ops-E<gt>finalize> +While there are C<next-E<gt>prepare> and C<next-E<gt>finalize> functions, these are different from other filter methods, in that any plugin context associated with the current connection (via the C<next> parameter to C<.open>, or via C<nbdkit_context_set_next>, is prepared @@ -648,8 +658,7 @@ in C<.finalize> forces the client to disconnect. =head2 C<.get_size> - int64_t (*get_size) (struct nbdkit_next_ops *next_ops, void *nxdata, - void *handle); + int64_t (*get_size) (nbdkit_next *next, void *handle); This intercepts the plugin C<.get_size> method and can be used to read or modify the apparent size of the block device that the NBD client @@ -658,13 +667,12 @@ will see. 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>. This function is only called once per connection and cached by nbdkit. -Similarly, repeated calls to C<next_ops-E<gt>get_size> will return a +Similarly, repeated calls to C<next-E<gt>get_size> will return a cached value. =head2 C<.export_description> - const char *export_description (struct nbdkit_next_ops *next_ops, - void *nxdata, void *handle); + const char *export_description (nbdkit_next *next, void *handle); This intercepts the plugin C<.export_description> method and can be used to read or modify the export description that the NBD client @@ -690,27 +698,16 @@ will see. =head2 C<.can_cache> - int (*can_write) (struct nbdkit_next_ops *next_ops, void *nxdata, - void *handle); - int (*can_flush) (struct nbdkit_next_ops *next_ops, void *nxdata, - void *handle); - int (*is_rotational) (struct nbdkit_next_ops *next_ops, - void *nxdata, - void *handle); - int (*can_trim) (struct nbdkit_next_ops *next_ops, void *nxdata, - void *handle); - int (*can_zero) (struct nbdkit_next_ops *next_ops, void *nxdata, - void *handle); - int (*can_fast_zero) (struct nbdkit_next_ops *next_ops, void *nxdata, - void *handle); - int (*can_extents) (struct nbdkit_next_ops *next_ops, void *nxdata, - void *handle); - int (*can_fua) (struct nbdkit_next_ops *next_ops, void *nxdata, - void *handle); - int (*can_multi_conn) (struct nbdkit_next_ops *next_ops, void *nxdata, - void *handle); - int (*can_cache) (struct nbdkit_next_ops *next_ops, void *nxdata, - void *handle); + int (*can_write) (nbdkit_next *next, void *handle); + int (*can_flush) (nbdkit_next *next, void *handle); + int (*is_rotational) (nbdkit_next *next, void *handle); + int (*can_trim) (nbdkit_next *next, void *handle); + int (*can_zero) (nbdkit_next *next, void *handle); + int (*can_fast_zero) (nbdkit_next *next, void *handle); + int (*can_extents) (nbdkit_next *next, void *handle); + int (*can_fua) (nbdkit_next *next, void *handle); + int (*can_multi_conn) (nbdkit_next *next, void *handle); + int (*can_cache) (nbdkit_next *next, void *handle); These intercept the corresponding plugin methods, and control feature bits advertised to the client. @@ -730,7 +727,7 @@ be done from filters, not plugins). Inform nbdkit that write zeroes should immediately fall back to C<.pwrite> emulation without trying C<.zero> (this value is returned -by C<next_ops-E<gt>can_zero> if the plugin returned false in its +by C<next-E<gt>can_zero> if the plugin returned false in its C<.can_zero>). =item C<NBDKIT_ZERO_NATIVE> @@ -738,7 +735,7 @@ C<.can_zero>). Inform nbdkit that write zeroes should attempt to use C<.zero>, although it may still fall back to C<.pwrite> emulation for C<ENOTSUP> or C<EOPNOTSUPP> failures (this value is returned by -C<next_ops-E<gt>can_zero> if the plugin returned true in its +C<next-E<gt>can_zero> if the plugin returned true in its C<.can_zero>). =back @@ -749,25 +746,25 @@ C<.can_cache> have three success values. The difference between C<.can_fua> values may affect choices made in the filter: when splitting a write request that requested FUA from the -client, if C<next_ops-E<gt>can_fua> returns C<NBDKIT_FUA_NATIVE>, then +client, if C<next-E<gt>can_fua> returns C<NBDKIT_FUA_NATIVE>, then the filter should pass the FUA flag on to each sub-request; while if it is known that FUA is emulated by a flush because of a return of C<NBDKIT_FUA_EMULATE>, it is more efficient to only flush once after all sub-requests have completed (often by passing C<NBDKIT_FLAG_FUA> on to only the final sub-request, or by dropping the flag and ending -with a direct call to C<next_ops-E<gt>flush>). +with a direct call to C<next-E<gt>flush>). If there is an error, the callback should call C<nbdkit_error> with an error message and return C<-1>. These functions are called at most once per connection and cached by nbdkit. Similarly, repeated calls to -any of the C<next_ops> counterparts will return a cached value; by +any of the C<nbdkit_next> counterparts will return a cached value; by calling into the plugin during C<.prepare>, you can ensure that later use of the cached values during data commands like <.pwrite> will not fail. =head2 C<.pread> - int (*pread) (struct nbdkit_next_ops *next_ops, void *nxdata, + int (*pread) (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err); @@ -776,7 +773,7 @@ modify data read by the plugin. The parameter C<flags> exists in case of future NBD protocol extensions; at this time, it will be 0 on input, and the filter should -not pass any flags to C<next_ops-E<gt>pread>. +not pass any flags to C<next-E<gt>pread>. 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 @@ -785,7 +782,7 @@ to return to the client. =head2 C<.pwrite> - int (*pwrite) (struct nbdkit_next_ops *next_ops, void *nxdata, + int (*pwrite) (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err); @@ -794,13 +791,13 @@ This intercepts the plugin C<.pwrite> method and can be used to modify data written by the plugin. This function will not be called if C<.can_write> returned false; in -turn, the filter should not call C<next_ops-E<gt>pwrite> if -C<next_ops-E<gt>can_write> did not return true. +turn, the filter should not call C<next-E<gt>pwrite> if +C<next-E<gt>can_write> did not return true. The parameter C<flags> may include C<NBDKIT_FLAG_FUA> on input based on the result of C<.can_fua>. In turn, the filter should only pass -C<NBDKIT_FLAG_FUA> on to C<next_ops-E<gt>pwrite> if -C<next_ops-E<gt>can_fua> returned a positive value. +C<NBDKIT_FLAG_FUA> on to C<next-E<gt>pwrite> if +C<next-E<gt>can_fua> returned a positive value. 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 @@ -809,19 +806,19 @@ to return to the client. =head2 C<.flush> - int (*flush) (struct nbdkit_next_ops *next_ops, void *nxdata, + int (*flush) (nbdkit_next *next, void *handle, uint32_t flags, int *err); This intercepts the plugin C<.flush> method and can be used to modify flush requests. This function will not be called if C<.can_flush> returned false; in -turn, the filter should not call C<next_ops-E<gt>flush> if -C<next_ops-E<gt>can_flush> did not return true. +turn, the filter should not call C<next-E<gt>flush> if +C<next-E<gt>can_flush> did not return true. The parameter C<flags> exists in case of future NBD protocol extensions; at this time, it will be 0 on input, and the filter should -not pass any flags to C<next_ops-E<gt>flush>. +not pass any flags to C<next-E<gt>flush>. If there is an error, C<.flush> should call C<nbdkit_error> with an error message B<and> return -1 with C<err> set to the positive errno @@ -829,7 +826,7 @@ value to return to the client. =head2 C<.trim> - int (*trim) (struct nbdkit_next_ops *next_ops, void *nxdata, + int (*trim) (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err); @@ -837,13 +834,13 @@ This intercepts the plugin C<.trim> method and can be used to modify trim requests. This function will not be called if C<.can_trim> returned false; in -turn, the filter should not call C<next_ops-E<gt>trim> if -C<next_ops-E<gt>can_trim> did not return true. +turn, the filter should not call C<next-E<gt>trim> if +C<next-E<gt>can_trim> did not return true. The parameter C<flags> may include C<NBDKIT_FLAG_FUA> on input based on the result of C<.can_fua>. In turn, the filter should only pass -C<NBDKIT_FLAG_FUA> on to C<next_ops-E<gt>trim> if -C<next_ops-E<gt>can_fua> returned a positive value. +C<NBDKIT_FLAG_FUA> on to C<next-E<gt>trim> if +C<next-E<gt>can_fua> returned a positive value. If there is an error, C<.trim> should call C<nbdkit_error> with an error message B<and> return -1 with C<err> set to the positive errno @@ -851,7 +848,7 @@ value to return to the client. =head2 C<.zero> - int (*zero) (struct nbdkit_next_ops *next_ops, void *nxdata, + int (*zero) (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err); @@ -860,7 +857,7 @@ zero requests. This function will not be called if C<.can_zero> returned C<NBDKIT_ZERO_NONE>; in turn, the filter should not call -C<next_ops-E<gt>zero> if C<next_ops-E<gt>can_zero> returned +C<next-E<gt>zero> if C<next-E<gt>can_zero> returned C<NBDKIT_ZERO_NONE>. On input, the parameter C<flags> may include C<NBDKIT_FLAG_MAY_TRIM> @@ -869,12 +866,12 @@ C<.can_fua>, and C<NBDKIT_FLAG_FAST_ZERO> based on the result of C<.can_fast_zero>. In turn, the filter may pass C<NBDKIT_FLAG_MAY_TRIM> unconditionally, but should only pass C<NBDKIT_FLAG_FUA> or C<NBDKIT_FLAG_FAST_ZERO> on to -C<next_ops-E<gt>zero> if the corresponding C<next_ops-E<gt>can_fua> or -C<next_ops-E<gt>can_fast_zero> returned a positive value. +C<next-E<gt>zero> if the corresponding C<next-E<gt>can_fua> or +C<next-E<gt>can_fast_zero> returned a positive value. Note that unlike the plugin C<.zero> which is permitted to fail with C<ENOTSUP> or C<EOPNOTSUPP> to force a fallback to C<.pwrite>, the -function C<next_ops-E<gt>zero> will not fail with C<err> set to +function C<next-E<gt>zero> will not fail with C<err> set to C<ENOTSUP> or C<EOPNOTSUPP> unless C<NBDKIT_FLAG_FAST_ZERO> was used, because otherwise the fallback has already taken place. @@ -887,7 +884,7 @@ C<.pwrite>, filters do not). =head2 C<.extents> - int (*extents) (struct nbdkit_next_ops *next_ops, void *nxdata, + int (*extents) (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err); @@ -896,8 +893,8 @@ This intercepts the plugin C<.extents> method and can be used to modify extent requests. This function will not be called if C<.can_extents> returned false; in -turn, the filter should not call C<next_ops-E<gt>extents> if -C<next_ops-E<gt>can_extents> did not return true. +turn, the filter should not call C<next-E<gt>extents> if +C<next-E<gt>can_extents> did not return true. It is possible for filters to transform the extents list received back from the layer below. Without error checking it would look like this: @@ -909,9 +906,9 @@ from the layer below. Without error checking it would look like this: struct nbdkit_extent e; int64_t size; - size = next_ops->get_size (nxdata); + size = next->get_size (next); extents2 = nbdkit_extents_new (offset + shift, size); - next_ops->extents (nxdata, count, offset + shift, flags, extents2, err); + next->extents (next, count, offset + shift, flags, extents2, err); for (i = 0; i < nbdkit_extents_count (extents2); ++i) { e = nbdkit_get_extent (extents2, i); e.offset -= shift; @@ -972,8 +969,7 @@ more requests to the underlying plugin until we have a full set of extents covering the region C<[offset..offset+count-1]>. struct nbdkit_extents *nbdkit_extents_full ( - struct nbdkit_next_ops *next_ops, - void *nxdata, + nbdkit_next *next, uint32_t count, uint64_t offset, uint32_t flags, int *err); @@ -992,13 +988,12 @@ be set to a suitable value. A convenience function is provided to filters only which makes it easier to ensure that the client only encounters aligned extents. - int nbdkit_extents_aligned (struct nbdkit_next_ops *next_ops, - void *nxdata, + int nbdkit_extents_aligned (nbdkit_next *next, uint32_t count, uint64_t offset, uint32_t flags, uint32_t align, struct nbdkit_extents *extents, int *err); -Calls next_ops->extents as needed until at least C<align> bytes are +Calls C<next-E<gt>extents> as needed until at least C<align> bytes are obtained, where C<align> is a power of 2. Anywhere the underlying plugin returns differing extents within C<align> bytes, this function treats that portion of the disk as a single extent with zero and @@ -1008,7 +1003,7 @@ C<offset> that is not already aligned. =head2 C<.cache> - int (*cache) (struct nbdkit_next_ops *next_ops, void *nxdata, + int (*cache) (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err); @@ -1017,12 +1012,12 @@ cache requests. This function will not be called if C<.can_cache> returned C<NBDKIT_CACHE_NONE> or C<NBDKIT_CACHE_EMULATE>; in turn, the filter -should not call C<next_ops-E<gt>cache> unless -C<next_ops-E<gt>can_cache> returned C<NBDKIT_CACHE_NATIVE>. +should not call C<next-E<gt>cache> unless +C<next-E<gt>can_cache> returned C<NBDKIT_CACHE_NATIVE>. The parameter C<flags> exists in case of future NBD protocol extensions; at this time, it will be 0 on input, and the filter should -not pass any flags to C<next_ops-E<gt>cache>. +not pass any flags to C<next-E<gt>cache>. If there is an error, C<.cache> should call C<nbdkit_error> with an error message B<and> return -1 with C<err> set to the positive errno diff --git a/include/nbdkit-filter.h b/include/nbdkit-filter.h index a8819c9b..62c9d1a8 100644 --- a/include/nbdkit-filter.h +++ b/include/nbdkit-filter.h @@ -56,14 +56,10 @@ extern "C" { typedef struct backend nbdkit_backend; typedef struct context nbdkit_context; typedef struct context nbdkit_next; -#elif defined NBDKIT_TYPESAFE /* Temporary define while converting filters */ +#else typedef struct nbdkit_backend nbdkit_backend; typedef struct nbdkit_context nbdkit_context; typedef struct nbdkit_next_ops nbdkit_next; -#else -typedef void nbdkit_backend; -typedef void nbdkit_context; -typedef void nbdkit_next; #endif /* Next ops. */ @@ -134,13 +130,11 @@ NBDKIT_EXTERN_DECL (size_t, nbdkit_extents_count, NBDKIT_EXTERN_DECL (struct nbdkit_extent, nbdkit_get_extent, (const struct nbdkit_extents *, size_t)); NBDKIT_EXTERN_DECL (struct nbdkit_extents *, nbdkit_extents_full, - (struct nbdkit_next_ops *next_ops, - nbdkit_next *nxdata, + (nbdkit_next *next, uint32_t count, uint64_t offset, uint32_t flags, int *err)); NBDKIT_EXTERN_DECL (int, nbdkit_extents_aligned, - (struct nbdkit_next_ops *next_ops, - nbdkit_next *nxdata, + (nbdkit_next *next, uint32_t count, uint64_t offset, uint32_t flags, uint32_t align, struct nbdkit_extents *extents, int *err)); @@ -213,56 +207,52 @@ struct nbdkit_filter { int readonly, const char *exportname, int is_tls); void (*close) (void *handle); - int (*prepare) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, + int (*prepare) (nbdkit_next *next, void *handle, int readonly); - int (*finalize) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, + int (*finalize) (nbdkit_next *next, void *handle); - int64_t (*get_size) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, + int64_t (*get_size) (nbdkit_next *next, void *handle); - const char * (*export_description) (struct nbdkit_next_ops *next_ops, - nbdkit_next *nxdata, void *handle); + const char * (*export_description) (nbdkit_next *next, void *handle); - int (*can_write) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, + int (*can_write) (nbdkit_next *next, void *handle); - int (*can_flush) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, + int (*can_flush) (nbdkit_next *next, void *handle); - int (*is_rotational) (struct nbdkit_next_ops *next_ops, - nbdkit_next *nxdata, void *handle); - int (*can_trim) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, + int (*is_rotational) (nbdkit_next *next, void *handle); + int (*can_trim) (nbdkit_next *next, void *handle); - int (*can_zero) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, + int (*can_zero) (nbdkit_next *next, void *handle); - int (*can_fast_zero) (struct nbdkit_next_ops *next_ops, - nbdkit_next *nxdata, void *handle); - int (*can_extents) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, + int (*can_fast_zero) (nbdkit_next *next, void *handle); + int (*can_extents) (nbdkit_next *next, void *handle); - int (*can_fua) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, + int (*can_fua) (nbdkit_next *next, void *handle); - int (*can_multi_conn) (struct nbdkit_next_ops *next_ops, - nbdkit_next *nxdata, void *handle); - int (*can_cache) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, + int (*can_multi_conn) (nbdkit_next *next, void *handle); + int (*can_cache) (nbdkit_next *next, void *handle); - int (*pread) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, + int (*pread) (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err); - int (*pwrite) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, + int (*pwrite) (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err); - int (*flush) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, + int (*flush) (nbdkit_next *next, void *handle, uint32_t flags, int *err); - int (*trim) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, + int (*trim) (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err); - int (*zero) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, + int (*zero) (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err); - int (*extents) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, + int (*extents) (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err); - int (*cache) (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, + int (*cache) (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err); }; diff --git a/server/extents.c b/server/extents.c index 9699fe6a..4b323595 100644 --- a/server/extents.c +++ b/server/extents.c @@ -212,19 +212,19 @@ nbdkit_add_extent (struct nbdkit_extents *exts, /* Compute aligned extents on behalf of a filter. */ int -nbdkit_extents_aligned (struct nbdkit_next_ops *next_ops, - nbdkit_next *nxdata, +nbdkit_extents_aligned (struct context *next_c, uint32_t count, uint64_t offset, uint32_t flags, uint32_t align, struct nbdkit_extents *exts, int *err) { + struct nbdkit_next_ops *next = &next_c->next; size_t i; struct nbdkit_extent *e, *e2; assert (IS_ALIGNED(count | offset, align)); /* Perform an initial query, then scan for the first unaligned extent. */ - if (next_ops->extents (nxdata, count, offset, flags, exts, err) == -1) + if (next->extents (next_c, count, offset, flags, exts, err) == -1) return -1; for (i = 0; i < exts->extents.size; ++i) { e = &exts->extents.ptr[i]; @@ -267,10 +267,10 @@ nbdkit_extents_aligned (struct nbdkit_next_ops *next_ops, *err = errno; return -1; } - if (next_ops->extents (nxdata, align - e->length, - offset + e->length, - flags & ~NBDKIT_FLAG_REQ_ONE, - extents2, err) == -1) + if (next->extents (next_c, align - e->length, + offset + e->length, + flags & ~NBDKIT_FLAG_REQ_ONE, + extents2, err) == -1) return -1; e2 = &extents2->extents.ptr[0]; assert (e2->offset == e->offset + e->length); @@ -298,10 +298,11 @@ nbdkit_extents_aligned (struct nbdkit_next_ops *next_ops, * covering the region [offset..offset+count-1]. */ struct nbdkit_extents * -nbdkit_extents_full (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, +nbdkit_extents_full (struct context *next_c, uint32_t count, uint64_t offset, uint32_t flags, int *err) { + struct nbdkit_next_ops *next = &next_c->next; struct nbdkit_extents *ret; /* Clear REQ_ONE to ask the plugin for as much information as it is @@ -321,7 +322,7 @@ nbdkit_extents_full (struct nbdkit_next_ops *next_ops, nbdkit_next *nxdata, = nbdkit_extents_new (offset, offset+count); if (t == NULL) goto error1; - if (next_ops->extents (nxdata, count, offset, flags, t, err) == -1) + if (next->extents (next_c, count, offset, flags, t, err) == -1) goto error0; for (i = 0; i < nbdkit_extents_count (t); ++i) { diff --git a/server/filters.c b/server/filters.c index d40c928a..41fa20e0 100644 --- a/server/filters.c +++ b/server/filters.c @@ -314,7 +314,7 @@ filter_prepare (struct context *c, int readonly) struct context *c_next = c->c_next; if (f->filter.prepare && - f->filter.prepare (&c_next->next, c_next, c->handle, readonly) == -1) + f->filter.prepare (c_next, c->handle, readonly) == -1) return -1; return 0; @@ -328,7 +328,7 @@ filter_finalize (struct context *c) struct context *c_next = c->c_next; if (f->filter.finalize && - f->filter.finalize (&c_next->next, c_next, c->handle) == -1) + f->filter.finalize (c_next, c->handle) == -1) return -1; return 0; } @@ -341,7 +341,7 @@ filter_export_description (struct context *c) struct context *c_next = c->c_next; if (f->filter.export_description) - return f->filter.export_description (&c_next->next, c_next, c->handle); + return f->filter.export_description (c_next, c->handle); else return backend_export_description (c_next); } @@ -354,7 +354,7 @@ filter_get_size (struct context *c) struct context *c_next = c->c_next; if (f->filter.get_size) - return f->filter.get_size (&c_next->next, c_next, c->handle); + return f->filter.get_size (c_next, c->handle); else return backend_get_size (c_next); } @@ -367,7 +367,7 @@ filter_can_write (struct context *c) struct context *c_next = c->c_next; if (f->filter.can_write) - return f->filter.can_write (&c_next->next, c_next, c->handle); + return f->filter.can_write (c_next, c->handle); else return backend_can_write (c_next); } @@ -380,7 +380,7 @@ filter_can_flush (struct context *c) struct context *c_next = c->c_next; if (f->filter.can_flush) - return f->filter.can_flush (&c_next->next, c_next, c->handle); + return f->filter.can_flush (c_next, c->handle); else return backend_can_flush (c_next); } @@ -393,7 +393,7 @@ filter_is_rotational (struct context *c) struct context *c_next = c->c_next; if (f->filter.is_rotational) - return f->filter.is_rotational (&c_next->next, c_next, c->handle); + return f->filter.is_rotational (c_next, c->handle); else return backend_is_rotational (c_next); } @@ -406,7 +406,7 @@ filter_can_trim (struct context *c) struct context *c_next = c->c_next; if (f->filter.can_trim) - return f->filter.can_trim (&c_next->next, c_next, c->handle); + return f->filter.can_trim (c_next, c->handle); else return backend_can_trim (c_next); } @@ -419,7 +419,7 @@ filter_can_zero (struct context *c) struct context *c_next = c->c_next; if (f->filter.can_zero) - return f->filter.can_zero (&c_next->next, c_next, c->handle); + return f->filter.can_zero (c_next, c->handle); else return backend_can_zero (c_next); } @@ -432,7 +432,7 @@ filter_can_fast_zero (struct context *c) struct context *c_next = c->c_next; if (f->filter.can_fast_zero) - return f->filter.can_fast_zero (&c_next->next, c_next, c->handle); + return f->filter.can_fast_zero (c_next, c->handle); else return backend_can_fast_zero (c_next); } @@ -445,7 +445,7 @@ filter_can_extents (struct context *c) struct context *c_next = c->c_next; if (f->filter.can_extents) - return f->filter.can_extents (&c_next->next, c_next, c->handle); + return f->filter.can_extents (c_next, c->handle); else return backend_can_extents (c_next); } @@ -458,7 +458,7 @@ filter_can_fua (struct context *c) struct context *c_next = c->c_next; if (f->filter.can_fua) - return f->filter.can_fua (&c_next->next, c_next, c->handle); + return f->filter.can_fua (c_next, c->handle); else return backend_can_fua (c_next); } @@ -471,7 +471,7 @@ filter_can_multi_conn (struct context *c) struct context *c_next = c->c_next; if (f->filter.can_multi_conn) - return f->filter.can_multi_conn (&c_next->next, c_next, c->handle); + return f->filter.can_multi_conn (c_next, c->handle); else return backend_can_multi_conn (c_next); } @@ -484,7 +484,7 @@ filter_can_cache (struct context *c) struct context *c_next = c->c_next; if (f->filter.can_cache) - return f->filter.can_cache (&c_next->next, c_next, c->handle); + return f->filter.can_cache (c_next, c->handle); else return backend_can_cache (c_next); } @@ -499,7 +499,7 @@ filter_pread (struct context *c, struct context *c_next = c->c_next; if (f->filter.pread) - return f->filter.pread (&c_next->next, c_next, c->handle, + return f->filter.pread (c_next, c->handle, buf, count, offset, flags, err); else return backend_pread (c_next, buf, count, offset, flags, err); @@ -515,7 +515,7 @@ filter_pwrite (struct context *c, struct context *c_next = c->c_next; if (f->filter.pwrite) - return f->filter.pwrite (&c_next->next, c_next, c->handle, + return f->filter.pwrite (c_next, c->handle, buf, count, offset, flags, err); else return backend_pwrite (c_next, buf, count, offset, flags, err); @@ -530,7 +530,7 @@ filter_flush (struct context *c, struct context *c_next = c->c_next; if (f->filter.flush) - return f->filter.flush (&c_next->next, c_next, c->handle, flags, err); + return f->filter.flush (c_next, c->handle, flags, err); else return backend_flush (c_next, flags, err); } @@ -545,7 +545,7 @@ filter_trim (struct context *c, struct context *c_next = c->c_next; if (f->filter.trim) - return f->filter.trim (&c_next->next, c_next, c->handle, count, offset, + return f->filter.trim (c_next, c->handle, count, offset, flags, err); else return backend_trim (c_next, count, offset, flags, err); @@ -560,7 +560,7 @@ filter_zero (struct context *c, struct context *c_next = c->c_next; if (f->filter.zero) - return f->filter.zero (&c_next->next, c_next, c->handle, + return f->filter.zero (c_next, c->handle, count, offset, flags, err); else return backend_zero (c_next, count, offset, flags, err); @@ -576,7 +576,7 @@ filter_extents (struct context *c, struct context *c_next = c->c_next; if (f->filter.extents) - return f->filter.extents (&c_next->next, c_next, c->handle, + return f->filter.extents (c_next, c->handle, count, offset, flags, extents, err); else @@ -594,7 +594,7 @@ filter_cache (struct context *c, struct context *c_next = c->c_next; if (f->filter.cache) - return f->filter.cache (&c_next->next, c_next, c->handle, + return f->filter.cache (c_next, c->handle, count, offset, flags, err); else return backend_cache (c_next, count, offset, flags, err); diff --git a/filters/cache/blk.h b/filters/cache/blk.h index 84db4cbb..87c753e2 100644 --- a/filters/cache/blk.h +++ b/filters/cache/blk.h @@ -51,20 +51,20 @@ extern int blk_set_size (uint64_t new_size); /* Read a single block from the cache or plugin. If cache_on_read is set, * also ensure it is cached. */ -extern int blk_read (struct nbdkit_next_ops *next_ops, void *nxdata, +extern int blk_read (nbdkit_next *next, uint64_t blknum, uint8_t *block, int *err) - __attribute__((__nonnull__ (1, 4, 5))); + __attribute__((__nonnull__ (1, 3, 4))); /* If a single block is not cached, copy it from the plugin. */ -extern int blk_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +extern int blk_cache (nbdkit_next *next, uint64_t blknum, uint8_t *block, int *err) - __attribute__((__nonnull__ (1, 4, 5))); + __attribute__((__nonnull__ (1, 3, 4))); /* Write to the cache and the plugin. */ -extern int blk_writethrough (struct nbdkit_next_ops *next_ops, void *nxdata, +extern int blk_writethrough (nbdkit_next *next, uint64_t blknum, const uint8_t *block, uint32_t flags, int *err) - __attribute__((__nonnull__ (1, 4, 6))); + __attribute__((__nonnull__ (1, 3, 5))); /* Write a whole block. * @@ -74,10 +74,10 @@ extern int blk_writethrough (struct nbdkit_next_ops *next_ops, void *nxdata, * * Otherwise it will only write to the cache. */ -extern int blk_write (struct nbdkit_next_ops *next_ops, void *nxdata, +extern int blk_write (nbdkit_next *next, uint64_t blknum, const uint8_t *block, uint32_t flags, int *err) - __attribute__((__nonnull__ (1, 4, 6))); + __attribute__((__nonnull__ (1, 3, 5))); /* Iterates over each dirty block in the cache. */ typedef int (*block_callback) (uint64_t blknum, void *vp); diff --git a/filters/cow/blk.h b/filters/cow/blk.h index be3e764a..e6fd7417 100644 --- a/filters/cow/blk.h +++ b/filters/cow/blk.h @@ -51,9 +51,9 @@ extern int blk_set_size (uint64_t new_size); extern void blk_status (uint64_t blknum, bool *present, bool *trimmed); /* Read a single block from the overlay or plugin. */ -extern int blk_read (struct nbdkit_next_ops *next_ops, void *nxdata, +extern int blk_read (nbdkit_next *next, uint64_t blknum, uint8_t *block, int *err) - __attribute__((__nonnull__ (1, 4, 5))); + __attribute__((__nonnull__ (1, 3, 4))); /* Cache mode for blocks not already in overlay */ enum cache_mode { @@ -64,10 +64,10 @@ enum cache_mode { }; /* Cache a single block from the plugin. */ -extern int blk_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +extern int blk_cache (nbdkit_next *next, uint64_t blknum, uint8_t *block, enum cache_mode, int *err) - __attribute__((__nonnull__ (1, 4, 6))); + __attribute__((__nonnull__ (1, 3, 5))); /* Write a single block. */ extern int blk_write (uint64_t blknum, const uint8_t *block, int *err) diff --git a/filters/ext2/io.h b/filters/ext2/io.h index 2112e541..845cffdb 100644 --- a/filters/ext2/io.h +++ b/filters/ext2/io.h @@ -35,7 +35,6 @@ #include <ext2_io.h> -#define NBDKIT_TYPESAFE /* HACK to get type-safe parameters. */ #include <nbdkit-filter.h> #define EXT2_ET_MAGIC_NBDKIT_IO_CHANNEL EXT2_ET_MAGIC_RESERVED_19 diff --git a/filters/partition/partition.h b/filters/partition/partition.h index ba9d50da..432b8eb4 100644 --- a/filters/partition/partition.h +++ b/filters/partition/partition.h @@ -39,10 +39,10 @@ extern unsigned partnum; -extern int find_mbr_partition (struct nbdkit_next_ops *next_ops, void *nxdata, +extern int find_mbr_partition (nbdkit_next *next, int64_t size, uint8_t *mbr, int64_t *offset_r, int64_t *range_r); -extern int find_gpt_partition (struct nbdkit_next_ops *next_ops, void *nxdata, +extern int find_gpt_partition (nbdkit_next *next, int64_t size, uint8_t *header_bytes, int64_t *offset_r, int64_t *range_r); diff --git a/filters/xz/xzfile.h b/filters/xz/xzfile.h index 79a92668..13deb2a5 100644 --- a/filters/xz/xzfile.h +++ b/filters/xz/xzfile.h @@ -40,7 +40,7 @@ typedef struct xzfile xzfile; /* Open (and verify) the named xz file. */ -extern xzfile *xzfile_open (struct nbdkit_next_ops *next_ops, void *nxdata); +extern xzfile *xzfile_open (nbdkit_next *next); /* Close the file and free up all resources. */ extern void xzfile_close (xzfile *); @@ -62,8 +62,8 @@ extern uint64_t xzfile_get_size (xzfile *); * file are returned in *start and *size. */ extern char *xzfile_read_block (xzfile *xz, - struct nbdkit_next_ops *next_ops, - void *nxdata, uint32_t flags, int *err, + nbdkit_next *next, + uint32_t flags, int *err, uint64_t offset, uint64_t *start, uint64_t *size); diff --git a/filters/blocksize/blocksize.c b/filters/blocksize/blocksize.c index 61549522..a6fa00cb 100644 --- a/filters/blocksize/blocksize.c +++ b/filters/blocksize/blocksize.c @@ -85,7 +85,7 @@ blocksize_parse (const char *name, const char *s, unsigned int *v) /* Called for each key=value passed on the command line. */ static int -blocksize_config (nbdkit_next_config *next, void *nxdata, +blocksize_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { @@ -100,7 +100,8 @@ blocksize_config (nbdkit_next_config *next, void *nxdata, /* Check that limits are sane. */ static int -blocksize_config_complete (nbdkit_next_config_complete *next, void *nxdata) +blocksize_config_complete (nbdkit_next_config_complete *next, + nbdkit_backend *nxdata) { if (minblock) { if (minblock & (minblock - 1)) { @@ -145,10 +146,10 @@ blocksize_config_complete (nbdkit_next_config_complete *next, void *nxdata) /* Round size down to avoid issues at end of file. */ static int64_t -blocksize_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, +blocksize_get_size (nbdkit_next *next, void *handle) { - int64_t size = next_ops->get_size (nxdata); + int64_t size = next->get_size (next); if (size == -1) return -1; @@ -156,7 +157,7 @@ blocksize_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, } static int -blocksize_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +blocksize_pread (nbdkit_next *next, void *handle, void *b, uint32_t count, uint64_t offs, uint32_t flags, int *err) { @@ -169,8 +170,7 @@ blocksize_pread (struct nbdkit_next_ops *next_ops, void *nxdata, ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); drop = offs & (minblock - 1); keep = MIN (minblock - drop, count); - if (next_ops->pread (nxdata, bounce, minblock, offs - drop, flags, - err) == -1) + if (next->pread (next, bounce, minblock, offs - drop, flags, err) == -1) return -1; memcpy (buf, bounce + drop, keep); buf += keep; @@ -181,7 +181,7 @@ blocksize_pread (struct nbdkit_next_ops *next_ops, void *nxdata, /* Aligned body */ while (count >= minblock) { keep = MIN (maxdata, ROUND_DOWN (count, minblock)); - if (next_ops->pread (nxdata, buf, keep, offs, flags, err) == -1) + if (next->pread (next, buf, keep, offs, flags, err) == -1) return -1; buf += keep; offs += keep; @@ -191,7 +191,7 @@ blocksize_pread (struct nbdkit_next_ops *next_ops, void *nxdata, /* Unaligned tail */ if (count) { ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); - if (next_ops->pread (nxdata, bounce, minblock, offs, flags, err) == -1) + if (next->pread (next, bounce, minblock, offs, flags, err) == -1) return -1; memcpy (buf, bounce, count); } @@ -200,7 +200,7 @@ blocksize_pread (struct nbdkit_next_ops *next_ops, void *nxdata, } static int -blocksize_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +blocksize_pwrite (nbdkit_next *next, void *handle, const void *b, uint32_t count, uint64_t offs, uint32_t flags, int *err) { @@ -210,7 +210,7 @@ blocksize_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, bool need_flush = false; if ((flags & NBDKIT_FLAG_FUA) && - next_ops->can_fua (nxdata) == NBDKIT_FUA_EMULATE) { + next->can_fua (next) == NBDKIT_FUA_EMULATE) { flags &= ~NBDKIT_FLAG_FUA; need_flush = true; } @@ -220,11 +220,10 @@ blocksize_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); drop = offs & (minblock - 1); keep = MIN (minblock - drop, count); - if (next_ops->pread (nxdata, bounce, minblock, offs - drop, 0, err) == -1) + if (next->pread (next, bounce, minblock, offs - drop, 0, err) == -1) return -1; memcpy (bounce + drop, buf, keep); - if (next_ops->pwrite (nxdata, bounce, minblock, offs - drop, flags, - err) == -1) + if (next->pwrite (next, bounce, minblock, offs - drop, flags, err) == -1) return -1; buf += keep; offs += keep; @@ -234,7 +233,7 @@ blocksize_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, /* Aligned body */ while (count >= minblock) { keep = MIN (maxdata, ROUND_DOWN (count, minblock)); - if (next_ops->pwrite (nxdata, buf, keep, offs, flags, err) == -1) + if (next->pwrite (next, buf, keep, offs, flags, err) == -1) return -1; buf += keep; offs += keep; @@ -244,20 +243,20 @@ blocksize_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, /* Unaligned tail */ if (count) { ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); - if (next_ops->pread (nxdata, bounce, minblock, offs, 0, err) == -1) + if (next->pread (next, bounce, minblock, offs, 0, err) == -1) return -1; memcpy (bounce, buf, count); - if (next_ops->pwrite (nxdata, bounce, minblock, offs, flags, err) == -1) + if (next->pwrite (next, bounce, minblock, offs, flags, err) == -1) return -1; } if (need_flush) - return next_ops->flush (nxdata, 0, err); + return next->flush (next, 0, err); return 0; } static int -blocksize_trim (struct nbdkit_next_ops *next_ops, void *nxdata, +blocksize_trim (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, int *err) { @@ -265,7 +264,7 @@ blocksize_trim (struct nbdkit_next_ops *next_ops, void *nxdata, bool need_flush = false; if ((flags & NBDKIT_FLAG_FUA) && - next_ops->can_fua (nxdata) == NBDKIT_FUA_EMULATE) { + next->can_fua (next) == NBDKIT_FUA_EMULATE) { flags &= ~NBDKIT_FLAG_FUA; need_flush = true; } @@ -283,19 +282,19 @@ blocksize_trim (struct nbdkit_next_ops *next_ops, void *nxdata, /* Aligned body */ while (count) { keep = MIN (maxlen, count); - if (next_ops->trim (nxdata, keep, offs, flags, err) == -1) + if (next->trim (next, keep, offs, flags, err) == -1) return -1; offs += keep; count -= keep; } if (need_flush) - return next_ops->flush (nxdata, 0, err); + return next->flush (next, 0, err); return 0; } static int -blocksize_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +blocksize_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, int *err) { @@ -316,7 +315,7 @@ blocksize_zero (struct nbdkit_next_ops *next_ops, void *nxdata, } if ((flags & NBDKIT_FLAG_FUA) && - next_ops->can_fua (nxdata) == NBDKIT_FUA_EMULATE) { + next->can_fua (next) == NBDKIT_FUA_EMULATE) { flags &= ~NBDKIT_FLAG_FUA; need_flush = true; } @@ -326,11 +325,11 @@ blocksize_zero (struct nbdkit_next_ops *next_ops, void *nxdata, ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); drop = offs & (minblock - 1); keep = MIN (minblock - drop, count); - if (next_ops->pread (nxdata, bounce, minblock, offs - drop, 0, err) == -1) + if (next->pread (next, bounce, minblock, offs - drop, 0, err) == -1) return -1; memset (bounce + drop, 0, keep); - if (next_ops->pwrite (nxdata, bounce, minblock, offs - drop, - flags & ~NBDKIT_FLAG_MAY_TRIM, err) == -1) + if (next->pwrite (next, bounce, minblock, offs - drop, + flags & ~NBDKIT_FLAG_MAY_TRIM, err) == -1) return -1; offs += keep; count -= keep; @@ -339,7 +338,7 @@ blocksize_zero (struct nbdkit_next_ops *next_ops, void *nxdata, /* Aligned body */ while (count >= minblock) { keep = MIN (maxlen, ROUND_DOWN (count, minblock)); - if (next_ops->zero (nxdata, keep, offs, flags, err) == -1) + if (next->zero (next, keep, offs, flags, err) == -1) return -1; offs += keep; count -= keep; @@ -348,21 +347,21 @@ blocksize_zero (struct nbdkit_next_ops *next_ops, void *nxdata, /* Unaligned tail */ if (count) { ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); - if (next_ops->pread (nxdata, bounce, minblock, offs, 0, err) == -1) + if (next->pread (next, bounce, minblock, offs, 0, err) == -1) return -1; memset (bounce, 0, count); - if (next_ops->pwrite (nxdata, bounce, minblock, offs, - flags & ~NBDKIT_FLAG_MAY_TRIM, err) == -1) + if (next->pwrite (next, bounce, minblock, offs, + flags & ~NBDKIT_FLAG_MAY_TRIM, err) == -1) return -1; } if (need_flush) - return next_ops->flush (nxdata, 0, err); + return next->flush (next, 0, err); return 0; } static int -blocksize_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +blocksize_extents (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err) { @@ -383,10 +382,9 @@ blocksize_extents (struct nbdkit_next_ops *next_ops, void *nxdata, return -1; } - if (nbdkit_extents_aligned (next_ops, nxdata, - MIN (ROUND_UP (count, minblock), maxlen), - ROUND_DOWN (offset, minblock), - flags, minblock, extents2, err) == -1) + if (nbdkit_extents_aligned (next, MIN (ROUND_UP (count, minblock), maxlen), + ROUND_DOWN (offset, minblock), flags, minblock, + extents2, err) == -1) return -1; for (i = 0; i < nbdkit_extents_count (extents2); ++i) { @@ -400,7 +398,7 @@ blocksize_extents (struct nbdkit_next_ops *next_ops, void *nxdata, } static int -blocksize_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +blocksize_cache (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, int *err) { @@ -418,7 +416,7 @@ blocksize_cache (struct nbdkit_next_ops *next_ops, void *nxdata, /* Aligned body */ while (remaining) { limit = MIN (maxdata, remaining); - if (next_ops->cache (nxdata, limit, offs, flags, err) == -1) + if (next->cache (next, limit, offs, flags, err) == -1) return -1; offs += limit; remaining -= limit; diff --git a/filters/cache/blk.c b/filters/cache/blk.c index b9af6909..12e8407e 100644 --- a/filters/cache/blk.c +++ b/filters/cache/blk.c @@ -191,7 +191,7 @@ blk_set_size (uint64_t new_size) } int -blk_read (struct nbdkit_next_ops *next_ops, void *nxdata, +blk_read (nbdkit_next *next, uint64_t blknum, uint8_t *block, int *err) { off_t offset = blknum * blksize; @@ -214,7 +214,7 @@ blk_read (struct nbdkit_next_ops *next_ops, void *nxdata, n -= tail; } - if (next_ops->pread (nxdata, block, n, offset, 0, err) == -1) + if (next->pread (next, block, n, offset, 0, err) == -1) return -1; /* Normally we're reading whole blocks, but at the very end of the @@ -251,7 +251,7 @@ blk_read (struct nbdkit_next_ops *next_ops, void *nxdata, } int -blk_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +blk_cache (nbdkit_next *next, uint64_t blknum, uint8_t *block, int *err) { off_t offset = blknum * blksize; @@ -275,7 +275,7 @@ blk_cache (struct nbdkit_next_ops *next_ops, void *nxdata, n -= tail; } - if (next_ops->pread (nxdata, block, n, offset, 0, err) == -1) + if (next->pread (next, block, n, offset, 0, err) == -1) return -1; /* Normally we're reading whole blocks, but at the very end of the @@ -310,7 +310,7 @@ blk_cache (struct nbdkit_next_ops *next_ops, void *nxdata, } int -blk_writethrough (struct nbdkit_next_ops *next_ops, void *nxdata, +blk_writethrough (nbdkit_next *next, uint64_t blknum, const uint8_t *block, uint32_t flags, int *err) { @@ -333,7 +333,7 @@ blk_writethrough (struct nbdkit_next_ops *next_ops, void *nxdata, return -1; } - if (next_ops->pwrite (nxdata, block, n, offset, flags, err) == -1) + if (next->pwrite (next, block, n, offset, flags, err) == -1) return -1; bitmap_set_blk (&bm, blknum, BLOCK_CLEAN); @@ -343,7 +343,7 @@ blk_writethrough (struct nbdkit_next_ops *next_ops, void *nxdata, } int -blk_write (struct nbdkit_next_ops *next_ops, void *nxdata, +blk_write (nbdkit_next *next, uint64_t blknum, const uint8_t *block, uint32_t flags, int *err) { @@ -351,7 +351,7 @@ blk_write (struct nbdkit_next_ops *next_ops, void *nxdata, if (cache_mode == CACHE_MODE_WRITETHROUGH || (cache_mode == CACHE_MODE_WRITEBACK && (flags & NBDKIT_FLAG_FUA))) - return blk_writethrough (next_ops, nxdata, blknum, block, flags, err); + return blk_writethrough (next, blknum, block, flags, err); offset = blknum * blksize; diff --git a/filters/cache/cache.c b/filters/cache/cache.c index cc412e59..499aec68 100644 --- a/filters/cache/cache.c +++ b/filters/cache/cache.c @@ -76,7 +76,8 @@ int64_t max_size = -1; unsigned hi_thresh = 95, lo_thresh = 80; bool cache_on_read = false; -static int cache_flush (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, uint32_t flags, int *err); +static int cache_flush (nbdkit_next *next, void *handle, uint32_t flags, + int *err); static void cache_load (void) @@ -92,7 +93,7 @@ cache_unload (void) } static int -cache_config (nbdkit_next_config *next, void *nxdata, +cache_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { if (strcmp (key, "cache") == 0) { @@ -187,7 +188,8 @@ cache_config (nbdkit_next_config *next, void *nxdata, #endif static int -cache_config_complete (nbdkit_next_config_complete *next, void *nxdata) +cache_config_complete (nbdkit_next_config_complete *next, + nbdkit_backend *nxdata) { /* If cache-max-size was set then check the thresholds. */ if (max_size != -1) { @@ -203,13 +205,13 @@ cache_config_complete (nbdkit_next_config_complete *next, void *nxdata) /* Get the file size, set the cache size. */ static int64_t -cache_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, +cache_get_size (nbdkit_next *next, void *handle) { int64_t size; int r; - size = next_ops->get_size (nxdata); + size = next->get_size (next); if (size == -1) return -1; @@ -228,12 +230,12 @@ cache_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, * calls. */ static int -cache_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, +cache_prepare (nbdkit_next *next, void *handle, int readonly) { int64_t r; - r = cache_get_size (next_ops, nxdata, handle); + r = cache_get_size (next, handle); if (r < 0) return -1; return 0; @@ -241,14 +243,14 @@ cache_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, /* Override the plugin's .can_cache, because we are caching here instead */ static int -cache_can_cache (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) +cache_can_cache (nbdkit_next *next, void *handle) { return NBDKIT_CACHE_NATIVE; } /* Override the plugin's .can_fast_zero, because our .zero is not fast */ static int -cache_can_fast_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +cache_can_fast_zero (nbdkit_next *next, void *handle) { /* It is better to advertise support even when we always reject fast @@ -259,28 +261,28 @@ cache_can_fast_zero (struct nbdkit_next_ops *next_ops, void *nxdata, /* Override the plugin's .can_flush, if we are cache=unsafe */ static int -cache_can_flush (struct nbdkit_next_ops *next_ops, void *nxdata, +cache_can_flush (nbdkit_next *next, void *handle) { if (cache_mode == CACHE_MODE_UNSAFE) return 1; - return next_ops->can_flush (nxdata); + return next->can_flush (next); } /* Override the plugin's .can_fua, if we are cache=unsafe */ static int -cache_can_fua (struct nbdkit_next_ops *next_ops, void *nxdata, +cache_can_fua (nbdkit_next *next, void *handle) { if (cache_mode == CACHE_MODE_UNSAFE) return NBDKIT_FUA_NATIVE; - return next_ops->can_fua (nxdata); + return next->can_fua (next); } /* Override the plugin's .can_multi_conn, if we are not cache=writethrough */ static int -cache_can_multi_conn (struct nbdkit_next_ops *next_ops, void *nxdata, +cache_can_multi_conn (nbdkit_next *next, void *handle) { /* For CACHE_MODE_UNSAFE, we always advertise a no-op flush because @@ -301,12 +303,12 @@ cache_can_multi_conn (struct nbdkit_next_ops *next_ops, void *nxdata, */ if (cache_mode != CACHE_MODE_WRITETHROUGH) return 1; - return next_ops->can_multi_conn (nxdata); + return next->can_multi_conn (next); } /* Read data. */ static int -cache_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +cache_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -333,7 +335,7 @@ cache_pread (struct nbdkit_next_ops *next_ops, void *nxdata, assert (block); ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); - r = blk_read (next_ops, nxdata, blknum, block, err); + r = blk_read (next, blknum, block, err); if (r == -1) return -1; @@ -354,7 +356,7 @@ cache_pread (struct nbdkit_next_ops *next_ops, void *nxdata, */ while (count >= blksize) { ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); - r = blk_read (next_ops, nxdata, blknum, buf, err); + r = blk_read (next, blknum, buf, err); if (r == -1) return -1; @@ -368,7 +370,7 @@ cache_pread (struct nbdkit_next_ops *next_ops, void *nxdata, if (count) { assert (block); ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); - r = blk_read (next_ops, nxdata, blknum, block, err); + r = blk_read (next, blknum, block, err); if (r == -1) return -1; @@ -380,7 +382,7 @@ cache_pread (struct nbdkit_next_ops *next_ops, void *nxdata, /* Write data. */ static int -cache_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +cache_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -400,7 +402,7 @@ cache_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, if ((flags & NBDKIT_FLAG_FUA) && (cache_mode == CACHE_MODE_UNSAFE || - next_ops->can_fua (nxdata) == NBDKIT_FUA_EMULATE)) { + next->can_fua (next) == NBDKIT_FUA_EMULATE)) { flags &= ~NBDKIT_FLAG_FUA; need_flush = true; } @@ -417,10 +419,10 @@ cache_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, */ assert (block); ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); - r = blk_read (next_ops, nxdata, blknum, block, err); + r = blk_read (next, blknum, block, err); if (r != -1) { memcpy (&block[blkoffs], buf, n); - r = blk_write (next_ops, nxdata, blknum, block, flags, err); + r = blk_write (next, blknum, block, flags, err); } if (r == -1) return -1; @@ -434,7 +436,7 @@ cache_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, /* Aligned body */ while (count >= blksize) { ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); - r = blk_write (next_ops, nxdata, blknum, buf, flags, err); + r = blk_write (next, blknum, buf, flags, err); if (r == -1) return -1; @@ -448,23 +450,23 @@ cache_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, if (count) { assert (block); ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); - r = blk_read (next_ops, nxdata, blknum, block, err); + r = blk_read (next, blknum, block, err); if (r != -1) { memcpy (block, buf, count); - r = blk_write (next_ops, nxdata, blknum, block, flags, err); + r = blk_write (next, blknum, block, flags, err); } if (r == -1) return -1; } if (need_flush) - return cache_flush (next_ops, nxdata, handle, 0, err); + return cache_flush (next, handle, 0, err); return 0; } /* Zero data. */ static int -cache_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +cache_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -473,7 +475,7 @@ cache_zero (struct nbdkit_next_ops *next_ops, void *nxdata, int r; bool need_flush = false; - /* We are purposefully avoiding next_ops->zero, so a zero request is + /* We are purposefully avoiding next->zero, so a zero request is * never faster than plain writes. */ if (flags & NBDKIT_FLAG_FAST_ZERO) { @@ -491,7 +493,7 @@ cache_zero (struct nbdkit_next_ops *next_ops, void *nxdata, flags &= ~NBDKIT_FLAG_MAY_TRIM; if ((flags & NBDKIT_FLAG_FUA) && (cache_mode == CACHE_MODE_UNSAFE || - next_ops->can_fua (nxdata) == NBDKIT_FUA_EMULATE)) { + next->can_fua (next) == NBDKIT_FUA_EMULATE)) { flags &= ~NBDKIT_FLAG_FUA; need_flush = true; } @@ -507,10 +509,10 @@ cache_zero (struct nbdkit_next_ops *next_ops, void *nxdata, * Hold the lock over the whole operation. */ ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); - r = blk_read (next_ops, nxdata, blknum, block, err); + r = blk_read (next, blknum, block, err); if (r != -1) { memset (&block[blkoffs], 0, n); - r = blk_write (next_ops, nxdata, blknum, block, flags, err); + r = blk_write (next, blknum, block, flags, err); } if (r == -1) return -1; @@ -524,9 +526,9 @@ cache_zero (struct nbdkit_next_ops *next_ops, void *nxdata, if (count >= blksize) memset (block, 0, blksize); while (count >=blksize) { - /* Intentional that we do not use next_ops->zero */ + /* Intentional that we do not use next->zero */ ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); - r = blk_write (next_ops, nxdata, blknum, block, flags, err); + r = blk_write (next, blknum, block, flags, err); if (r == -1) return -1; @@ -538,17 +540,17 @@ cache_zero (struct nbdkit_next_ops *next_ops, void *nxdata, /* Unaligned tail */ if (count) { ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); - r = blk_read (next_ops, nxdata, blknum, block, err); + r = blk_read (next, blknum, block, err); if (r != -1) { memset (&block[count], 0, blksize - count); - r = blk_write (next_ops, nxdata, blknum, block, flags, err); + r = blk_write (next, blknum, block, flags, err); } if (r == -1) return -1; } if (need_flush) - return cache_flush (next_ops, nxdata, handle, 0, err); + return cache_flush (next, handle, 0, err); return 0; } @@ -557,19 +559,18 @@ struct flush_data { uint8_t *block; /* bounce buffer */ unsigned errors; /* count of errors seen */ int first_errno; /* first errno seen */ - struct nbdkit_next_ops *next_ops; - void *nxdata; + nbdkit_next *next; }; static int flush_dirty_block (uint64_t blknum, void *); static int -cache_flush (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, +cache_flush (nbdkit_next *next, void *handle, uint32_t flags, int *err) { CLEANUP_FREE uint8_t *block = NULL; struct flush_data data - { .errors = 0, .first_errno = 0, .next_ops = next_ops, .nxdata = nxdata }; + { .errors = 0, .first_errno = 0, .next = next }; int tmp; if (cache_mode == CACHE_MODE_UNSAFE) @@ -597,8 +598,7 @@ cache_flush (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, } /* Now issue a flush request to the underlying storage. */ - if (next_ops->flush (nxdata, 0, - data.errors ? &tmp : &data.first_errno) == -1) + if (next->flush (next, 0, data.errors ? &tmp : &data.first_errno) == -1) data.errors++; if (data.errors > 0) { @@ -617,10 +617,10 @@ flush_dirty_block (uint64_t blknum, void *datav) /* Perform a read + writethrough which will read from the * cache and write it through to the underlying storage. */ - if (blk_read (data->next_ops, data->nxdata, blknum, data->block, + if (blk_read (data->next, blknum, data->block, data->errors ? &tmp : &data->first_errno) == -1) goto err; - if (blk_writethrough (data->next_ops, data->nxdata, blknum, data->block, 0, + if (blk_writethrough (data->next, blknum, data->block, 0, data->errors ? &tmp : &data->first_errno) == -1) goto err; @@ -634,7 +634,7 @@ flush_dirty_block (uint64_t blknum, void *datav) /* Cache data. */ static int -cache_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +cache_cache (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -664,7 +664,7 @@ cache_cache (struct nbdkit_next_ops *next_ops, void *nxdata, /* Aligned body */ while (remaining) { ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); - r = blk_cache (next_ops, nxdata, blknum, block, err); + r = blk_cache (next, blknum, block, err); if (r == -1) return -1; diff --git a/filters/cacheextents/cacheextents.c b/filters/cacheextents/cacheextents.c index 95b3c00f..82c5919e 100644 --- a/filters/cacheextents/cacheextents.c +++ b/filters/cacheextents/cacheextents.c @@ -119,7 +119,7 @@ fill (struct nbdkit_extents *extents, int *err) } static int -cacheextents_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +cacheextents_extents (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, @@ -149,7 +149,7 @@ cacheextents_extents (struct nbdkit_next_ops *next_ops, void *nxdata, * costly to provide everything). */ flags &= ~(NBDKIT_FLAG_REQ_ONE); - if (next_ops->extents (nxdata, count, offset, flags, extents, err) == -1) + if (next->extents (next, count, offset, flags, extents, err) == -1) return -1; return fill (extents, err); @@ -170,33 +170,33 @@ kill_cacheextents (void) } static int -cacheextents_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +cacheextents_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { kill_cacheextents (); - return next_ops->pwrite (nxdata, buf, count, offset, flags, err); + return next->pwrite (next, buf, count, offset, flags, err); } static int -cacheextents_trim (struct nbdkit_next_ops *next_ops, void *nxdata, +cacheextents_trim (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { kill_cacheextents (); - return next_ops->trim (nxdata, count, offset, flags, err); + return next->trim (next, count, offset, flags, err); } static int -cacheextents_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +cacheextents_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { kill_cacheextents (); - return next_ops->zero (nxdata, count, offset, flags, err); + return next->zero (next, count, offset, flags, err); } static struct nbdkit_filter filter = { diff --git a/filters/checkwrite/checkwrite.c b/filters/checkwrite/checkwrite.c index 2dc93ab1..e3eea0a4 100644 --- a/filters/checkwrite/checkwrite.c +++ b/filters/checkwrite/checkwrite.c @@ -57,42 +57,42 @@ checkwrite_open (nbdkit_next_open *next, nbdkit_context *nxdata, * write-like operations. */ static int -checkwrite_can_write (struct nbdkit_next_ops *next_ops, void *nxdata, +checkwrite_can_write (nbdkit_next *next, void *handle) { return 1; } static int -checkwrite_can_flush (struct nbdkit_next_ops *next_ops, void *nxdata, +checkwrite_can_flush (nbdkit_next *next, void *handle) { return 1; } static int -checkwrite_can_fua (struct nbdkit_next_ops *next_ops, void *nxdata, +checkwrite_can_fua (nbdkit_next *next, void *handle) { return NBDKIT_FUA_NATIVE; } static int -checkwrite_can_trim (struct nbdkit_next_ops *next_ops, void *nxdata, +checkwrite_can_trim (nbdkit_next *next, void *handle) { return 1; } static int -checkwrite_can_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +checkwrite_can_zero (nbdkit_next *next, void *handle) { return NBDKIT_ZERO_NATIVE; } static int -checkwrite_can_fast_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +checkwrite_can_fast_zero (nbdkit_next *next, void *handle) { /* It is better to advertise support, even if we always reject fast @@ -102,7 +102,7 @@ checkwrite_can_fast_zero (struct nbdkit_next_ops *next_ops, void *nxdata, } static int -checkwrite_can_multi_conn (struct nbdkit_next_ops *next_ops, void *nxdata, +checkwrite_can_multi_conn (nbdkit_next *next, void *handle) { return 1; @@ -118,7 +118,7 @@ data_does_not_match (int *err) /* Provide write-like operations which perform the additional checks. */ static int -checkwrite_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +checkwrite_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -133,7 +133,7 @@ checkwrite_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, } /* Read underlying plugin data into the buffer. */ - if (next_ops->pread (nxdata, expected, count, offset, 0, err) == -1) + if (next->pread (next, expected, count, offset, 0, err) == -1) return -1; /* If data written doesn't match data expected, inject EIO. */ @@ -144,7 +144,7 @@ checkwrite_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, } static int -checkwrite_flush (struct nbdkit_next_ops *next_ops, void *nxdata, +checkwrite_flush (nbdkit_next *next, void *handle, uint32_t flags, int *err) { /* Does nothing, we just have to support it. */ @@ -161,15 +161,15 @@ checkwrite_flush (struct nbdkit_next_ops *next_ops, void *nxdata, * or create a fully allocated target (nbdcopy --allocated). */ static int -checkwrite_trim_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +checkwrite_trim_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { /* If the plugin supports extents, speed this up by using them. */ - if (next_ops->can_extents (nxdata)) { + if (next->can_extents (next)) { size_t i, n; CLEANUP_EXTENTS_FREE struct nbdkit_extents *exts - nbdkit_extents_full (next_ops, nxdata, count, offset, 0, err); + nbdkit_extents_full (next, count, offset, 0, err); if (exts == NULL) return -1; @@ -203,7 +203,7 @@ checkwrite_trim_zero (struct nbdkit_next_ops *next_ops, void *nxdata, return -1; } - if (next_ops->pread (nxdata, buf, buflen, offset, 0, err) == -1) + if (next->pread (next, buf, buflen, offset, 0, err) == -1) return -1; if (! is_zero (buf, buflen)) return data_does_not_match (err); @@ -234,7 +234,7 @@ checkwrite_trim_zero (struct nbdkit_next_ops *next_ops, void *nxdata, while (count > 0) { uint32_t n = MIN (MAX_REQUEST_SIZE, count); - if (next_ops->pread (nxdata, buf, n, offset, 0, err) == -1) + if (next->pread (next, buf, n, offset, 0, err) == -1) return -1; if (! is_zero (buf, n)) return data_does_not_match (err); diff --git a/filters/cow/blk.c b/filters/cow/blk.c index cbd40188..7b088e00 100644 --- a/filters/cow/blk.c +++ b/filters/cow/blk.c @@ -224,7 +224,7 @@ blk_status (uint64_t blknum, bool *present, bool *trimmed) * whole block of size ?blksize?. */ int -blk_read (struct nbdkit_next_ops *next_ops, void *nxdata, +blk_read (nbdkit_next *next, uint64_t blknum, uint8_t *block, int *err) { off_t offset = blknum * BLKSIZE; @@ -252,7 +252,7 @@ blk_read (struct nbdkit_next_ops *next_ops, void *nxdata, n -= tail; } - if (next_ops->pread (nxdata, block, n, offset, 0, err) == -1) + if (next->pread (next, block, n, offset, 0, err) == -1) return -1; /* Normally we're reading whole blocks, but at the very end of the @@ -277,7 +277,7 @@ blk_read (struct nbdkit_next_ops *next_ops, void *nxdata, } int -blk_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +blk_cache (nbdkit_next *next, uint64_t blknum, uint8_t *block, enum cache_mode mode, int *err) { /* XXX Could make this lock more fine-grained with some thought. */ @@ -310,9 +310,9 @@ blk_cache (struct nbdkit_next_ops *next_ops, void *nxdata, if (mode == BLK_CACHE_IGNORE) return 0; if (mode == BLK_CACHE_PASSTHROUGH) - return next_ops->cache (nxdata, n, offset, 0, err); + return next->cache (next, n, offset, 0, err); - if (next_ops->pread (nxdata, block, n, offset, 0, err) == -1) + if (next->pread (next, block, n, offset, 0, err) == -1) return -1; /* Normally we're reading whole blocks, but at the very end of the * file we might read a partial block. Deal with that case by diff --git a/filters/cow/cow.c b/filters/cow/cow.c index 8027f05c..83844845 100644 --- a/filters/cow/cow.c +++ b/filters/cow/cow.c @@ -73,7 +73,7 @@ cow_unload (void) } static int -cow_config (nbdkit_next_config *next, void *nxdata, +cow_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { if (strcmp (key, "cow-on-cache") == 0) { @@ -94,7 +94,7 @@ cow_config (nbdkit_next_config *next, void *nxdata, "cow-on-cache=<BOOL> Set to true to treat client cache requests as writes.\n" static void * -cow_open (nbdkit_next_open *next, void *nxdata, +cow_open (nbdkit_next_open *next, nbdkit_context *nxdata, int readonly, const char *exportname, int is_tls) { /* Always pass readonly=1 to the underlying plugin. */ @@ -106,13 +106,13 @@ cow_open (nbdkit_next_open *next, void *nxdata, /* Get the file size, set the cache size. */ static int64_t -cow_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, +cow_get_size (nbdkit_next *next, void *handle) { int64_t size; int r; - size = next_ops->get_size (nxdata); + size = next->get_size (next); if (size == -1) return -1; @@ -130,59 +130,59 @@ cow_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, * calls. */ static int -cow_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, +cow_prepare (nbdkit_next *next, void *handle, int readonly) { int64_t r; - r = cow_get_size (next_ops, nxdata, handle); + r = cow_get_size (next, handle); return r >= 0 ? 0 : -1; } static int -cow_can_write (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) +cow_can_write (nbdkit_next *next, void *handle) { return 1; } static int -cow_can_trim (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) +cow_can_trim (nbdkit_next *next, void *handle) { return 1; } static int -cow_can_extents (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) +cow_can_extents (nbdkit_next *next, void *handle) { return 1; } static int -cow_can_flush (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) +cow_can_flush (nbdkit_next *next, void *handle) { return 1; } static int -cow_can_fua (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) +cow_can_fua (nbdkit_next *next, void *handle) { return NBDKIT_FUA_NATIVE; } static int -cow_can_cache (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) +cow_can_cache (nbdkit_next *next, void *handle) { - /* Cache next_ops->can_cache now, so later calls to next_ops->cache + /* Cache next->can_cache now, so later calls to next->cache * don't fail, even though we override the answer here. */ - int r = next_ops->can_cache (nxdata); + int r = next->can_cache (next); if (r == -1) return -1; return NBDKIT_CACHE_NATIVE; } static int -cow_can_multi_conn (struct nbdkit_next_ops *next_ops, void *nxdata, +cow_can_multi_conn (nbdkit_next *next, void *handle) { /* Our cache is consistent between connections. */ @@ -191,7 +191,7 @@ cow_can_multi_conn (struct nbdkit_next_ops *next_ops, void *nxdata, /* Override the plugin's .can_fast_zero, because our .zero is not fast */ static int -cow_can_fast_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +cow_can_fast_zero (nbdkit_next *next, void *handle) { /* It is better to advertise support even when we always reject fast @@ -200,11 +200,12 @@ cow_can_fast_zero (struct nbdkit_next_ops *next_ops, void *nxdata, return 1; } -static int cow_flush (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, uint32_t flags, int *err); +static int cow_flush (nbdkit_next *next, void *handle, uint32_t flags, + int *err); /* Read data. */ static int -cow_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +cow_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -229,7 +230,7 @@ cow_pread (struct nbdkit_next_ops *next_ops, void *nxdata, uint64_t n = MIN (BLKSIZE - blkoffs, count); assert (block); - r = blk_read (next_ops, nxdata, blknum, block, err); + r = blk_read (next, blknum, block, err); if (r == -1) return -1; @@ -249,7 +250,7 @@ cow_pread (struct nbdkit_next_ops *next_ops, void *nxdata, * smarter here. */ while (count >= BLKSIZE) { - r = blk_read (next_ops, nxdata, blknum, buf, err); + r = blk_read (next, blknum, buf, err); if (r == -1) return -1; @@ -262,7 +263,7 @@ cow_pread (struct nbdkit_next_ops *next_ops, void *nxdata, /* Unaligned tail */ if (count) { assert (block); - r = blk_read (next_ops, nxdata, blknum, block, err); + r = blk_read (next, blknum, block, err); if (r == -1) return -1; @@ -274,7 +275,7 @@ cow_pread (struct nbdkit_next_ops *next_ops, void *nxdata, /* Write data. */ static int -cow_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +cow_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -303,7 +304,7 @@ cow_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, */ assert (block); ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&rmw_lock); - r = blk_read (next_ops, nxdata, blknum, block, err); + r = blk_read (next, blknum, block, err); if (r != -1) { memcpy (&block[blkoffs], buf, n); r = blk_write (blknum, block, err); @@ -333,7 +334,7 @@ cow_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, if (count) { assert (block); ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&rmw_lock); - r = blk_read (next_ops, nxdata, blknum, block, err); + r = blk_read (next, blknum, block, err); if (r != -1) { memcpy (block, buf, count); r = blk_write (blknum, block, err); @@ -349,7 +350,7 @@ cow_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, /* Zero data. */ static int -cow_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +cow_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -357,7 +358,7 @@ cow_zero (struct nbdkit_next_ops *next_ops, void *nxdata, uint64_t blknum, blkoffs; int r; - /* We are purposefully avoiding next_ops->zero, so a zero request is + /* We are purposefully avoiding next->zero, so a zero request is * never faster than plain writes. */ if (flags & NBDKIT_FLAG_FAST_ZERO) { @@ -383,7 +384,7 @@ cow_zero (struct nbdkit_next_ops *next_ops, void *nxdata, * Hold the rmw_lock over the whole operation. */ ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&rmw_lock); - r = blk_read (next_ops, nxdata, blknum, block, err); + r = blk_read (next, blknum, block, err); if (r != -1) { memset (&block[blkoffs], 0, n); r = blk_write (blknum, block, err); @@ -415,7 +416,7 @@ cow_zero (struct nbdkit_next_ops *next_ops, void *nxdata, /* Unaligned tail */ if (count) { ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&rmw_lock); - r = blk_read (next_ops, nxdata, blknum, block, err); + r = blk_read (next, blknum, block, err); if (r != -1) { memset (&block[count], 0, BLKSIZE - count); r = blk_write (blknum, block, err); @@ -431,7 +432,7 @@ cow_zero (struct nbdkit_next_ops *next_ops, void *nxdata, /* Trim data. */ static int -cow_trim (struct nbdkit_next_ops *next_ops, void *nxdata, +cow_trim (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -459,7 +460,7 @@ cow_trim (struct nbdkit_next_ops *next_ops, void *nxdata, * Hold the lock over the whole operation. */ ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&rmw_lock); - r = blk_read (next_ops, nxdata, blknum, block, err); + r = blk_read (next, blknum, block, err); if (r != -1) { memset (&block[blkoffs], 0, n); r = blk_write (blknum, block, err); @@ -486,7 +487,7 @@ cow_trim (struct nbdkit_next_ops *next_ops, void *nxdata, /* Unaligned tail */ if (count) { ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&rmw_lock); - r = blk_read (next_ops, nxdata, blknum, block, err); + r = blk_read (next, blknum, block, err); if (r != -1) { memset (&block[count], 0, BLKSIZE - count); r = blk_write (blknum, block, err); @@ -501,7 +502,7 @@ cow_trim (struct nbdkit_next_ops *next_ops, void *nxdata, } static int -cow_flush (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, +cow_flush (nbdkit_next *next, void *handle, uint32_t flags, int *err) { /* Deliberately ignored. */ @@ -509,7 +510,7 @@ cow_flush (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, } static int -cow_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +cow_cache (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -519,7 +520,7 @@ cow_cache (struct nbdkit_next_ops *next_ops, void *nxdata, uint64_t remaining = count; /* Rounding out could exceed 32 bits */ enum cache_mode mode; - switch (next_ops->can_cache (nxdata)) { + switch (next->can_cache (next)) { case NBDKIT_CACHE_NONE: mode = BLK_CACHE_IGNORE; break; @@ -555,7 +556,7 @@ cow_cache (struct nbdkit_next_ops *next_ops, void *nxdata, /* Aligned body */ while (remaining) { - r = blk_cache (next_ops, nxdata, blknum, block, mode, err); + r = blk_cache (next, blknum, block, mode, err); if (r == -1) return -1; @@ -569,11 +570,11 @@ cow_cache (struct nbdkit_next_ops *next_ops, void *nxdata, /* Extents. */ static int -cow_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +cow_extents (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err) { - const bool can_extents = next_ops->can_extents (nxdata); + const bool can_extents = next->can_extents (next); const bool req_one = flags & NBDKIT_FLAG_REQ_ONE; uint64_t end; uint64_t blknum; @@ -638,7 +639,7 @@ cow_extents (struct nbdkit_next_ops *next_ops, void *nxdata, } /* Don't ask for extent data beyond the end of the plugin. */ - size = next_ops->get_size (nxdata); + size = next->get_size (next); if (size == -1) return -1; @@ -648,8 +649,7 @@ cow_extents (struct nbdkit_next_ops *next_ops, void *nxdata, } CLEANUP_EXTENTS_FREE struct nbdkit_extents *extents2 - nbdkit_extents_full (next_ops, nxdata, - range_count, range_offset, flags, err); + nbdkit_extents_full (next, range_count, range_offset, flags, err); if (extents2 == NULL) return -1; diff --git a/filters/ddrescue/ddrescue.c b/filters/ddrescue/ddrescue.c index 53a03f8d..7b1c9c1e 100644 --- a/filters/ddrescue/ddrescue.c +++ b/filters/ddrescue/ddrescue.c @@ -137,7 +137,7 @@ ddrescue_unload (void) } static int -ddrescue_config (nbdkit_next_config *next, void *nxdata, +ddrescue_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { if (strcmp (key, "ddrescue-mapfile") == 0) { @@ -159,14 +159,14 @@ ddrescue_config (nbdkit_next_config *next, void *nxdata, * below. */ static int -ddrescue_can_write (struct nbdkit_next_ops *next_ops, void *nxdata, +ddrescue_can_write (nbdkit_next *next, void *handle) { return 0; } static int -ddrescue_can_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +ddrescue_can_cache (nbdkit_next *next, void *handle) { return 0; @@ -174,7 +174,7 @@ ddrescue_can_cache (struct nbdkit_next_ops *next_ops, void *nxdata, /* Read data. */ static int -ddrescue_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +ddrescue_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -186,7 +186,7 @@ ddrescue_pread (struct nbdkit_next_ops *next_ops, void *nxdata, if (offset >= map.ranges.ptr[i].start && offset <= map.ranges.ptr[i].end) { if (offset + count - 1 <= map.ranges.ptr[i].end) { /* entirely contained within this range */ - return next_ops->pread (nxdata, buf, count, offset, flags, err); + return next->pread (next, buf, count, offset, flags, err); } } } diff --git a/filters/delay/delay.c b/filters/delay/delay.c index f440e5a6..7e7fe195 100644 --- a/filters/delay/delay.c +++ b/filters/delay/delay.c @@ -130,7 +130,7 @@ cache_delay (int *err) /* Called for each key=value passed on the command line. */ static int -delay_config (nbdkit_next_config *next, void *nxdata, +delay_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { if (strcmp (key, "rdelay") == 0 || @@ -208,41 +208,41 @@ delay_config (nbdkit_next_config *next, void *nxdata, /* Override the plugin's .can_fast_zero if needed */ static int -delay_can_fast_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +delay_can_fast_zero (nbdkit_next *next, void *handle) { /* Advertise if we are handling fast zero requests locally */ if (delay_zero_ms && !delay_fast_zero) return 1; - return next_ops->can_fast_zero (nxdata); + return next->can_fast_zero (next); } /* Read data. */ static int -delay_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +delay_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { if (read_delay (err) == -1) return -1; - return next_ops->pread (nxdata, buf, count, offset, flags, err); + return next->pread (next, buf, count, offset, flags, err); } /* Write data. */ static int -delay_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +delay_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { if (write_delay (err) == -1) return -1; - return next_ops->pwrite (nxdata, buf, count, offset, flags, err); + return next->pwrite (next, buf, count, offset, flags, err); } /* Zero data. */ static int -delay_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +delay_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -252,40 +252,40 @@ delay_zero (struct nbdkit_next_ops *next_ops, void *nxdata, } if (zero_delay (err) == -1) return -1; - return next_ops->zero (nxdata, count, offset, flags, err); + return next->zero (next, count, offset, flags, err); } /* Trim data. */ static int -delay_trim (struct nbdkit_next_ops *next_ops, void *nxdata, +delay_trim (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { if (trim_delay (err) == -1) return -1; - return next_ops->trim (nxdata, count, offset, flags, err); + return next->trim (next, count, offset, flags, err); } /* Extents. */ static int -delay_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +delay_extents (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err) { if (extents_delay (err) == -1) return -1; - return next_ops->extents (nxdata, count, offset, flags, extents, err); + return next->extents (next, count, offset, flags, extents, err); } /* Cache. */ static int -delay_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +delay_cache (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { if (cache_delay (err) == -1) return -1; - return next_ops->cache (nxdata, count, offset, flags, err); + return next->cache (next, count, offset, flags, err); } static struct nbdkit_filter filter = { diff --git a/filters/error/error.c b/filters/error/error.c index a7ed3f3b..4b513a81 100644 --- a/filters/error/error.c +++ b/filters/error/error.c @@ -155,7 +155,7 @@ parse_error_rate (const char *key, const char *value, double *retp) /* Called for each key=value passed on the command line. */ static int -error_config (nbdkit_next_config *next, void *nxdata, +error_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { int i; @@ -302,19 +302,19 @@ random_error (const struct error_settings *error_settings, /* Read data. */ static int -error_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +error_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { if (random_error (&pread_settings, "pread", err)) return -1; - return next_ops->pread (nxdata, buf, count, offset, flags, err); + return next->pread (next, buf, count, offset, flags, err); } /* Write data. */ static int -error_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +error_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -322,55 +322,55 @@ error_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, if (random_error (&pwrite_settings, "pwrite", err)) return -1; - return next_ops->pwrite (nxdata, buf, count, offset, flags, err); + return next->pwrite (next, buf, count, offset, flags, err); } /* Trim data. */ static int -error_trim (struct nbdkit_next_ops *next_ops, void *nxdata, +error_trim (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { if (random_error (&trim_settings, "trim", err)) return -1; - return next_ops->trim (nxdata, count, offset, flags, err); + return next->trim (next, count, offset, flags, err); } /* Zero data. */ static int -error_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +error_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { if (random_error (&zero_settings, "zero", err)) return -1; - return next_ops->zero (nxdata, count, offset, flags, err); + return next->zero (next, count, offset, flags, err); } /* Extents. */ static int -error_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +error_extents (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err) { if (random_error (&extents_settings, "extents", err)) return -1; - return next_ops->extents (nxdata, count, offset, flags, extents, err); + return next->extents (next, count, offset, flags, extents, err); } /* Extents. */ static int -error_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +error_cache (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { if (random_error (&cache_settings, "cache", err)) return -1; - return next_ops->cache (nxdata, count, offset, flags, err); + return next->cache (next, count, offset, flags, err); } static struct nbdkit_filter filter = { diff --git a/filters/exitwhen/exitwhen.c b/filters/exitwhen/exitwhen.c index 67e87dde..80836357 100644 --- a/filters/exitwhen/exitwhen.c +++ b/filters/exitwhen/exitwhen.c @@ -352,7 +352,7 @@ resume_polling_thread (void) /* Read command line parameters are build events list. */ static int -exitwhen_config (nbdkit_next_config *next, void *nxdata, +exitwhen_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { struct event event; @@ -436,7 +436,7 @@ exitwhen_config (nbdkit_next_config *next, void *nxdata, * then we exit immediately. */ static int -exitwhen_get_ready (nbdkit_next_get_ready *next, void *nxdata, +exitwhen_get_ready (nbdkit_next_get_ready *next, nbdkit_backend *nxdata, int thread_model) { ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); @@ -451,7 +451,7 @@ exitwhen_get_ready (nbdkit_next_get_ready *next, void *nxdata, * polling. */ static int -exitwhen_after_fork (nbdkit_next_after_fork *next, void *nxdata) +exitwhen_after_fork (nbdkit_next_after_fork *next, nbdkit_backend *nxdata) { int err; pthread_t thread; @@ -466,7 +466,8 @@ exitwhen_after_fork (nbdkit_next_after_fork *next, void *nxdata) } static int -exitwhen_preconnect (nbdkit_next_preconnect *next, void *nxdata, int readonly) +exitwhen_preconnect (nbdkit_next_preconnect *next, nbdkit_backend *nxdata, + int readonly) { ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); diff --git a/filters/exportname/exportname.c b/filters/exportname/exportname.c index 164641ba..a4bebf12 100644 --- a/filters/exportname/exportname.c +++ b/filters/exportname/exportname.c @@ -77,7 +77,7 @@ exportname_unload (void) /* Called for each key=value passed on the command line. */ static int -exportname_config (nbdkit_next_config *next, void *nxdata, +exportname_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { int r; @@ -204,7 +204,8 @@ get_desc (const char *name, const char *def) } static int -exportname_list_exports (nbdkit_next_list_exports *next, void *nxdata, +exportname_list_exports (nbdkit_next_list_exports *next, + nbdkit_backend *nxdata, int readonly, int is_tls, struct nbdkit_exports *exps) { @@ -245,7 +246,8 @@ exportname_list_exports (nbdkit_next_list_exports *next, void *nxdata, } static const char * -exportname_default_export (nbdkit_next_default_export *next, void *nxdata, +exportname_default_export (nbdkit_next_default_export *next, + nbdkit_backend *nxdata, int readonly, int is_tls) { size_t i; @@ -269,7 +271,7 @@ struct handle { }; static void * -exportname_open (nbdkit_next_open *next, void *nxdata, +exportname_open (nbdkit_next_open *next, nbdkit_context *nxdata, int readonly, const char *exportname, int is_tls) { size_t i; @@ -313,14 +315,14 @@ exportname_close (void *handle) } static const char * -exportname_export_description (struct nbdkit_next_ops *next_ops, void *nxdata, +exportname_export_description (nbdkit_next *next, void *handle) { struct handle *h = handle; const char *def = NULL; if (desc_mode == DESC_KEEP) - def = next_ops->export_description (nxdata); + def = next->export_description (next); return get_desc (h->name, def); } diff --git a/filters/ext2/ext2.c b/filters/ext2/ext2.c index 9a6eec94..cc80458f 100644 --- a/filters/ext2/ext2.c +++ b/filters/ext2/ext2.c @@ -45,7 +45,6 @@ #define NBDKIT_API_VERSION 2 -#define NBDKIT_TYPESAFE /* HACK to get type-safe parameters. */ #include <nbdkit-filter.h> #include "cleanup.h" @@ -186,8 +185,7 @@ ext2_open (nbdkit_next_open *next, nbdkit_context *nxdata, } static int -ext2_prepare (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle, - int readonly) +ext2_prepare (nbdkit_next *next, void *handle, int readonly) { struct handle *h = handle; errcode_t err; @@ -203,10 +201,10 @@ ext2_prepare (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle, #ifdef EXT2_FLAG_64BITS fs_flags |= EXT2_FLAG_64BITS; #endif - r = next_ops->get_size (nxdata); + r = next->get_size (next); if (r == -1) return -1; - r = next_ops->can_write (nxdata); + r = next->can_write (next); if (r == -1) return -1; if (r == 0) @@ -215,8 +213,8 @@ ext2_prepare (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle, if (!readonly) fs_flags |= EXT2_FLAG_RW; - h->next = next_ops; - name = nbdkit_io_encode (next_ops); + h->next = next; + name = nbdkit_io_encode (next); if (!name) { nbdkit_error ("nbdkit_io_encode: %m"); return -1; @@ -293,21 +291,20 @@ ext2_close (void *handle) } static int -ext2_can_fua (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle) +ext2_can_fua (nbdkit_next *next, void *handle) { return NBDKIT_FUA_NATIVE; } static int -ext2_can_cache (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle) +ext2_can_cache (nbdkit_next *next, void *handle) { /* Let nbdkit call pread to populate the file system cache. */ return NBDKIT_CACHE_EMULATE; } static int -ext2_can_multi_conn (nbdkit_next *next_ops, nbdkit_next *nxdata, - void *handle) +ext2_can_multi_conn (nbdkit_next *next, void *handle) { /* Since we do not permit parallel connections, it does not matter * what we advertise here, and we could just as easily inherit the @@ -320,15 +317,14 @@ ext2_can_multi_conn (nbdkit_next *next_ops, nbdkit_next *nxdata, } static int -ext2_can_flush (nbdkit_next *next_ops, nbdkit_next *nxdata, - void *handle) +ext2_can_flush (nbdkit_next *next, void *handle) { /* Regardless of the underlying plugin, we handle flush at the level * of the filesystem. However, we also need to cache the underlying * plugin ability, since ext2 wants to flush the filesystem into * permanent storage when possible. */ - if (next_ops->can_flush (nxdata) == -1) + if (next->can_flush (next) == -1) return -1; return 1; } @@ -338,23 +334,23 @@ ext2_can_flush (nbdkit_next *next_ops, nbdkit_next *nxdata, * is very obscure. */ static int -ext2_can_zero (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle) +ext2_can_zero (nbdkit_next *next, void *handle) { /* For now, tell nbdkit to call .pwrite instead of any optimization. * However, we also want to cache the underlying plugin support. */ - if (next_ops->can_zero (nxdata) == -1) + if (next->can_zero (next) == -1) return -1; return NBDKIT_ZERO_EMULATE; } static int -ext2_can_trim (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle) +ext2_can_trim (nbdkit_next *next, void *handle) { /* For now, tell nbdkit to never call .trim. However, we also want * to cache the underlying plugin support. */ - if (next_ops->can_trim (nxdata) == -1) + if (next->can_trim (next) == -1) return -1; return 0; } @@ -378,13 +374,12 @@ static int ext2_thread_model (void) /* Description. */ static const char * -ext2_export_description (nbdkit_next *next_ops, nbdkit_next *nxdata, - void *handle) +ext2_export_description (nbdkit_next *next, void *handle) { struct handle *h = handle; const char *fname = file ?: h->exportname; const char *slash = fname[0] == '/' ? "" : "/"; - const char *base = next_ops->export_description (nxdata); + const char *base = next->export_description (next); if (!base) return NULL; @@ -394,7 +389,7 @@ ext2_export_description (nbdkit_next *next_ops, nbdkit_next *nxdata, /* Get the disk size. */ static int64_t -ext2_get_size (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle) +ext2_get_size (nbdkit_next *next, void *handle) { struct handle *h = handle; errcode_t err; @@ -410,7 +405,7 @@ ext2_get_size (nbdkit_next *next_ops, nbdkit_next *nxdata, void *handle) /* Read data. */ static int -ext2_pread (nbdkit_next *next_ops, nbdkit_next *nxdata, +ext2_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *errp) { @@ -447,7 +442,7 @@ ext2_pread (nbdkit_next *next_ops, nbdkit_next *nxdata, /* Write data to the file. */ static int -ext2_pwrite (nbdkit_next *next_ops, nbdkit_next *nxdata, +ext2_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *errp) { @@ -488,7 +483,7 @@ ext2_pwrite (nbdkit_next *next_ops, nbdkit_next *nxdata, } static int -ext2_flush (nbdkit_next *next_ops, nbdkit_next *nxdata, +ext2_flush (nbdkit_next *next, void *handle, uint32_t flags, int *errp) { struct handle *h = handle; diff --git a/filters/extentlist/extentlist.c b/filters/extentlist/extentlist.c index 98b65f9e..c609062c 100644 --- a/filters/extentlist/extentlist.c +++ b/filters/extentlist/extentlist.c @@ -69,7 +69,7 @@ extentlist_unload (void) /* Called for each key=value passed on the command line. */ static int -extentlist_config (nbdkit_next_config *next, void *nxdata, +extentlist_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { if (strcmp (key, "extentlist") == 0) { @@ -85,7 +85,8 @@ extentlist_config (nbdkit_next_config *next, void *nxdata, } static int -extentlist_config_complete (nbdkit_next_config_complete *next, void *nxdata) +extentlist_config_complete (nbdkit_next_config_complete *next, + nbdkit_backend *nxdata) { if (extentlist == NULL) { nbdkit_error ("you must supply the extentlist parameter " @@ -261,7 +262,7 @@ parse_extentlist (void) } static int -extentlist_get_ready (nbdkit_next_get_ready *next, void *nxdata, +extentlist_get_ready (nbdkit_next_get_ready *next, nbdkit_backend *nxdata, int thread_model) { parse_extentlist (); @@ -270,7 +271,7 @@ extentlist_get_ready (nbdkit_next_get_ready *next, void *nxdata, } static int -extentlist_can_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +extentlist_can_extents (nbdkit_next *next, void *handle) { return 1; @@ -281,7 +282,7 @@ int extentlist_debug_lookup = 0; /* Read extents. */ static int -extentlist_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +extentlist_extents (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *ret_extents, diff --git a/filters/fua/fua.c b/filters/fua/fua.c index 229d83db..7f9eb760 100644 --- a/filters/fua/fua.c +++ b/filters/fua/fua.c @@ -51,7 +51,7 @@ static enum FuaMode { } fuamode; static int -fua_config (nbdkit_next_config *next, void *nxdata, +fua_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { if (strcmp (key, "fuamode") == 0) { @@ -82,7 +82,7 @@ fua_config (nbdkit_next_config *next, void *nxdata, /* Check that desired mode is supported by plugin. */ static int -fua_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, +fua_prepare (nbdkit_next *next, void *handle, int readonly) { int r; @@ -97,7 +97,7 @@ fua_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, case DISCARD: break; case EMULATE: - r = next_ops->can_flush (nxdata); + r = next->can_flush (next); if (r == -1) return -1; if (r == 0) { @@ -107,7 +107,7 @@ fua_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, break; case NATIVE: case FORCE: - r = next_ops->can_fua (nxdata); + r = next->can_fua (next); if (r == -1) return -1; if (r == NBDKIT_FUA_NONE) { @@ -122,7 +122,7 @@ fua_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, /* Advertise proper flush support. */ static int -fua_can_flush (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) +fua_can_flush (nbdkit_next *next, void *handle) { switch (fuamode) { case FORCE: @@ -132,14 +132,14 @@ fua_can_flush (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) case EMULATE: case NATIVE: case PASS: - return next_ops->can_flush (nxdata); + return next->can_flush (next); } abort (); } /* Advertise desired fua mode. */ static int -fua_can_fua (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) +fua_can_fua (nbdkit_next *next, void *handle) { switch (fuamode) { case NONE: @@ -151,13 +151,13 @@ fua_can_fua (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) case DISCARD: return NBDKIT_FUA_NATIVE; case PASS: - return next_ops->can_fua (nxdata); + return next->can_fua (next); } abort (); } static int -fua_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +fua_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offs, uint32_t flags, int *err) { @@ -184,14 +184,14 @@ fua_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, flags &= ~NBDKIT_FLAG_FUA; break; } - r = next_ops->pwrite (nxdata, buf, count, offs, flags, err); + r = next->pwrite (next, buf, count, offs, flags, err); if (r != -1 && need_flush) - r = next_ops->flush (nxdata, 0, err); + r = next->flush (next, 0, err); return r; } static int -fua_flush (struct nbdkit_next_ops *next_ops, void *nxdata, +fua_flush (nbdkit_next *next, void *handle, uint32_t flags, int *err) { switch (fuamode) { @@ -203,13 +203,13 @@ fua_flush (struct nbdkit_next_ops *next_ops, void *nxdata, case EMULATE: case NATIVE: case PASS: - return next_ops->flush (nxdata, flags, err); + return next->flush (next, flags, err); } abort (); } static int -fua_trim (struct nbdkit_next_ops *next_ops, void *nxdata, +fua_trim (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, int *err) { @@ -236,14 +236,14 @@ fua_trim (struct nbdkit_next_ops *next_ops, void *nxdata, flags &= ~NBDKIT_FLAG_FUA; break; } - r = next_ops->trim (nxdata, count, offs, flags, err); + r = next->trim (next, count, offs, flags, err); if (r != -1 && need_flush) - r = next_ops->flush (nxdata, 0, err); + r = next->flush (next, 0, err); return r; } static int -fua_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +fua_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, int *err) { @@ -270,9 +270,9 @@ fua_zero (struct nbdkit_next_ops *next_ops, void *nxdata, flags &= ~NBDKIT_FLAG_FUA; break; } - r = next_ops->zero (nxdata, count, offs, flags, err); + r = next->zero (next, count, offs, flags, err); if (r != -1 && need_flush) - r = next_ops->flush (nxdata, 0, err); + r = next->flush (next, 0, err); return r; } diff --git a/filters/gzip/gzip.c b/filters/gzip/gzip.c index 0b3f48b7..dff9634d 100644 --- a/filters/gzip/gzip.c +++ b/filters/gzip/gzip.c @@ -125,7 +125,7 @@ xwrite (const void *buf, size_t count) /* The first thread to call gzip_prepare uncompresses the whole plugin. */ static int -do_uncompress (struct nbdkit_next_ops *next_ops, void *nxdata) +do_uncompress (nbdkit_next *next) { z_stream strm; int zerr; @@ -143,7 +143,7 @@ do_uncompress (struct nbdkit_next_ops *next_ops, void *nxdata) assert (size == -1); /* Get the size of the underlying plugin. */ - compressed_size = next_ops->get_size (nxdata); + compressed_size = next->get_size (next); if (compressed_size == -1) return -1; @@ -207,8 +207,8 @@ do_uncompress (struct nbdkit_next_ops *next_ops, void *nxdata) size_t n = MIN (block_size, compressed_size - strm.total_in); int err = 0; - if (next_ops->pread (nxdata, in_block, (uint32_t) n, strm.total_in, - 0, &err) == -1) { + if (next->pread (next, in_block, (uint32_t)n, strm.total_in, 0, + &err) == -1) { errno = err; return -1; } @@ -248,19 +248,19 @@ do_uncompress (struct nbdkit_next_ops *next_ops, void *nxdata) } static int -gzip_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, +gzip_prepare (nbdkit_next *next, void *handle, int readonly) { ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); if (size >= 0) return 0; - return do_uncompress (next_ops, nxdata); + return do_uncompress (next); } /* Whatever the plugin says, this filter makes it read-only. */ static int -gzip_can_write (struct nbdkit_next_ops *next_ops, void *nxdata, +gzip_can_write (nbdkit_next *next, void *handle) { return 0; @@ -268,7 +268,7 @@ gzip_can_write (struct nbdkit_next_ops *next_ops, void *nxdata, /* Whatever the plugin says, this filter is consistent across connections. */ static int -gzip_can_multi_conn (struct nbdkit_next_ops *next_ops, void *nxdata, +gzip_can_multi_conn (nbdkit_next *next, void *handle) { return 1; @@ -278,7 +278,7 @@ gzip_can_multi_conn (struct nbdkit_next_ops *next_ops, void *nxdata, * supported. */ static int -gzip_can_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +gzip_can_extents (nbdkit_next *next, void *handle) { return 0; @@ -289,7 +289,7 @@ gzip_can_extents (struct nbdkit_next_ops *next_ops, void *nxdata, * behavior of calling .pread for caching. */ static int -gzip_can_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +gzip_can_cache (nbdkit_next *next, void *handle) { return NBDKIT_CACHE_EMULATE; @@ -297,10 +297,10 @@ gzip_can_cache (struct nbdkit_next_ops *next_ops, void *nxdata, /* Description. */ static const char * -gzip_export_description (struct nbdkit_next_ops *next_ops, void *nxdata, +gzip_export_description (nbdkit_next *next, void *handle) { - const char *base = next_ops->export_description (nxdata); + const char *base = next->export_description (next); if (!base) return NULL; @@ -309,7 +309,7 @@ gzip_export_description (struct nbdkit_next_ops *next_ops, void *nxdata, /* Get the file size. */ static int64_t -gzip_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, +gzip_get_size (nbdkit_next *next, void *handle) { int64_t t; @@ -318,7 +318,7 @@ gzip_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, assert (size >= 0); /* Check the plugin size didn't change underneath us. */ - t = next_ops->get_size (nxdata); + t = next->get_size (next); if (t == -1) return -1; if (t != compressed_size) { @@ -333,7 +333,7 @@ gzip_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, /* Read data from the temporary file. */ static int -gzip_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +gzip_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { diff --git a/filters/ip/ip.c b/filters/ip/ip.c index eebb3a24..9c3449ac 100644 --- a/filters/ip/ip.c +++ b/filters/ip/ip.c @@ -399,7 +399,7 @@ parse_rules (const char *paramname, } static int -ip_config (nbdkit_next_config *next, void *nxdata, +ip_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { /* For convenience we permit multiple allow and deny parameters, @@ -420,7 +420,7 @@ ip_config (nbdkit_next_config *next, void *nxdata, } static int -ip_config_complete (nbdkit_next_config_complete *next, void *nxdata) +ip_config_complete (nbdkit_next_config_complete *next, nbdkit_backend *nxdata) { if (ip_debug_rules) { print_rules ("ip: parsed allow", allow_rules); @@ -586,7 +586,8 @@ check_if_allowed (const struct sockaddr *addr) } static int -ip_preconnect (nbdkit_next_preconnect *next, void *nxdata, int readonly) +ip_preconnect (nbdkit_next_preconnect *next, nbdkit_backend *nxdata, + int readonly) { struct sockaddr_storage addr; socklen_t addrlen = sizeof addr; diff --git a/filters/log/log.c b/filters/log/log.c index 7b81a8f1..26358302 100644 --- a/filters/log/log.c +++ b/filters/log/log.c @@ -76,7 +76,7 @@ log_unload (void) /* Called for each key=value passed on the command line. */ static int -log_config (nbdkit_next_config *next, void *nxdata, +log_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { if (strcmp (key, "logfile") == 0) { @@ -103,7 +103,8 @@ log_config (nbdkit_next_config *next, void *nxdata, /* Open the logfile. */ static int -log_get_ready (nbdkit_next_get_ready *next, void *nxdata, int thread_model) +log_get_ready (nbdkit_next_get_ready *next, nbdkit_backend *nxdata, + int thread_model) { int fd; @@ -136,7 +137,7 @@ log_get_ready (nbdkit_next_get_ready *next, void *nxdata, int thread_model) } static int -log_after_fork (nbdkit_next_after_fork *next, void *nxdata) +log_after_fork (nbdkit_next_after_fork *next, nbdkit_backend *nxdata) { /* Only issue this message if we actually fork. */ if (getpid () != saved_pid) @@ -147,7 +148,7 @@ log_after_fork (nbdkit_next_after_fork *next, void *nxdata) /* List exports. */ static int -log_list_exports (nbdkit_next_list_exports *next, void *nxdata, +log_list_exports (nbdkit_next_list_exports *next, nbdkit_backend *nxdata, int readonly, int is_tls, struct nbdkit_exports *exports) { @@ -204,7 +205,7 @@ log_preconnect (nbdkit_next_preconnect *next, nbdkit_backend *nxdata, /* Open a connection. */ static void * -log_open (nbdkit_next_open *next, void *nxdata, +log_open (nbdkit_next_open *next, nbdkit_context *nxdata, int readonly, const char *exportname, int is_tls) { struct handle *h; @@ -242,7 +243,7 @@ log_close (void *handle) } static int -log_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, +log_prepare (nbdkit_next *next, void *handle, int readonly) { FILE *fp; @@ -250,16 +251,16 @@ log_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, size_t len = 0; struct handle *h = handle; const char *exportname = h->exportname; - int64_t size = next_ops->get_size (nxdata); - int w = next_ops->can_write (nxdata); - int f = next_ops->can_flush (nxdata); - int r = next_ops->is_rotational (nxdata); - int t = next_ops->can_trim (nxdata); - int z = next_ops->can_zero (nxdata); - int F = next_ops->can_fua (nxdata); - int e = next_ops->can_extents (nxdata); - int c = next_ops->can_cache (nxdata); - int Z = next_ops->can_fast_zero (nxdata); + int64_t size = next->get_size (next); + int w = next->can_write (next); + int f = next->can_flush (next); + int r = next->is_rotational (next); + int t = next->can_trim (next); + int z = next->can_zero (next); + int F = next->can_fua (next); + int e = next->can_extents (next); + int c = next->can_cache (next); + int Z = next->can_fast_zero (next); if (size < 0 || w < 0 || f < 0 || r < 0 || t < 0 || z < 0 || F < 0 || e < 0 || c < 0 || Z < 0) @@ -284,7 +285,7 @@ log_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, } static int -log_finalize (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) +log_finalize (nbdkit_next *next, void *handle) { struct handle *h = handle; @@ -294,7 +295,7 @@ log_finalize (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) /* Read data. */ static int -log_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +log_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offs, uint32_t flags, int *err) { @@ -304,12 +305,12 @@ log_pread (struct nbdkit_next_ops *next_ops, void *nxdata, LOG (h, "Read", r, err, "offset=0x%" PRIx64 " count=0x%x", offs, count); assert (!flags); - return r = next_ops->pread (nxdata, buf, count, offs, flags, err); + return r = next->pread (next, buf, count, offs, flags, err); } /* Write data. */ static int -log_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +log_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offs, uint32_t flags, int *err) { @@ -321,12 +322,12 @@ log_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, offs, count, !!(flags & NBDKIT_FLAG_FUA)); assert (!(flags & ~NBDKIT_FLAG_FUA)); - return r = next_ops->pwrite (nxdata, buf, count, offs, flags, err); + return r = next->pwrite (next, buf, count, offs, flags, err); } /* Flush. */ static int -log_flush (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, +log_flush (nbdkit_next *next, void *handle, uint32_t flags, int *err) { struct handle *h = handle; @@ -335,12 +336,12 @@ log_flush (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, LOG (h, "Flush", r, err, ""); assert (!flags); - return r = next_ops->flush (nxdata, flags, err); + return r = next->flush (next, flags, err); } /* Trim data. */ static int -log_trim (struct nbdkit_next_ops *next_ops, void *nxdata, +log_trim (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, int *err) { @@ -352,12 +353,12 @@ log_trim (struct nbdkit_next_ops *next_ops, void *nxdata, offs, count, !!(flags & NBDKIT_FLAG_FUA)); assert (!(flags & ~NBDKIT_FLAG_FUA)); - return r = next_ops->trim (nxdata, count, offs, flags, err); + return r = next->trim (next, count, offs, flags, err); } /* Zero data. */ static int -log_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +log_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, int *err) { @@ -372,12 +373,12 @@ log_zero (struct nbdkit_next_ops *next_ops, void *nxdata, assert (!(flags & ~(NBDKIT_FLAG_FUA | NBDKIT_FLAG_MAY_TRIM | NBDKIT_FLAG_FAST_ZERO))); - return r = next_ops->zero (nxdata, count, offs, flags, err); + return r = next->zero (next, count, offs, flags, err); } /* Extents. */ static int -log_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +log_extents (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, struct nbdkit_extents *extents, int *err) { @@ -389,7 +390,7 @@ log_extents (struct nbdkit_next_ops *next_ops, void *nxdata, enter (h, id, "Extents", "offset=0x%" PRIx64 " count=0x%x req_one=%d", offs, count, !!(flags & NBDKIT_FLAG_REQ_ONE)); - r = next_ops->extents (nxdata, count, offs, flags, extents, err); + r = next->extents (next, count, offs, flags, extents, err); if (r == -1) leave_simple (h, id, "Extents", r, err); else { @@ -430,7 +431,7 @@ log_extents (struct nbdkit_next_ops *next_ops, void *nxdata, /* Cache data. */ static int -log_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +log_cache (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, int *err) { @@ -440,7 +441,7 @@ log_cache (struct nbdkit_next_ops *next_ops, void *nxdata, LOG (h, "Cache", r, err, "offset=0x%" PRIx64 " count=0x%x", offs, count); assert (!flags); - return r = next_ops->cache (nxdata, count, offs, flags, err); + return r = next->cache (next, count, offs, flags, err); } static struct nbdkit_filter filter = { diff --git a/filters/nocache/nocache.c b/filters/nocache/nocache.c index fe11243e..169fc37d 100644 --- a/filters/nocache/nocache.c +++ b/filters/nocache/nocache.c @@ -50,7 +50,7 @@ static enum CacheMode { } cachemode; static int -nocache_config (nbdkit_next_config *next, void *nxdata, +nocache_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { if (strcmp (key, "cachemode") == 0) { @@ -73,7 +73,7 @@ nocache_config (nbdkit_next_config *next, void *nxdata, /* Advertise desired FLAG_SEND_CACHE mode. */ static int -nocache_can_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +nocache_can_cache (nbdkit_next *next, void *handle) { switch (cachemode) { @@ -88,7 +88,7 @@ nocache_can_cache (struct nbdkit_next_ops *next_ops, void *nxdata, } static int -nocache_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +nocache_cache (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, int *err) { diff --git a/filters/noextents/noextents.c b/filters/noextents/noextents.c index e6ac33b2..f3044809 100644 --- a/filters/noextents/noextents.c +++ b/filters/noextents/noextents.c @@ -35,7 +35,7 @@ #include <nbdkit-filter.h> static int -noextents_can_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +noextents_can_extents (nbdkit_next *next, void *handle) { return 0; diff --git a/filters/noparallel/noparallel.c b/filters/noparallel/noparallel.c index f9006c06..1a24b106 100644 --- a/filters/noparallel/noparallel.c +++ b/filters/noparallel/noparallel.c @@ -44,7 +44,7 @@ static int thread_model = NBDKIT_THREAD_MODEL_SERIALIZE_REQUESTS; static int -noparallel_config (nbdkit_next_config *next, void *nxdata, +noparallel_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { if (strcmp (key, "serialize") == 0 || diff --git a/filters/nozero/nozero.c b/filters/nozero/nozero.c index 22d5914c..7c5d67c4 100644 --- a/filters/nozero/nozero.c +++ b/filters/nozero/nozero.c @@ -66,7 +66,7 @@ static enum FastZeroMode { } fastzeromode; static int -nozero_config (nbdkit_next_config *next, void *nxdata, +nozero_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { if (strcmp (key, "zeromode") == 0) { @@ -106,7 +106,7 @@ nozero_config (nbdkit_next_config *next, void *nxdata, /* Check that desired mode is supported by plugin. */ static int -nozero_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, +nozero_prepare (nbdkit_next *next, void *handle, int readonly) { int r; @@ -116,7 +116,7 @@ nozero_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, return 0; if (zeromode == NOTRIM || zeromode == PLUGIN) { - r = next_ops->can_zero (nxdata); + r = next->can_zero (next); if (r == -1) return -1; if (!r) { @@ -130,7 +130,7 @@ nozero_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, /* Advertise desired WRITE_ZEROES mode. */ static int -nozero_can_zero (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) +nozero_can_zero (nbdkit_next *next, void *handle) { switch (zeromode) { case NONE: @@ -138,24 +138,24 @@ nozero_can_zero (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) case EMULATE: return NBDKIT_ZERO_EMULATE; default: - return next_ops->can_zero (nxdata); + return next->can_zero (next); } } /* Advertise desired FAST_ZERO mode. */ static int -nozero_can_fast_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +nozero_can_fast_zero (nbdkit_next *next, void *handle) { if (zeromode == NONE) return 0; if (zeromode != EMULATE && fastzeromode == DEFAULT) - return next_ops->can_fast_zero (nxdata); + return next->can_fast_zero (next); return fastzeromode != NOFAST; } static int -nozero_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +nozero_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, int *err) { @@ -178,10 +178,10 @@ nozero_zero (struct nbdkit_next_ops *next_ops, void *nxdata, flags &= ~NBDKIT_FLAG_MAY_TRIM; if (zeromode != EMULATE) - return next_ops->zero (nxdata, count, offs, flags, err); + return next->zero (next, count, offs, flags, err); if (flags & NBDKIT_FLAG_FUA) { - if (next_ops->can_fua (nxdata) == NBDKIT_FUA_EMULATE) + if (next->can_fua (next) == NBDKIT_FUA_EMULATE) need_flush = true; else writeflags = NBDKIT_FLAG_FUA; @@ -197,7 +197,7 @@ nozero_zero (struct nbdkit_next_ops *next_ops, void *nxdata, if (size == count && need_flush) writeflags = NBDKIT_FLAG_FUA; - if (next_ops->pwrite (nxdata, buffer, size, offs, writeflags, err) == -1) + if (next->pwrite (next, buffer, size, offs, writeflags, err) == -1) return -1; offs += size; count -= size; diff --git a/filters/offset/offset.c b/filters/offset/offset.c index ae1ce230..ff0b858c 100644 --- a/filters/offset/offset.c +++ b/filters/offset/offset.c @@ -46,7 +46,7 @@ static int64_t offset = 0, range = -1; /* Called for each key=value passed on the command line. */ static int -offset_config (nbdkit_next_config *next, void *nxdata, +offset_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { if (strcmp (key, "offset") == 0) { @@ -71,10 +71,10 @@ offset_config (nbdkit_next_config *next, void *nxdata, /* Get the file size. */ static int64_t -offset_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, +offset_get_size (nbdkit_next *next, void *handle) { - int64_t real_size = next_ops->get_size (nxdata); + int64_t real_size = next->get_size (next); if (real_size == -1) return -1; @@ -102,59 +102,58 @@ offset_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, /* Read data. */ static int -offset_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +offset_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offs, uint32_t flags, int *err) { - return next_ops->pread (nxdata, buf, count, offs + offset, flags, err); + return next->pread (next, buf, count, offs + offset, flags, err); } /* Write data. */ static int -offset_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +offset_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offs, uint32_t flags, int *err) { - return next_ops->pwrite (nxdata, buf, count, offs + offset, flags, err); + return next->pwrite (next, buf, count, offs + offset, flags, err); } /* Trim data. */ static int -offset_trim (struct nbdkit_next_ops *next_ops, void *nxdata, +offset_trim (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, int *err) { - return next_ops->trim (nxdata, count, offs + offset, flags, err); + return next->trim (next, count, offs + offset, flags, err); } /* Zero data. */ static int -offset_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +offset_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, int *err) { - return next_ops->zero (nxdata, count, offs + offset, flags, err); + return next->zero (next, count, offs + offset, flags, err); } /* Extents. */ static int -offset_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +offset_extents (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, struct nbdkit_extents *extents, int *err) { size_t i; CLEANUP_EXTENTS_FREE struct nbdkit_extents *extents2 = NULL; struct nbdkit_extent e; - int64_t end = range >= 0 ? offset + range : next_ops->get_size (nxdata); + int64_t end = range >= 0 ? offset + range : next->get_size (next); extents2 = nbdkit_extents_new (offs + offset, end); if (extents2 == NULL) { *err = errno; return -1; } - if (next_ops->extents (nxdata, count, offs + offset, - flags, extents2, err) == -1) + if (next->extents (next, count, offs + offset, flags, extents2, err) == -1) return -1; for (i = 0; i < nbdkit_extents_count (extents2); ++i) { @@ -170,11 +169,11 @@ offset_extents (struct nbdkit_next_ops *next_ops, void *nxdata, /* Cache data. */ static int -offset_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +offset_cache (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, int *err) { - return next_ops->cache (nxdata, count, offs + offset, flags, err); + return next->cache (next, count, offs + offset, flags, err); } static struct nbdkit_filter filter = { diff --git a/filters/partition/partition-gpt.c b/filters/partition/partition-gpt.c index f2ff2116..555483c3 100644 --- a/filters/partition/partition-gpt.c +++ b/filters/partition/partition-gpt.c @@ -66,7 +66,7 @@ get_gpt_partition (uint8_t *bytes, } int -find_gpt_partition (struct nbdkit_next_ops *next_ops, void *nxdata, +find_gpt_partition (nbdkit_next *next, int64_t size, uint8_t *header_bytes, int64_t *offset_r, int64_t *range_r) { @@ -100,9 +100,8 @@ find_gpt_partition (struct nbdkit_next_ops *next_ops, void *nxdata, for (i = 0; i < nr_partition_entries; ++i) { /* We already checked these are within bounds above. */ - if (next_ops->pread (nxdata, partition_bytes, sizeof partition_bytes, - 2*SECTOR_SIZE + i*size_partition_entry, 0, - &err) == -1) + if (next->pread (next, partition_bytes, sizeof partition_bytes, + 2 * SECTOR_SIZE + i * size_partition_entry, 0, &err) == -1) return -1; get_gpt_partition (partition_bytes, partition_type_guid, &first_lba, &last_lba); diff --git a/filters/partition/partition-mbr.c b/filters/partition/partition-mbr.c index 22532eff..d964e0c6 100644 --- a/filters/partition/partition-mbr.c +++ b/filters/partition/partition-mbr.c @@ -68,7 +68,7 @@ get_mbr_partition (uint8_t *sector, int i, struct mbr_partition *part) } int -find_mbr_partition (struct nbdkit_next_ops *next_ops, void *nxdata, +find_mbr_partition (nbdkit_next *next, int64_t size, uint8_t *mbr, int64_t *offset_r, int64_t *range_r) { @@ -132,8 +132,7 @@ find_mbr_partition (struct nbdkit_next_ops *next_ops, void *nxdata, /* Read the EBR sector. */ nbdkit_debug ("partition: reading EBR at %" PRIi64, ebr); - if (next_ops->pread (nxdata, sector, sizeof sector, ebr, 0, - &errno) == -1) + if (next->pread (next, sector, sizeof sector, ebr, 0, &errno) == -1) return -1; if (partnum == i) { diff --git a/filters/partition/partition.c b/filters/partition/partition.c index d897b374..4f91d04b 100644 --- a/filters/partition/partition.c +++ b/filters/partition/partition.c @@ -50,7 +50,7 @@ unsigned partnum = 0; /* Called for each key=value passed on the command line. */ static int -partition_config (nbdkit_next_config *next, void *nxdata, +partition_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { if (strcmp (key, "partition") == 0) { @@ -68,7 +68,8 @@ partition_config (nbdkit_next_config *next, void *nxdata, /* Check the user did pass partition number. */ static int -partition_config_complete (nbdkit_next_config_complete *next, void *nxdata) +partition_config_complete (nbdkit_next_config_complete *next, + nbdkit_backend *nxdata) { if (partnum == 0) { nbdkit_error ("you must supply the partition parameter on the command line"); @@ -89,7 +90,7 @@ struct handle { /* Open a connection. */ static void * -partition_open (nbdkit_next_open *next, void *nxdata, +partition_open (nbdkit_next_open *next, nbdkit_context *nxdata, int readonly, const char *exportname, int is_tls) { struct handle *h; @@ -117,7 +118,7 @@ partition_close (void *handle) } static int -partition_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, +partition_prepare (nbdkit_next *next, void *handle, int readonly) { struct handle *h = handle; @@ -126,7 +127,7 @@ partition_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, int r; int err; - size = next_ops->get_size (nxdata); + size = next->get_size (next); if (size == -1) return -1; if (size < 2 * SECTOR_SIZE) { @@ -136,20 +137,19 @@ partition_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, nbdkit_debug ("disk size=%" PRIi64, size); - if (next_ops->pread (nxdata, lba01, sizeof lba01, 0, 0, &err) == -1) + if (next->pread (next, lba01, sizeof lba01, 0, 0, &err) == -1) return -1; /* Is it GPT? */ if (size >= 2 * 34 * SECTOR_SIZE && memcmp (&lba01[SECTOR_SIZE], "EFI PART", 8) == 0) { - r = find_gpt_partition (next_ops, nxdata, size, &lba01[SECTOR_SIZE], - &h->offset, &h->range); + r = find_gpt_partition (next, size, &lba01[SECTOR_SIZE], &h->offset, + &h->range); h->type = "GPT"; } /* Is it MBR? */ else if (lba01[0x1fe] == 0x55 && lba01[0x1ff] == 0xAA) { - r = find_mbr_partition (next_ops, nxdata, size, lba01, - &h->offset, &h->range); + r = find_mbr_partition (next, size, lba01, &h->offset, &h->range); h->type = "MBR"; } else { @@ -176,11 +176,11 @@ partition_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, /* Description. */ static const char * -partition_export_description (struct nbdkit_next_ops *next_ops, void *nxdata, +partition_export_description (nbdkit_next *next, void *handle) { struct handle *h = handle; - const char *base = next_ops->export_description (nxdata); + const char *base = next->export_description (next); assert (h->type); if (!base) @@ -191,7 +191,7 @@ partition_export_description (struct nbdkit_next_ops *next_ops, void *nxdata, /* Get the file size. */ static int64_t -partition_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, +partition_get_size (nbdkit_next *next, void *handle) { struct handle *h = handle; @@ -201,52 +201,52 @@ partition_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, /* Read data. */ static int -partition_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +partition_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offs, uint32_t flags, int *err) { struct handle *h = handle; - return next_ops->pread (nxdata, buf, count, offs + h->offset, flags, err); + return next->pread (next, buf, count, offs + h->offset, flags, err); } /* Write data. */ static int -partition_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +partition_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offs, uint32_t flags, int *err) { struct handle *h = handle; - return next_ops->pwrite (nxdata, buf, count, offs + h->offset, flags, err); + return next->pwrite (next, buf, count, offs + h->offset, flags, err); } /* Trim data. */ static int -partition_trim (struct nbdkit_next_ops *next_ops, void *nxdata, +partition_trim (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, int *err) { struct handle *h = handle; - return next_ops->trim (nxdata, count, offs + h->offset, flags, err); + return next->trim (next, count, offs + h->offset, flags, err); } /* Zero data. */ static int -partition_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +partition_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, int *err) { struct handle *h = handle; - return next_ops->zero (nxdata, count, offs + h->offset, flags, err); + return next->zero (next, count, offs + h->offset, flags, err); } /* Extents. */ static int -partition_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +partition_extents (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, struct nbdkit_extents *extents, int *err) { @@ -260,8 +260,8 @@ partition_extents (struct nbdkit_next_ops *next_ops, void *nxdata, *err = errno; return -1; } - if (next_ops->extents (nxdata, count, offs + h->offset, - flags, extents2, err) == -1) + if (next->extents (next, count, offs + h->offset, flags, extents2, + err) == -1) return -1; for (i = 0; i < nbdkit_extents_count (extents2); ++i) { @@ -277,13 +277,13 @@ partition_extents (struct nbdkit_next_ops *next_ops, void *nxdata, /* Cache data. */ static int -partition_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +partition_cache (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, int *err) { struct handle *h = handle; - return next_ops->cache (nxdata, count, offs + h->offset, flags, err); + return next->cache (next, count, offs + h->offset, flags, err); } static struct nbdkit_filter filter = { diff --git a/filters/pause/pause.c b/filters/pause/pause.c index 62d44391..90511b93 100644 --- a/filters/pause/pause.c +++ b/filters/pause/pause.c @@ -64,7 +64,7 @@ pause_unload (void) } static int -pause_config (nbdkit_next_config *next, void *nxdata, +pause_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { if (strcmp (key, "pause-control") == 0) { @@ -79,7 +79,8 @@ pause_config (nbdkit_next_config *next, void *nxdata, } static int -pause_config_complete (nbdkit_next_config_complete *next, void *nxdata) +pause_config_complete (nbdkit_next_config_complete *next, + nbdkit_backend *nxdata) { size_t len; struct sockaddr_un addr; @@ -230,7 +231,7 @@ control_socket_thread (void *arg) /* Start the background thread after fork. */ static int -pause_after_fork (nbdkit_next_after_fork *next, void *nxdata) +pause_after_fork (nbdkit_next_after_fork *next, nbdkit_backend *nxdata) { int err; pthread_t thread; @@ -267,21 +268,21 @@ end_request (void) /* Read data. */ static int -pause_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +pause_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { int r; begin_request (); - r = next_ops->pread (nxdata, buf, count, offset, flags, err); + r = next->pread (next, buf, count, offset, flags, err); end_request (); return r; } /* Write data. */ static int -pause_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +pause_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -289,63 +290,63 @@ pause_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, int r; begin_request (); - r = next_ops->pwrite (nxdata, buf, count, offset, flags, err); + r = next->pwrite (next, buf, count, offset, flags, err); end_request (); return r; } /* Zero data. */ static int -pause_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +pause_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { int r; begin_request (); - r = next_ops->zero (nxdata, count, offset, flags, err); + r = next->zero (next, count, offset, flags, err); end_request (); return r; } /* Trim data. */ static int -pause_trim (struct nbdkit_next_ops *next_ops, void *nxdata, +pause_trim (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { int r; begin_request (); - r = next_ops->trim (nxdata, count, offset, flags, err); + r = next->trim (next, count, offset, flags, err); end_request (); return r; } /* Extents. */ static int -pause_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +pause_extents (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err) { int r; begin_request (); - r = next_ops->extents (nxdata, count, offset, flags, extents, err); + r = next->extents (next, count, offset, flags, extents, err); end_request (); return r; } /* Cache. */ static int -pause_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +pause_cache (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { int r; begin_request (); - r = next_ops->cache (nxdata, count, offset, flags, err); + r = next->cache (next, count, offset, flags, err); end_request (); return r; } diff --git a/filters/rate/rate.c b/filters/rate/rate.c index 103eae0b..7b07b5bf 100644 --- a/filters/rate/rate.c +++ b/filters/rate/rate.c @@ -97,7 +97,7 @@ rate_unload (void) /* Called for each key=value passed on the command line. */ static int -rate_config (nbdkit_next_config *next, void *nxdata, +rate_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { if (strcmp (key, "rate") == 0) { @@ -147,7 +147,8 @@ rate_config (nbdkit_next_config *next, void *nxdata, } static int -rate_get_ready (nbdkit_next_get_ready *next, void *nxdata, int thread_model) +rate_get_ready (nbdkit_next_get_ready *next, nbdkit_backend *nxdata, + int thread_model) { /* Initialize the global buckets. */ bucket_init (&read_bucket, rate, BUCKET_CAPACITY); @@ -164,7 +165,7 @@ rate_get_ready (nbdkit_next_get_ready *next, void *nxdata, int thread_model) /* Create the per-connection handle. */ static void * -rate_open (nbdkit_next_open *next, void *nxdata, +rate_open (nbdkit_next_open *next, nbdkit_context *nxdata, int readonly, const char *exportname, int is_tls) { struct rate_handle *h; @@ -275,7 +276,7 @@ maybe_sleep (struct bucket *bucket, pthread_mutex_t *lock, uint32_t count, /* Read data. */ static int -rate_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +rate_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -288,12 +289,12 @@ rate_pread (struct nbdkit_next_ops *next_ops, void *nxdata, if (maybe_sleep (&h->read_bucket, &h->read_bucket_lock, count, err)) return -1; - return next_ops->pread (nxdata, buf, count, offset, flags, err); + return next->pread (next, buf, count, offset, flags, err); } /* Write data. */ static int -rate_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +rate_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -307,7 +308,7 @@ rate_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, if (maybe_sleep (&h->write_bucket, &h->write_bucket_lock, count, err)) return -1; - return next_ops->pwrite (nxdata, buf, count, offset, flags, err); + return next->pwrite (next, buf, count, offset, flags, err); } static struct nbdkit_filter filter = { diff --git a/filters/readahead/readahead.c b/filters/readahead/readahead.c index f0e67a67..bb6f55c7 100644 --- a/filters/readahead/readahead.c +++ b/filters/readahead/readahead.c @@ -76,28 +76,27 @@ readahead_unload (void) free (buffer); } -static int64_t readahead_get_size (struct nbdkit_next_ops *next_ops, - void *nxdata, void *handle); +static int64_t readahead_get_size (nbdkit_next *next, void *handle); /* In prepare, force a call to get_size which sets the size global. */ static int -readahead_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, +readahead_prepare (nbdkit_next *next, void *handle, int readonly) { int64_t r; - r = readahead_get_size (next_ops, nxdata, handle); + r = readahead_get_size (next, handle); return r >= 0 ? 0 : -1; } /* Get the size. */ static int64_t -readahead_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, +readahead_get_size (nbdkit_next *next, void *handle) { int64_t r; - r = next_ops->get_size (nxdata); + r = next->get_size (next); if (r == -1) return -1; @@ -109,7 +108,7 @@ readahead_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, /* Cache */ static int -readahead_can_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +readahead_can_cache (nbdkit_next *next, void *handle) { /* We are already operating as a cache regardless of the plugin's @@ -122,7 +121,7 @@ readahead_can_cache (struct nbdkit_next_ops *next_ops, void *nxdata, /* Read data. */ static int -fill_readahead (struct nbdkit_next_ops *next_ops, void *nxdata, +fill_readahead (nbdkit_next *next, uint32_t count, uint64_t offset, uint32_t flags, int *err) { position = offset; @@ -147,7 +146,7 @@ fill_readahead (struct nbdkit_next_ops *next_ops, void *nxdata, bufsize = length; } - if (next_ops->pread (nxdata, buffer, length, offset, flags, err) == -1) { + if (next->pread (next, buffer, length, offset, flags, err) == -1) { length = 0; /* failed to fill the prefetch buffer */ return -1; } @@ -156,7 +155,7 @@ fill_readahead (struct nbdkit_next_ops *next_ops, void *nxdata, } static int -readahead_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +readahead_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -168,7 +167,7 @@ readahead_pread (struct nbdkit_next_ops *next_ops, void *nxdata, * first request or reset after a miss. */ window = READAHEAD_MIN; - if (fill_readahead (next_ops, nxdata, count, offset, flags, err) == -1) + if (fill_readahead (next, count, offset, flags, err) == -1) return -1; } @@ -188,7 +187,7 @@ readahead_pread (struct nbdkit_next_ops *next_ops, void *nxdata, */ else if (offset == position + length) { window = MIN (window * 2, READAHEAD_MAX); - if (fill_readahead (next_ops, nxdata, count, offset, flags, err) == -1) + if (fill_readahead (next, count, offset, flags, err) == -1) return -1; } @@ -215,41 +214,41 @@ kill_readahead (void) } static int -readahead_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +readahead_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { kill_readahead (); - return next_ops->pwrite (nxdata, buf, count, offset, flags, err); + return next->pwrite (next, buf, count, offset, flags, err); } static int -readahead_trim (struct nbdkit_next_ops *next_ops, void *nxdata, +readahead_trim (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { kill_readahead (); - return next_ops->trim (nxdata, count, offset, flags, err); + return next->trim (next, count, offset, flags, err); } static int -readahead_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +readahead_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { kill_readahead (); - return next_ops->zero (nxdata, count, offset, flags, err); + return next->zero (next, count, offset, flags, err); } static int -readahead_flush (struct nbdkit_next_ops *next_ops, void *nxdata, +readahead_flush (nbdkit_next *next, void *handle, uint32_t flags, int *err) { kill_readahead (); - return next_ops->flush (nxdata, flags, err); + return next->flush (next, flags, err); } static struct nbdkit_filter filter = { diff --git a/filters/retry/retry.c b/filters/retry/retry.c index 22527c7d..f1c5d37f 100644 --- a/filters/retry/retry.c +++ b/filters/retry/retry.c @@ -40,7 +40,6 @@ #include <string.h> #include <sys/time.h> -#define NBDKIT_TYPESAFE /* Hack to expose context APIs */ #include <nbdkit-filter.h> #include "cleanup.h" @@ -164,7 +163,7 @@ struct retry_data { }; static bool -valid_range (struct nbdkit_next_ops *next, +valid_range (nbdkit_next *next, uint32_t count, uint64_t offset, bool is_write, int *err) { if ((int64_t) offset + count > next->get_size (next)) { @@ -249,7 +248,7 @@ do_retry (struct retry_handle *h, struct retry_data *data, } static int -retry_pread (struct nbdkit_next_ops *next_ops, nbdkit_next *next, +retry_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -270,7 +269,7 @@ retry_pread (struct nbdkit_next_ops *next_ops, nbdkit_next *next, /* Write. */ static int -retry_pwrite (struct nbdkit_next_ops *next_ops, nbdkit_next *next, +retry_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -305,7 +304,7 @@ retry_pwrite (struct nbdkit_next_ops *next_ops, nbdkit_next *next, /* Trim. */ static int -retry_trim (struct nbdkit_next_ops *next_ops, nbdkit_next *next, +retry_trim (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -340,7 +339,7 @@ retry_trim (struct nbdkit_next_ops *next_ops, nbdkit_next *next, /* Flush. */ static int -retry_flush (struct nbdkit_next_ops *next_ops, nbdkit_next *next, +retry_flush (nbdkit_next *next, void *handle, uint32_t flags, int *err) { @@ -365,7 +364,7 @@ retry_flush (struct nbdkit_next_ops *next_ops, nbdkit_next *next, /* Zero. */ static int -retry_zero (struct nbdkit_next_ops *next_ops, nbdkit_next *next, +retry_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -405,7 +404,7 @@ retry_zero (struct nbdkit_next_ops *next_ops, nbdkit_next *next, /* Extents. */ static int -retry_extents (struct nbdkit_next_ops *next_ops, nbdkit_next *next, +retry_extents (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err) @@ -453,7 +452,7 @@ retry_extents (struct nbdkit_next_ops *next_ops, nbdkit_next *next, /* Cache. */ static int -retry_cache (struct nbdkit_next_ops *next_ops, nbdkit_next *next, +retry_cache (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) diff --git a/filters/stats/stats.c b/filters/stats/stats.c index 639ceacf..7fd043a3 100644 --- a/filters/stats/stats.c +++ b/filters/stats/stats.c @@ -176,7 +176,7 @@ stats_unload (void) } static int -stats_config (nbdkit_next_config *next, void *nxdata, +stats_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { int r; @@ -200,7 +200,8 @@ stats_config (nbdkit_next_config *next, void *nxdata, } static int -stats_config_complete (nbdkit_next_config_complete *next, void *nxdata) +stats_config_complete (nbdkit_next_config_complete *next, + nbdkit_backend *nxdata) { if (filename == NULL) { nbdkit_error ("stats filter requires statsfile parameter"); @@ -211,7 +212,8 @@ stats_config_complete (nbdkit_next_config_complete *next, void *nxdata) } static int -stats_get_ready (nbdkit_next_get_ready *next, void *nxdata, int thread_model) +stats_get_ready (nbdkit_next_get_ready *next, nbdkit_backend *nxdata, + int thread_model) { int fd; @@ -260,7 +262,7 @@ record_stat (nbdstat *st, uint32_t count, const struct timeval *start) /* Read. */ static int -stats_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +stats_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -268,14 +270,14 @@ stats_pread (struct nbdkit_next_ops *next_ops, void *nxdata, int r; gettimeofday (&start, NULL); - r = next_ops->pread (nxdata, buf, count, offset, flags, err); + r = next->pread (next, buf, count, offset, flags, err); if (r == 0) record_stat (&pread_st, count, &start); return r; } /* Write. */ static int -stats_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +stats_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -284,14 +286,14 @@ stats_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, int r; gettimeofday (&start, NULL); - r = next_ops->pwrite (nxdata, buf, count, offset, flags, err); + r = next->pwrite (next, buf, count, offset, flags, err); if (r == 0) record_stat (&pwrite_st, count, &start); return r; } /* Trim. */ static int -stats_trim (struct nbdkit_next_ops *next_ops, void *nxdata, +stats_trim (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -300,14 +302,14 @@ stats_trim (struct nbdkit_next_ops *next_ops, void *nxdata, int r; gettimeofday (&start, NULL); - r = next_ops->trim (nxdata, count, offset, flags, err); + r = next->trim (next, count, offset, flags, err); if (r == 0) record_stat (&trim_st, count, &start); return r; } /* Flush. */ static int -stats_flush (struct nbdkit_next_ops *next_ops, void *nxdata, +stats_flush (nbdkit_next *next, void *handle, uint32_t flags, int *err) { @@ -315,14 +317,14 @@ stats_flush (struct nbdkit_next_ops *next_ops, void *nxdata, int r; gettimeofday (&start, NULL); - r = next_ops->flush (nxdata, flags, err); + r = next->flush (next, flags, err); if (r == 0) record_stat (&flush_st, 0, &start); return r; } /* Zero. */ static int -stats_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +stats_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -331,14 +333,14 @@ stats_zero (struct nbdkit_next_ops *next_ops, void *nxdata, int r; gettimeofday (&start, NULL); - r = next_ops->zero (nxdata, count, offset, flags, err); + r = next->zero (next, count, offset, flags, err); if (r == 0) record_stat (&zero_st, count, &start); return r; } /* Extents. */ static int -stats_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +stats_extents (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err) @@ -347,7 +349,7 @@ stats_extents (struct nbdkit_next_ops *next_ops, void *nxdata, int r; gettimeofday (&start, NULL); - r = next_ops->extents (nxdata, count, offset, flags, extents, err); + r = next->extents (next, count, offset, flags, extents, err); /* XXX There's a case for trying to determine how long the extents * will be that are returned to the client (instead of simply using * count), given the flags and the complex rules in the protocol. @@ -358,7 +360,7 @@ stats_extents (struct nbdkit_next_ops *next_ops, void *nxdata, /* Cache. */ static int -stats_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +stats_cache (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -367,7 +369,7 @@ stats_cache (struct nbdkit_next_ops *next_ops, void *nxdata, int r; gettimeofday (&start, NULL); - r = next_ops->cache (nxdata, count, offset, flags, err); + r = next->cache (next, count, offset, flags, err); if (r == 0) record_stat (&cache_st, count, &start); return r; } diff --git a/filters/swab/swab.c b/filters/swab/swab.c index c9f4b066..68776eee 100644 --- a/filters/swab/swab.c +++ b/filters/swab/swab.c @@ -51,7 +51,7 @@ static int bits = 16; /* Called for each key=value passed on the command line. */ static int -swab_config (nbdkit_next_config *next, void *nxdata, +swab_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { int r; @@ -75,10 +75,10 @@ swab_config (nbdkit_next_config *next, void *nxdata, /* Round size down to avoid issues at end of file. */ static int64_t -swab_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, +swab_get_size (nbdkit_next *next, void *handle) { - int64_t size = next_ops->get_size (nxdata); + int64_t size = next->get_size (next); if (size == -1) return -1; @@ -133,7 +133,7 @@ buf_bswap (void *dest, const void *src, uint32_t count) /* Read data. */ static int -swab_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +swab_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -141,7 +141,7 @@ swab_pread (struct nbdkit_next_ops *next_ops, void *nxdata, if (!is_aligned (count, offset, err)) return -1; - r = next_ops->pread (nxdata, buf, count, offset, flags, err); + r = next->pread (next, buf, count, offset, flags, err); if (r == -1) return -1; @@ -152,7 +152,7 @@ swab_pread (struct nbdkit_next_ops *next_ops, void *nxdata, /* Write data. */ static int -swab_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +swab_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -169,48 +169,48 @@ swab_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, buf_bswap (block, buf, count); - return next_ops->pwrite (nxdata, block, count, offset, flags, err); + return next->pwrite (next, block, count, offset, flags, err); } /* Trim data. */ static int -swab_trim (struct nbdkit_next_ops *next_ops, void *nxdata, +swab_trim (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { if (!is_aligned (count, offset, err)) return -1; - return next_ops->trim (nxdata, count, offset, flags, err); + return next->trim (next, count, offset, flags, err); } /* Zero data. */ static int -swab_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +swab_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { if (!is_aligned (count, offset, err)) return -1; - return next_ops->zero (nxdata, count, offset, flags, err); + return next->zero (next, count, offset, flags, err); } /* Extents. */ static int -swab_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +swab_extents (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err) { if (!is_aligned (count, offset, err)) return -1; - return nbdkit_extents_aligned (next_ops, nxdata, count, offset, flags, - bits/8, extents, err); + return nbdkit_extents_aligned (next, count, offset, flags, bits / 8, extents, + err); } /* Cache. */ static int -swab_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +swab_cache (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { if (!is_aligned (count, offset, err)) return -1; - return next_ops->cache (nxdata, count, offset, flags, err); + return next->cache (next, count, offset, flags, err); } diff --git a/filters/tar/tar.c b/filters/tar/tar.c index 7cf2cd26..b9f40784 100644 --- a/filters/tar/tar.c +++ b/filters/tar/tar.c @@ -65,7 +65,7 @@ static bool initialized = false; static uint64_t tar_offset, tar_size; static int -tar_config (nbdkit_next_config *next, void *nxdata, +tar_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { if (strcmp (key, "tar-entry") == 0) { @@ -85,7 +85,8 @@ tar_config (nbdkit_next_config *next, void *nxdata, } static int -tar_config_complete (nbdkit_next_config_complete *next, void *nxdata) +tar_config_complete (nbdkit_next_config_complete *next, + nbdkit_backend *nxdata) { if (entry == NULL) { nbdkit_error ("you must supply the tar-entry=<FILENAME> parameter"); @@ -139,7 +140,7 @@ tar_close (void *handle) * https://www.redhat.com/archives/libguestfs/2020-July/msg00017.html */ static int -calculate_offset_of_entry (struct nbdkit_next_ops *next_ops, void *nxdata) +calculate_offset_of_entry (nbdkit_next *next) { const size_t bufsize = 65536; char output[] = "/tmp/tarXXXXXX"; @@ -191,7 +192,7 @@ calculate_offset_of_entry (struct nbdkit_next_ops *next_ops, void *nxdata) nbdkit_error ("malloc: %m"); return -1; } - copysize = next_ops->get_size (nxdata); + copysize = next->get_size (next); if (copysize == -1) return -1; @@ -215,7 +216,7 @@ calculate_offset_of_entry (struct nbdkit_next_ops *next_ops, void *nxdata) int64_t j; struct stat statbuf; - r = next_ops->pread (nxdata, buf, count, i, 0, &err); + r = next->pread (next, buf, count, i, 0, &err); if (r == -1) { errno = err; nbdkit_error ("pread: %m"); @@ -277,14 +278,14 @@ calculate_offset_of_entry (struct nbdkit_next_ops *next_ops, void *nxdata) } static int -tar_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, +tar_prepare (nbdkit_next *next, void *handle, int readonly) { struct handle *h = handle; ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); if (!initialized) { - if (calculate_offset_of_entry (next_ops, nxdata) == -1) + if (calculate_offset_of_entry (next) == -1) return -1; } @@ -297,10 +298,10 @@ tar_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, /* Description. */ static const char * -tar_export_description (struct nbdkit_next_ops *next_ops, void *nxdata, +tar_export_description (nbdkit_next *next, void *handle) { - const char *base = next_ops->export_description (nxdata); + const char *base = next->export_description (next); if (!base) return NULL; @@ -310,7 +311,7 @@ tar_export_description (struct nbdkit_next_ops *next_ops, void *nxdata, /* Get the file size. */ static int64_t -tar_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, +tar_get_size (nbdkit_next *next, void *handle) { struct handle *h = handle; @@ -319,7 +320,7 @@ tar_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, /* We must call underlying get_size even though we don't use the * result, because it caches the plugin size in server/backend.c. */ - size = next_ops->get_size (nxdata); + size = next->get_size (next); if (size == -1) return -1; @@ -328,47 +329,47 @@ tar_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, /* Read data from the file. */ static int -tar_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +tar_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offs, uint32_t flags, int *err) { struct handle *h = handle; - return next_ops->pread (nxdata, buf, count, offs + h->offset, flags, err); + return next->pread (next, buf, count, offs + h->offset, flags, err); } /* Write data to the file. */ static int -tar_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +tar_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offs, uint32_t flags, int *err) { struct handle *h = handle; - return next_ops->pwrite (nxdata, buf, count, offs + h->offset, flags, err); + return next->pwrite (next, buf, count, offs + h->offset, flags, err); } /* Trim data. */ static int -tar_trim (struct nbdkit_next_ops *next_ops, void *nxdata, +tar_trim (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, int *err) { struct handle *h = handle; - return next_ops->trim (nxdata, count, offs + h->offset, flags, err); + return next->trim (next, count, offs + h->offset, flags, err); } /* Zero data. */ static int -tar_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +tar_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, int *err) { struct handle *h = handle; - return next_ops->zero (nxdata, count, offs + h->offset, flags, err); + return next->zero (next, count, offs + h->offset, flags, err); } /* Extents. */ static int -tar_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +tar_extents (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, struct nbdkit_extents *extents, int *err) { @@ -382,8 +383,8 @@ tar_extents (struct nbdkit_next_ops *next_ops, void *nxdata, *err = errno; return -1; } - if (next_ops->extents (nxdata, count, offs + h->offset, - flags, extents2, err) == -1) + if (next->extents (next, count, offs + h->offset, flags, extents2, + err) == -1) return -1; for (i = 0; i < nbdkit_extents_count (extents2); ++i) { @@ -399,12 +400,12 @@ tar_extents (struct nbdkit_next_ops *next_ops, void *nxdata, /* Cache data. */ static int -tar_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +tar_cache (nbdkit_next *next, void *handle, uint32_t count, uint64_t offs, uint32_t flags, int *err) { struct handle *h = handle; - return next_ops->cache (nxdata, count, offs + h->offset, flags, err); + return next->cache (next, count, offs + h->offset, flags, err); } static struct nbdkit_filter filter = { diff --git a/filters/tls-fallback/tls-fallback.c b/filters/tls-fallback/tls-fallback.c index bec983be..ee3e6784 100644 --- a/filters/tls-fallback/tls-fallback.c +++ b/filters/tls-fallback/tls-fallback.c @@ -49,7 +49,7 @@ static char message[512] NONSTRING = "This NBD server requires TLS " /* Called for each key=value passed on the command line. */ static int -tls_fallback_config (nbdkit_next_config *next, void *nxdata, +tls_fallback_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { if (strcmp (key, "tlsreadme") == 0) { @@ -63,7 +63,7 @@ tls_fallback_config (nbdkit_next_config *next, void *nxdata, "tlsreadme=<MESSAGE> Alternative contents for the plaintext dummy export.\n" int -tls_fallback_get_ready (nbdkit_next_get_ready *next, void *nxdata, +tls_fallback_get_ready (nbdkit_next_get_ready *next, nbdkit_backend *nxdata, int thread_model) { if (thread_model == NBDKIT_THREAD_MODEL_SERIALIZE_CONNECTIONS) { @@ -75,7 +75,8 @@ tls_fallback_get_ready (nbdkit_next_get_ready *next, void *nxdata, } static int -tls_fallback_list_exports (nbdkit_next_list_exports *next, void *nxdata, +tls_fallback_list_exports (nbdkit_next_list_exports *next, + nbdkit_backend *nxdata, int readonly, int is_tls, struct nbdkit_exports *exports) { @@ -85,7 +86,8 @@ tls_fallback_list_exports (nbdkit_next_list_exports *next, void *nxdata, } static const char * -tls_fallback_default_export (nbdkit_next_default_export *next, void *nxdata, +tls_fallback_default_export (nbdkit_next_default_export *next, + nbdkit_backend *nxdata, int readonly, int is_tls) { if (!is_tls) @@ -101,7 +103,8 @@ tls_fallback_default_export (nbdkit_next_default_export *next, void *nxdata, #define NOT_TLS (handle == &message) static void * -tls_fallback_open (nbdkit_next_open *next, void *nxdata, int readonly, +tls_fallback_open (nbdkit_next_open *next, nbdkit_context *nxdata, + int readonly, const char *exportname, int is_tls) { /* We do NOT want to call next() when insecure, because we don't @@ -120,79 +123,78 @@ tls_fallback_open (nbdkit_next_open *next, void *nxdata, int readonly, */ static const char * -tls_fallback_export_description (struct nbdkit_next_ops *next_ops, - void *nxdata, void *handle) +tls_fallback_export_description (nbdkit_next *next, void *handle) { if (NOT_TLS) return NULL; - return next_ops->export_description (nxdata); + return next->export_description (next); } static int64_t -tls_fallback_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, +tls_fallback_get_size (nbdkit_next *next, void *handle) { if (NOT_TLS) return sizeof message; - return next_ops->get_size (nxdata); + return next->get_size (next); } static int -tls_fallback_can_write (struct nbdkit_next_ops *next_ops, void *nxdata, +tls_fallback_can_write (nbdkit_next *next, void *handle) { if (NOT_TLS) return 0; - return next_ops->can_write (nxdata); + return next->can_write (next); } static int -tls_fallback_can_flush (struct nbdkit_next_ops *next_ops, void *nxdata, +tls_fallback_can_flush (nbdkit_next *next, void *handle) { if (NOT_TLS) return 0; - return next_ops->can_flush (nxdata); + return next->can_flush (next); } static int -tls_fallback_is_rotational (struct nbdkit_next_ops *next_ops, void *nxdata, +tls_fallback_is_rotational (nbdkit_next *next, void *handle) { if (NOT_TLS) return 0; - return next_ops->is_rotational (nxdata); + return next->is_rotational (next); } static int -tls_fallback_can_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +tls_fallback_can_extents (nbdkit_next *next, void *handle) { if (NOT_TLS) return 0; - return next_ops->can_extents (nxdata); + return next->can_extents (next); } static int -tls_fallback_can_multi_conn (struct nbdkit_next_ops *next_ops, void *nxdata, +tls_fallback_can_multi_conn (nbdkit_next *next, void *handle) { if (NOT_TLS) return 0; - return next_ops->can_multi_conn (nxdata); + return next->can_multi_conn (next); } static int -tls_fallback_can_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +tls_fallback_can_cache (nbdkit_next *next, void *handle) { if (NOT_TLS) return NBDKIT_CACHE_NONE; - return next_ops->can_cache (nxdata); + return next->can_cache (next); } static int -tls_fallback_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +tls_fallback_pread (nbdkit_next *next, void *handle, void *b, uint32_t count, uint64_t offs, uint32_t flags, int *err) { @@ -200,7 +202,7 @@ tls_fallback_pread (struct nbdkit_next_ops *next_ops, void *nxdata, memcpy (b, message + offs, count); return 0; } - return next_ops->pread (nxdata, b, count, offs, flags, err); + return next->pread (next, b, count, offs, flags, err); } static struct nbdkit_filter filter = { diff --git a/filters/truncate/truncate.c b/filters/truncate/truncate.c index 00b5d8ce..10fb2fc9 100644 --- a/filters/truncate/truncate.c +++ b/filters/truncate/truncate.c @@ -85,7 +85,7 @@ parse_round_param (const char *key, const char *value, unsigned *ret) /* Called for each key=value passed on the command line. */ static int -truncate_config (nbdkit_next_config *next, void *nxdata, +truncate_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { if (strcmp (key, "truncate") == 0) { @@ -124,7 +124,7 @@ struct handle { /* Open a connection. */ static void * -truncate_open (nbdkit_next_open *next, void *nxdata, +truncate_open (nbdkit_next_open *next, nbdkit_context *nxdata, int readonly, const char *exportname, int is_tls) { struct handle *h; @@ -149,18 +149,18 @@ truncate_close (void *handle) free (h); } -/* In prepare, force a call to next_ops->get_size in order to set +/* In prepare, force a call to next->get_size in order to set * per-connection real_size & size; these values are not changed * during the life of the connection. */ static int -truncate_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, +truncate_prepare (nbdkit_next *next, void *handle, int readonly) { int64_t r; struct handle *h = handle; - r = next_ops->get_size (nxdata); + r = next->get_size (next); if (r == -1) return -1; @@ -188,7 +188,7 @@ truncate_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, /* Get the size. */ static int64_t -truncate_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, +truncate_get_size (nbdkit_next *next, void *handle) { struct handle *h = handle; @@ -204,13 +204,13 @@ truncate_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, /* Advertise extents support. */ static int -truncate_can_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +truncate_can_extents (nbdkit_next *next, void *handle) { /* Advertise unconditional support for the image tail, but also call - * into next_ops to ensure next_ops->extents doesn't fail later. + * into next to ensure next->extents doesn't fail later. */ - int r = next_ops->can_extents (nxdata); + int r = next->can_extents (next); if (r == -1) return -1; return 1; @@ -218,13 +218,13 @@ truncate_can_extents (struct nbdkit_next_ops *next_ops, void *nxdata, /* Override the plugin's .can_fast_zero, because zeroing a tail is fast. */ static int -truncate_can_fast_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +truncate_can_fast_zero (nbdkit_next *next, void *handle) { - /* Cache next_ops->can_fast_zero now, so later calls don't fail, + /* Cache next->can_fast_zero now, so later calls don't fail, * even though we override the answer here. */ - int r = next_ops->can_fast_zero (nxdata); + int r = next->can_fast_zero (next); if (r == -1) return -1; return 1; @@ -232,7 +232,7 @@ truncate_can_fast_zero (struct nbdkit_next_ops *next_ops, void *nxdata, /* Read data. */ static int -truncate_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +truncate_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -245,7 +245,7 @@ truncate_pread (struct nbdkit_next_ops *next_ops, void *nxdata, n = count; else n = h->real_size - offset; - r = next_ops->pread (nxdata, buf, n, offset, flags, err); + r = next->pread (next, buf, n, offset, flags, err); if (r == -1) return -1; count -= n; @@ -260,7 +260,7 @@ truncate_pread (struct nbdkit_next_ops *next_ops, void *nxdata, /* Write data. */ static int -truncate_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +truncate_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) @@ -274,7 +274,7 @@ truncate_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, n = count; else n = h->real_size - offset; - r = next_ops->pwrite (nxdata, buf, n, offset, flags, err); + r = next->pwrite (next, buf, n, offset, flags, err); if (r == -1) return -1; count -= n; @@ -295,7 +295,7 @@ truncate_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, /* Trim data. */ static int -truncate_trim (struct nbdkit_next_ops *next_ops, void *nxdata, +truncate_trim (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -307,14 +307,14 @@ truncate_trim (struct nbdkit_next_ops *next_ops, void *nxdata, n = count; else n = h->real_size - offset; - return next_ops->trim (nxdata, n, offset, flags, err); + return next->trim (next, n, offset, flags, err); } return 0; } /* Zero data. */ static int -truncate_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +truncate_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -327,18 +327,18 @@ truncate_zero (struct nbdkit_next_ops *next_ops, void *nxdata, else n = h->real_size - offset; if (flags & NBDKIT_FLAG_FAST_ZERO && - next_ops->can_fast_zero (nxdata) == 0) { + next->can_fast_zero (next) == 0) { *err = ENOTSUP; return -1; } - return next_ops->zero (nxdata, n, offset, flags, err); + return next->zero (next, n, offset, flags, err); } return 0; } /* Extents. */ static int -truncate_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +truncate_extents (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err) { @@ -378,7 +378,7 @@ truncate_extents (struct nbdkit_next_ops *next_ops, void *nxdata, n = count; else n = h->real_size - offset; - if (next_ops->extents (nxdata, n, offset, flags, extents2, err) == -1) + if (next->extents (next, n, offset, flags, extents2, err) == -1) return -1; for (i = 0; i < nbdkit_extents_count (extents2); ++i) { @@ -395,7 +395,7 @@ truncate_extents (struct nbdkit_next_ops *next_ops, void *nxdata, /* Cache. */ static int -truncate_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +truncate_cache (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -408,7 +408,7 @@ truncate_cache (struct nbdkit_next_ops *next_ops, void *nxdata, n = count; else n = h->real_size - offset; - r = next_ops->cache (nxdata, n, offset, flags, err); + r = next->cache (next, n, offset, flags, err); if (r == -1) return -1; } diff --git a/filters/xz/xz.c b/filters/xz/xz.c index 63adb37e..5e717a8f 100644 --- a/filters/xz/xz.c +++ b/filters/xz/xz.c @@ -53,7 +53,7 @@ static uint64_t maxblock = 512 * 1024 * 1024; static uint32_t maxdepth = 8; static int -xz_config (nbdkit_next_config *next, void *nxdata, +xz_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { if (strcmp (key, "xz-max-block") == 0) { @@ -90,7 +90,7 @@ struct xz_handle { /* Create the per-connection handle. */ static void * -xz_open (nbdkit_next_open *next, void *nxdata, +xz_open (nbdkit_next_open *next, nbdkit_context *nxdata, int readonly, const char *exportname, int is_tls) { struct xz_handle *h; @@ -133,12 +133,12 @@ xz_close (void *handle) } static int -xz_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, +xz_prepare (nbdkit_next *next, void *handle, int readonly) { struct xz_handle *h = handle; - h->xz = xzfile_open (next_ops, nxdata); + h->xz = xzfile_open (next); if (!h->xz) return -1; @@ -159,10 +159,10 @@ xz_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, /* Description. */ static const char * -xz_export_description (struct nbdkit_next_ops *next_ops, void *nxdata, +xz_export_description (nbdkit_next *next, void *handle) { - const char *base = next_ops->export_description (nxdata); + const char *base = next->export_description (next); if (!base) return NULL; @@ -171,7 +171,7 @@ xz_export_description (struct nbdkit_next_ops *next_ops, void *nxdata, /* Get the file size. */ static int64_t -xz_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) +xz_get_size (nbdkit_next *next, void *handle) { struct xz_handle *h = handle; @@ -184,7 +184,7 @@ xz_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle) * below. This is possibly a bug in nbdkit. */ static int -xz_can_write (struct nbdkit_next_ops *next_ops, void *nxdata, +xz_can_write (nbdkit_next *next, void *handle) { return 0; @@ -192,7 +192,7 @@ xz_can_write (struct nbdkit_next_ops *next_ops, void *nxdata, /* Whatever the plugin says, this filter is consistent across connections. */ static int -xz_can_multi_conn (struct nbdkit_next_ops *next_ops, void *nxdata, +xz_can_multi_conn (nbdkit_next *next, void *handle) { return 1; @@ -202,7 +202,7 @@ xz_can_multi_conn (struct nbdkit_next_ops *next_ops, void *nxdata, * sparseness so in future we should generate extents information. XXX */ static int -xz_can_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +xz_can_extents (nbdkit_next *next, void *handle) { return 0; @@ -210,7 +210,7 @@ xz_can_extents (struct nbdkit_next_ops *next_ops, void *nxdata, /* Cache */ static int -xz_can_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +xz_can_cache (nbdkit_next *next, void *handle) { /* We are already operating as a cache regardless of the plugin's @@ -222,7 +222,7 @@ xz_can_cache (struct nbdkit_next_ops *next_ops, void *nxdata, /* Read data from the file. */ static int -xz_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +xz_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { @@ -235,7 +235,7 @@ xz_pread (struct nbdkit_next_ops *next_ops, void *nxdata, data = get_block (h->c, offset, &start, &size); if (!data) { /* Not in the cache. We need to read the block from the xz file. */ - data = xzfile_read_block (h->xz, next_ops, nxdata, flags, err, + data = xzfile_read_block (h->xz, next, flags, err, offset, &start, &size); if (data == NULL) return -1; @@ -255,7 +255,7 @@ xz_pread (struct nbdkit_next_ops *next_ops, void *nxdata, count -= n; offset += n; if (count > 0) - return xz_pread (next_ops, nxdata, h, buf, count, offset, flags, err); + return xz_pread (next, h, buf, count, offset, flags, err); return 0; } diff --git a/filters/xz/xzfile.c b/filters/xz/xzfile.c index 1ad010ef..287a8248 100644 --- a/filters/xz/xzfile.c +++ b/filters/xz/xzfile.c @@ -64,12 +64,12 @@ struct xzfile { uint64_t max_uncompressed_block_size; }; -static bool check_header_magic (struct nbdkit_next_ops *next_ops, void *nxdata); -static lzma_index *parse_indexes (struct nbdkit_next_ops *next_ops, void *nxdata, size_t *); +static bool check_header_magic (nbdkit_next *next); +static lzma_index *parse_indexes (nbdkit_next *next, size_t *); static int iter_indexes (lzma_index *idx, size_t *, uint64_t *); xzfile * -xzfile_open (struct nbdkit_next_ops *next_ops, void *nxdata) +xzfile_open (nbdkit_next *next) { xzfile *xz; uint64_t size; @@ -81,13 +81,13 @@ xzfile_open (struct nbdkit_next_ops *next_ops, void *nxdata) } /* Check file magic. */ - if (!check_header_magic (next_ops, nxdata)) { + if (!check_header_magic (next)) { nbdkit_error ("xz: not an xz file"); goto err1; } /* Read and parse the indexes. */ - xz->idx = parse_indexes (next_ops, nxdata, &xz->nr_streams); + xz->idx = parse_indexes (next, &xz->nr_streams); if (xz->idx == NULL) goto err1; @@ -112,16 +112,16 @@ xzfile_open (struct nbdkit_next_ops *next_ops, void *nxdata) } static bool -check_header_magic (struct nbdkit_next_ops *next_ops, void *nxdata) +check_header_magic (nbdkit_next *next) { char buf[XZ_HEADER_MAGIC_LEN]; int err; - if (next_ops->get_size (nxdata) < XZ_HEADER_MAGIC_LEN) { + if (next->get_size (next) < XZ_HEADER_MAGIC_LEN) { nbdkit_error ("xz: file too short"); return false; } - if (next_ops->pread (nxdata, buf, XZ_HEADER_MAGIC_LEN, 0, 0, &err) == -1) { + if (next->pread (next, buf, XZ_HEADER_MAGIC_LEN, 0, 0, &err) == -1) { nbdkit_error ("xz: could not read header magic: error %d", err); return false; } @@ -134,7 +134,7 @@ check_header_magic (struct nbdkit_next_ops *next_ops, void *nxdata) * in the xz sources. */ static lzma_index * -parse_indexes (struct nbdkit_next_ops *next_ops, void *nxdata, +parse_indexes (nbdkit_next *next, size_t *nr_streams) { lzma_ret r; @@ -152,7 +152,7 @@ parse_indexes (struct nbdkit_next_ops *next_ops, void *nxdata, *nr_streams = 0; /* Check file size is a multiple of 4 bytes. */ - pos = size = next_ops->get_size (nxdata); + pos = size = next->get_size (next); if (pos == -1) { nbdkit_error ("xz: get_size: %m"); goto err; @@ -171,9 +171,8 @@ parse_indexes (struct nbdkit_next_ops *next_ops, void *nxdata, goto err; } - if (next_ops->pread (nxdata, footer, LZMA_STREAM_HEADER_SIZE, - pos - LZMA_STREAM_HEADER_SIZE, - 0, &err) == -1) { + if (next->pread (next, footer, LZMA_STREAM_HEADER_SIZE, + pos - LZMA_STREAM_HEADER_SIZE, 0, &err) == -1) { nbdkit_error ("xz: read stream footer: error %d", err); goto err; } @@ -224,7 +223,7 @@ parse_indexes (struct nbdkit_next_ops *next_ops, void *nxdata, if (pos + strm.avail_in > size) strm.avail_in = size - pos; - if (next_ops->pread (nxdata, buf, strm.avail_in, offs, 0, &err) == -1) { + if (next->pread (next, buf, strm.avail_in, offs, 0, &err) == -1) { nbdkit_error ("xz: read index: error %d", err); goto err; } @@ -245,8 +244,8 @@ parse_indexes (struct nbdkit_next_ops *next_ops, void *nxdata, nbdkit_debug ("decode stream header at pos = %" PRIi64, pos); /* Read and decode the stream header. */ - if (next_ops->pread (nxdata, header, LZMA_STREAM_HEADER_SIZE, pos, 0, - &err) == -1) { + if (next->pread (next, header, LZMA_STREAM_HEADER_SIZE, pos, 0, + &err) == -1) { nbdkit_error ("xz: read stream header: error %d", err); goto err; } @@ -349,8 +348,8 @@ xzfile_get_size (xzfile *xz) char * xzfile_read_block (xzfile *xz, - struct nbdkit_next_ops *next_ops, - void *nxdata, uint32_t flags, int *err, + nbdkit_next *next, + uint32_t flags, int *err, uint64_t offset, uint64_t *start_rtn, uint64_t *size_rtn) { @@ -369,7 +368,7 @@ xzfile_read_block (xzfile *xz, /* Read the total size of the underlying disk, so we don't * read over the end. */ - size = next_ops->get_size (nxdata); + size = next->get_size (next); if (size == -1) { nbdkit_error ("xz: get_size: %m"); return NULL; @@ -393,7 +392,7 @@ xzfile_read_block (xzfile *xz, * tell us how big the block header is. */ offs = iter.block.compressed_file_offset; - if (next_ops->pread (nxdata, header, 1, offs, 0, err) == -1) { + if (next->pread (next, header, 1, offs, 0, err) == -1) { nbdkit_error ("xz: read: could not read block header byte: error %d", *err); return NULL; } @@ -410,8 +409,8 @@ xzfile_read_block (xzfile *xz, block.header_size = lzma_block_header_size_decode (header[0]); /* Now read and decode the block header. */ - if (next_ops->pread (nxdata, &header[1], block.header_size-1, offs, - 0, err) == -1) { + if (next->pread (next, &header[1], block.header_size-1, offs, + 0, err) == -1) { nbdkit_error ("xz: read: could not read block of compressed data: " "error %d", *err); return NULL; @@ -467,7 +466,7 @@ xzfile_read_block (xzfile *xz, strm.avail_in = size - offs; if (strm.avail_in > 0) { strm.next_in = buf; - if (next_ops->pread (nxdata, buf, strm.avail_in, offs, 0, err) == -1) { + if (next->pread (next, buf, strm.avail_in, offs, 0, err) == -1) { nbdkit_error ("xz: read: error %d", *err); goto err2; } diff --git a/tests/test-truncate4.sh b/tests/test-truncate4.sh index 4a27cbc2..f3ebcddb 100755 --- a/tests/test-truncate4.sh +++ b/tests/test-truncate4.sh @@ -30,7 +30,7 @@ # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. -# Regression test when next_ops->get_size changes between connections. +# Regression test when next->get_size changes between connections. # # For now, NBD does not support dynamic resize; but the file plugin # reads size from the file system for each new connection, at which diff --git a/tests/test-layers-filter.c b/tests/test-layers-filter.c index ed06a008..08461ccf 100644 --- a/tests/test-layers-filter.c +++ b/tests/test-layers-filter.c @@ -43,10 +43,9 @@ #define str(s) #s #define DEBUG_FUNCTION nbdkit_debug ("%s: %s", layer, __func__) -/* Perform sanity checking on next_ops(nxdata) stability */ +/* Perform sanity checking on nbdkit_next stability */ struct handle { - void *nxdata; - struct nbdkit_next_ops *next_ops; + nbdkit_next *next; }; static void @@ -62,7 +61,7 @@ test_layers_filter_unload (void) } static int -test_layers_filter_config (nbdkit_next_config *next, void *nxdata, +test_layers_filter_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) { DEBUG_FUNCTION; @@ -71,7 +70,7 @@ test_layers_filter_config (nbdkit_next_config *next, void *nxdata, static int test_layers_filter_config_complete (nbdkit_next_config_complete *next, - void *nxdata) + nbdkit_backend *nxdata) { DEBUG_FUNCTION; return next (nxdata); @@ -89,7 +88,7 @@ test_layers_filter_thread_model (void) static int test_layers_filter_get_ready (nbdkit_next_get_ready *next, - void *nxdata, int thread_model) + nbdkit_backend *nxdata, int thread_model) { DEBUG_FUNCTION; return next (nxdata); @@ -97,7 +96,7 @@ test_layers_filter_get_ready (nbdkit_next_get_ready *next, static int test_layers_filter_after_fork (nbdkit_next_after_fork *next, - void *nxdata) + nbdkit_backend *nxdata) { DEBUG_FUNCTION; return next (nxdata); @@ -105,14 +104,15 @@ test_layers_filter_after_fork (nbdkit_next_after_fork *next, static int test_layers_filter_preconnect (nbdkit_next_preconnect *next, - void *nxdata, int readonly) + nbdkit_backend *nxdata, int readonly) { DEBUG_FUNCTION; return next (nxdata, readonly); } static int -test_layers_filter_list_exports (nbdkit_next_list_exports *next, void *nxdata, +test_layers_filter_list_exports (nbdkit_next_list_exports *next, + nbdkit_backend *nxdata, int readonly, int is_tls, struct nbdkit_exports *exports) { @@ -122,14 +122,15 @@ test_layers_filter_list_exports (nbdkit_next_list_exports *next, void *nxdata, static const char * test_layers_filter_default_export (nbdkit_next_default_export *next, - void *nxdata, int readonly, int is_tls) + nbdkit_backend *nxdata, int readonly, + int is_tls) { DEBUG_FUNCTION; return next (nxdata, readonly); } static void * -test_layers_filter_open (nbdkit_next_open *next, void *nxdata, +test_layers_filter_open (nbdkit_next_open *next, nbdkit_context *nxdata, int readonly, const char *exportname, int is_tls) { struct handle *h = calloc (1, sizeof *h); @@ -156,240 +157,233 @@ test_layers_filter_close (void *handle) } static int -test_layers_filter_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, +test_layers_filter_prepare (nbdkit_next *next, void *handle, int readonly) { struct handle *h = handle; - assert (h->next_ops == NULL); - h->next_ops = next_ops; - h->nxdata = nxdata; - assert (next_ops == nxdata); + assert (h->next == NULL); + h->next = next; DEBUG_FUNCTION; return 0; } static int -test_layers_filter_finalize (struct nbdkit_next_ops *next_ops, void *nxdata, +test_layers_filter_finalize (nbdkit_next *next, void *handle) { struct handle *h = handle; - assert (h->next_ops == next_ops && h->nxdata == nxdata); + assert (h->next == next); DEBUG_FUNCTION; return 0; } static int64_t -test_layers_filter_get_size (struct nbdkit_next_ops *next_ops, void *nxdata, +test_layers_filter_get_size (nbdkit_next *next, void *handle) { struct handle *h = handle; - assert (h->next_ops == next_ops && h->nxdata == nxdata); + assert (h->next == next); DEBUG_FUNCTION; - return next_ops->get_size (nxdata); + return next->get_size (next); } static int -test_layers_filter_can_write (struct nbdkit_next_ops *next_ops, void *nxdata, +test_layers_filter_can_write (nbdkit_next *next, void *handle) { struct handle *h = handle; - assert (h->next_ops == next_ops && h->nxdata == nxdata); + assert (h->next == next); DEBUG_FUNCTION; - return next_ops->can_write (nxdata); + return next->can_write (next); } static int -test_layers_filter_can_flush (struct nbdkit_next_ops *next_ops, void *nxdata, +test_layers_filter_can_flush (nbdkit_next *next, void *handle) { struct handle *h = handle; - assert (h->next_ops == next_ops && h->nxdata == nxdata); + assert (h->next == next); DEBUG_FUNCTION; - return next_ops->can_flush (nxdata); + return next->can_flush (next); } static int -test_layers_filter_is_rotational (struct nbdkit_next_ops *next_ops, - void *nxdata, +test_layers_filter_is_rotational (nbdkit_next *next, void *handle) { struct handle *h = handle; - assert (h->next_ops == next_ops && h->nxdata == nxdata); + assert (h->next == next); DEBUG_FUNCTION; - return next_ops->is_rotational (nxdata); + return next->is_rotational (next); } static int -test_layers_filter_can_trim (struct nbdkit_next_ops *next_ops, void *nxdata, +test_layers_filter_can_trim (nbdkit_next *next, void *handle) { struct handle *h = handle; - assert (h->next_ops == next_ops && h->nxdata == nxdata); + assert (h->next == next); DEBUG_FUNCTION; - return next_ops->can_trim (nxdata); + return next->can_trim (next); } static int -test_layers_filter_can_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +test_layers_filter_can_zero (nbdkit_next *next, void *handle) { struct handle *h = handle; - assert (h->next_ops == next_ops && h->nxdata == nxdata); + assert (h->next == next); DEBUG_FUNCTION; - return next_ops->can_zero (nxdata); + return next->can_zero (next); } static int -test_layers_filter_can_fast_zero (struct nbdkit_next_ops *next_ops, - void *nxdata, void *handle) +test_layers_filter_can_fast_zero (nbdkit_next *next, void *handle) { struct handle *h = handle; - assert (h->next_ops == next_ops && h->nxdata == nxdata); + assert (h->next == next); DEBUG_FUNCTION; - return next_ops->can_fast_zero (nxdata); + return next->can_fast_zero (next); } static int -test_layers_filter_can_fua (struct nbdkit_next_ops *next_ops, void *nxdata, +test_layers_filter_can_fua (nbdkit_next *next, void *handle) { struct handle *h = handle; - assert (h->next_ops == next_ops && h->nxdata == nxdata); + assert (h->next == next); DEBUG_FUNCTION; - return next_ops->can_fua (nxdata); + return next->can_fua (next); } static int -test_layers_filter_can_multi_conn (struct nbdkit_next_ops *next_ops, - void *nxdata, +test_layers_filter_can_multi_conn (nbdkit_next *next, void *handle) { struct handle *h = handle; - assert (h->next_ops == next_ops && h->nxdata == nxdata); + assert (h->next == next); DEBUG_FUNCTION; - return next_ops->can_multi_conn (nxdata); + return next->can_multi_conn (next); } static int -test_layers_filter_can_extents (struct nbdkit_next_ops *next_ops, - void *nxdata, +test_layers_filter_can_extents (nbdkit_next *next, void *handle) { struct handle *h = handle; - assert (h->next_ops == next_ops && h->nxdata == nxdata); + assert (h->next == next); DEBUG_FUNCTION; - return next_ops->can_extents (nxdata); + return next->can_extents (next); } static int -test_layers_filter_can_cache (struct nbdkit_next_ops *next_ops, - void *nxdata, +test_layers_filter_can_cache (nbdkit_next *next, void *handle) { struct handle *h = handle; - assert (h->next_ops == next_ops && h->nxdata == nxdata); + assert (h->next == next); DEBUG_FUNCTION; - return next_ops->can_cache (nxdata); + return next->can_cache (next); } static int -test_layers_filter_pread (struct nbdkit_next_ops *next_ops, void *nxdata, +test_layers_filter_pread (nbdkit_next *next, void *handle, void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { struct handle *h = handle; - assert (h->next_ops == next_ops && h->nxdata == nxdata); + assert (h->next == next); DEBUG_FUNCTION; - return next_ops->pread (nxdata, buf, count, offset, flags, err); + return next->pread (next, buf, count, offset, flags, err); } static int -test_layers_filter_pwrite (struct nbdkit_next_ops *next_ops, void *nxdata, +test_layers_filter_pwrite (nbdkit_next *next, void *handle, const void *buf, uint32_t count, uint64_t offset, uint32_t flags, int *err) { struct handle *h = handle; - assert (h->next_ops == next_ops && h->nxdata == nxdata); + assert (h->next == next); DEBUG_FUNCTION; - return next_ops->pwrite (nxdata, buf, count, offset, flags, err); + return next->pwrite (next, buf, count, offset, flags, err); } static int -test_layers_filter_flush (struct nbdkit_next_ops *next_ops, void *nxdata, +test_layers_filter_flush (nbdkit_next *next, void *handle, uint32_t flags, int *err) { struct handle *h = handle; - assert (h->next_ops == next_ops && h->nxdata == nxdata); + assert (h->next == next); DEBUG_FUNCTION; - return next_ops->flush (nxdata, flags, err); + return next->flush (next, flags, err); } static int -test_layers_filter_trim (struct nbdkit_next_ops *next_ops, void *nxdata, +test_layers_filter_trim (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { struct handle *h = handle; - assert (h->next_ops == next_ops && h->nxdata == nxdata); + assert (h->next == next); DEBUG_FUNCTION; - return next_ops->trim (nxdata, count, offset, flags, err); + return next->trim (next, count, offset, flags, err); } static int -test_layers_filter_zero (struct nbdkit_next_ops *next_ops, void *nxdata, +test_layers_filter_zero (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { struct handle *h = handle; - assert (h->next_ops == next_ops && h->nxdata == nxdata); + assert (h->next == next); DEBUG_FUNCTION; - return next_ops->zero (nxdata, count, offset, flags, err); + return next->zero (next, count, offset, flags, err); } static int -test_layers_filter_extents (struct nbdkit_next_ops *next_ops, void *nxdata, +test_layers_filter_extents (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents, int *err) { struct handle *h = handle; - assert (h->next_ops == next_ops && h->nxdata == nxdata); + assert (h->next == next); DEBUG_FUNCTION; - return next_ops->extents (nxdata, count, offset, flags, extents, err); + return next->extents (next, count, offset, flags, extents, err); } static int -test_layers_filter_cache (struct nbdkit_next_ops *next_ops, void *nxdata, +test_layers_filter_cache (nbdkit_next *next, void *handle, uint32_t count, uint64_t offset, uint32_t flags, int *err) { struct handle *h = handle; - assert (h->next_ops == next_ops && h->nxdata == nxdata); + assert (h->next == next); DEBUG_FUNCTION; - return next_ops->cache (nxdata, count, offset, flags, err); + return next->cache (next, count, offset, flags, err); } static struct nbdkit_filter filter = { -- 2.30.1
Eric Blake
2021-Mar-05 23:31 UTC
[Libguestfs] [nbdkit PATCH v3 15/16] multi-conn: New filter
Implement a TODO item of emulating multi-connection consistency via multiple plugin flush calls to allow a client to assume that a flush on a single connection is good enough. This also gives us some fine-tuning over whether to advertise the bit, including some setups that are unsafe but may be useful in timing tests. Testing is interesting: I used the sh plugin to implement a server that intentionally keeps a per-connection cache. Note that this filter assumes that multiple connections will still share the same data (other than caching effects); effects are not guaranteed when trying to mix it with more exotic plugins like info that violate that premise. --- filters/cache/nbdkit-cache-filter.pod | 5 +- filters/fua/nbdkit-fua-filter.pod | 7 + .../multi-conn/nbdkit-multi-conn-filter.pod | 178 +++++++ filters/nocache/nbdkit-nocache-filter.pod | 1 + filters/noextents/nbdkit-noextents-filter.pod | 1 + .../noparallel/nbdkit-noparallel-filter.pod | 1 + filters/nozero/nbdkit-nozero-filter.pod | 1 + configure.ac | 4 +- filters/multi-conn/Makefile.am | 68 +++ tests/Makefile.am | 9 + filters/multi-conn/multi-conn.c | 435 ++++++++++++++++++ tests/test-multi-conn-plugin.sh | 122 +++++ tests/test-multi-conn.sh | 293 ++++++++++++ TODO | 7 - 14 files changed, 1123 insertions(+), 9 deletions(-) create mode 100644 filters/multi-conn/nbdkit-multi-conn-filter.pod create mode 100644 filters/multi-conn/Makefile.am create mode 100644 filters/multi-conn/multi-conn.c create mode 100755 tests/test-multi-conn-plugin.sh create mode 100755 tests/test-multi-conn.sh diff --git a/filters/cache/nbdkit-cache-filter.pod b/filters/cache/nbdkit-cache-filter.pod index 34fd0b29..482a9c55 100644 --- a/filters/cache/nbdkit-cache-filter.pod +++ b/filters/cache/nbdkit-cache-filter.pod @@ -41,7 +41,9 @@ an explicit flush is done by the client. This is the default caching mode, and is safe if your client issues flush requests correctly (which is true for modern Linux and other -well-written NBD clients). +well-written NBD clients). Note that this mode is able to advertise +multi-connection consistency even without the use of +L<nbdkit-multi-conn-filter(1)>. =item B<cache=writethrough> @@ -162,6 +164,7 @@ L<nbdkit(1)>, L<nbdkit-file-plugin(1)>, L<nbdkit-cacheextents-filter(1)>, L<nbdkit-readahead-filter(1)>, +L<nbdkit-multi-conn-filter(1)>, L<nbdkit-filter(3)>, L<qemu-img(1)>. diff --git a/filters/fua/nbdkit-fua-filter.pod b/filters/fua/nbdkit-fua-filter.pod index 0f9b9744..9b0d84b5 100644 --- a/filters/fua/nbdkit-fua-filter.pod +++ b/filters/fua/nbdkit-fua-filter.pod @@ -16,6 +16,12 @@ This filter can be used to disable FUA and flush requests for speed server fallbacks, and for evaluating timing differences between proper use of FUA compared to a full flush. +Note that by default, the NBD protocol does not guarantee that the use +of FUA from one connection will be visible from another connection +unless the server advertised NBD_FLAG_MULTI_CONN. You may wish to +combine this filter with L<nbdkit-multi-conn-filter(1)> if you plan on +making multiple connections to the plugin. + =head1 PARAMETERS The C<fuamode> parameter is optional and controls which mode the @@ -137,6 +143,7 @@ L<nbdkit-file-plugin(1)>, L<nbdkit-filter(3)>, L<nbdkit-blocksize-filter(1)>, L<nbdkit-log-filter(1)>, +L<nbdkit-multi-conn-filter(1)>, L<nbdkit-nocache-filter(1)>, L<nbdkit-noextents-filter(1)>, L<nbdkit-noparallel-filter(1)>, diff --git a/filters/multi-conn/nbdkit-multi-conn-filter.pod b/filters/multi-conn/nbdkit-multi-conn-filter.pod new file mode 100644 index 00000000..c8f334b3 --- /dev/null +++ b/filters/multi-conn/nbdkit-multi-conn-filter.pod @@ -0,0 +1,178 @@ +=head1 NAME + +nbdkit-multi-conn-filter - nbdkit multi-conn filter + +=head1 SYNOPSIS + + nbdkit --filter=multi-conn plugin [multi-conn-mode=MODE] \ + [multi-conn-track-dirty=LEVEL] [plugin-args...] + +=head1 DESCRIPTION + +C<nbdkit-multi-conn-filter> is a filter that enables alterations to +the server's advertisement of NBD_FLAG_MULTI_CONN. When a server +permits multiple simultaneous clients, and sets this flag, a client +may assume that all connections see a consistent view (after getting +the server reply from a write in one connection, sending a flush +command on a single connection and waiting for that reply then +guarantees that all connections will then see the just-written data). +If the flag is not advertised, a client must presume that separate +connections may have utilized independent caches, where a flush on one +connection does not affect the cache of a second connection. + +The main use of this filter is to emulate consistent semantics across +multiple connections when not already provided by a plugin, although +it also has additional modes useful for evaluating performance and +correctness of client and plugin multi-conn behaviors. This filter +assumes that multiple connections to a plugin will eventually share +data, other than any caching effects; it is not suitable for use with +a plugin that produces completely independent data per connection. + +Additional control over the behavior of client flush commands is +possible by combining this filter with L<nbdkit-fua-filter(1)>. Note +that L<nbdkit-cache-filter(1)> is also able to provide +multi-connection consistency, but at the expense of an extra layer of +caching not needed with this filter. + +=head1 PARAMETERS + +=over 4 + +=item B<multi-conn-mode=auto> + +This filter defaults to B<auto> mode. If the selected thread model is +SERIALIZE_CONNECTIONS, then this filter behaves the same as B<disable> +mode; if the plugin advertises multi-conn, then this filter behaves +the same as B<plugin> mode; otherwise, this filter behaves the same as +B<emulate> mode. As a result, this mode advertises +NBD_FLAG_MULTI_CONN to the client exactly when the server supports +multiple simultaneous connections. + +=item B<multi-conn-mode=emulate> + +When B<emulate> mode is chosen, then this filter tracks all parallel +connections. When a client issues a flush command over any one +connection (including an implied flush by a write command with the FUA +(force unit access) flag set), the filter then replicates that flush +across each connection to the plugin (although the amount of plugin +calls can be tuned by adjusting B<multi-conn-track-dirty>). This +assumes that flushing each connection is enough to clear any +per-connection cached data, in order to give each connection a +consistent view of the image; therefore, this mode advertises +NBD_FLAG_MULTI_CONN to the client. + +Note that in this mode, a client will be unable to connect if the +plugin lacks support for flush, as there would be no way to emulate +cross-connection consistency. + +=item B<multi-conn-mode=disable> + +When B<disable> mode is chosen, this filter disables advertisement of +NBD_FLAG_MULTI_CONN to the client, even if the plugin supports it, and +does not replicate flush commands across connections. This is useful +for testing whether a client with multiple connections properly sends +multiple flushes in order to overcome per-connection caching. + +=item B<multi-conn-mode=plugin> + +When B<plugin> mode is chosen, the filter does not change whether +NBD_FLAG_MULTI_CONN is advertised by the plugin, and does not +replicate flush commands across connections; but still honors +B<multi-conn-track-dirty> for minimizing the number of flush commands +passed on to the plugin. + +=item B<multi-conn-mode=unsafe> + +When B<unsafe> mode is chosen, this filter blindly advertises +NBD_FLAG_MULTI_CONN to the client even if the plugin lacks support. +This is dangerous, and risks data corruption if the client makes +assumptions about data consistency that were not actually met. + +=item B<multi-conn-track-dirty=fast> + +When dirty tracking is set to B<fast>, the filter tracks whether any +connection has caused the image to be dirty (any write, zero, or trim +commands since the last flush, regardless of connection); if all +connections are clean, a client flush command is ignored rather than +sent on to the plugin. In this mode, a flush action on one connection +marks all other connections as clean, regardless of whether the filter +actually advertised NBD_FLAG_MULTI_CONN, which can result in less +activity when a client sends multiple flushes rather than taking +advantage of multi-conn semantics. This is safe with +B<multi-conn-mode=emulate>, but potentially unsafe with +B<multi-conn-mode=plugin> when the plugin did not advertise +multi-conn, as it does not track whether a read may have cached stale +data prior to a flush. + +=item B<multi-conn-track-dirty=connection> + +Dirty tracking is set to B<connection> by default, where the filter +tracks whether a given connection is dirty (any write, zero, or trim +commands since the last flush on the given connection, and any read +since the last flush on any other connection); if the connection is +clean, a flush command to that connection (whether directly from the +client, or replicated by B<multi-conn-mode=emulate> is ignored rather +than sent on to the plugin. This mode may result in more flush calls +than B<multi-conn-track-dirty=fast>, but in turn is safe to use with +B<multi-conn-mode=plugin>. + +=item B<multi-conn-track-dirty=off> + +When dirty tracking is set to B<off>, all flush commands from the +client are passed on to the plugin, regardless of whether the flush +would be needed for consistency. Note that when combined with +B<multi-conn-mode=emulate>, a client which disregards +NBD_FLAG_MULTI_CONN by flushing on each connection itself results in a +quadratic number of flush operations on the plugin. + +=back + +=head1 EXAMPLES + +Provide consistent cross-connection flush semantics on top of a plugin +that lacks it natively: + + nbdkit --filter=multi-conn vddk /absolute/path/to/file.vmdk + +Minimize the number of expensive flush operations performed when +utilizing a plugin that has multi-conn consistency from a client that +blindly flushes across every connection: + + nbdkit --filter=multi-conn file multi-conn-mode=plugin \ + multi-conn-track-dirty=fast disk.img + +=head1 FILES + +=over 4 + +=item F<$filterdir/nbdkit-multi-conn-filter.so> + +The filter. + +Use C<nbdkit --dump-config> to find the location of C<$filterdir>. + +=back + +=head1 VERSION + +C<nbdkit-multi-conn-filter> first appeared in nbdkit 1.26. + +=head1 SEE ALSO + +L<nbdkit(1)>, +L<nbdkit-file-plugin(1)>, +L<nbdkit-filter(3)>, +L<nbdkit-cache-filter(1)>, +L<nbdkit-fua-filter(1)>, +L<nbdkit-nocache-filter(1)>, +L<nbdkit-noextents-filter(1)>, +L<nbdkit-noparallel-filter(1)>, +L<nbdkit-nozero-filter(1)>. + +=head1 AUTHORS + +Eric Blake + +=head1 COPYRIGHT + +Copyright (C) 2018-2021 Red Hat Inc. diff --git a/filters/nocache/nbdkit-nocache-filter.pod b/filters/nocache/nbdkit-nocache-filter.pod index de970136..3c30533c 100644 --- a/filters/nocache/nbdkit-nocache-filter.pod +++ b/filters/nocache/nbdkit-nocache-filter.pod @@ -77,6 +77,7 @@ L<nbdkit-file-plugin(1)>, L<nbdkit-filter(3)>, L<nbdkit-cache-filter(1)>, L<nbdkit-fua-filter(1)>, +L<nbdkit-multi-conn-filter(1)>, L<nbdkit-noextents-filter(1)>, L<nbdkit-noparallel-filter(1)>, L<nbdkit-nozero-filter(1)>. diff --git a/filters/noextents/nbdkit-noextents-filter.pod b/filters/noextents/nbdkit-noextents-filter.pod index 0260a5cf..891b197d 100644 --- a/filters/noextents/nbdkit-noextents-filter.pod +++ b/filters/noextents/nbdkit-noextents-filter.pod @@ -49,6 +49,7 @@ L<nbdkit(1)>, L<nbdkit-filter(3)>, L<nbdkit-extentlist-filter(1)>, L<nbdkit-fua-filter(1)>, +L<nbdkit-multi-conn-filter(1)>, L<nbdkit-nocache-filter(1)>, L<nbdkit-noparallel-filter(1)>, L<nbdkit-nozero-filter(1)>, diff --git a/filters/noparallel/nbdkit-noparallel-filter.pod b/filters/noparallel/nbdkit-noparallel-filter.pod index 16861ad9..8ac8d1a7 100644 --- a/filters/noparallel/nbdkit-noparallel-filter.pod +++ b/filters/noparallel/nbdkit-noparallel-filter.pod @@ -76,6 +76,7 @@ L<nbdkit-file-plugin(1)>, L<nbdkit-filter(3)>, L<nbdkit-fua-filter(1)>, L<nbdkit-limit-filter(1)>, +L<nbdkit-multi-conn-filter(1)>, L<nbdkit-nocache-filter(1)>, L<nbdkit-noextents-filter(1)>, L<nbdkit-nozero-filter(1)>. diff --git a/filters/nozero/nbdkit-nozero-filter.pod b/filters/nozero/nbdkit-nozero-filter.pod index 27a030f4..ad6e590d 100644 --- a/filters/nozero/nbdkit-nozero-filter.pod +++ b/filters/nozero/nbdkit-nozero-filter.pod @@ -131,6 +131,7 @@ L<nbdkit(1)>, L<nbdkit-file-plugin(1)>, L<nbdkit-filter(3)>, L<nbdkit-fua-filter(1)>, +L<nbdkit-multi-conn-filter(1)>, L<nbdkit-nocache-filter(1)>, L<nbdkit-noparallel-filter(1)>, L<nbdkit-noextents-filter(1)>. diff --git a/configure.ac b/configure.ac index 587fac0c..4c376a07 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ # nbdkit -# Copyright (C) 2013-2020 Red Hat Inc. +# Copyright (C) 2013-2021 Red Hat Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -128,6 +128,7 @@ filters="\ ip \ limit \ log \ + multi-conn \ nocache \ noextents \ nofilter \ @@ -1259,6 +1260,7 @@ AC_CONFIG_FILES([Makefile filters/ip/Makefile filters/limit/Makefile filters/log/Makefile + filters/multi-conn/Makefile filters/nocache/Makefile filters/noextents/Makefile filters/nofilter/Makefile diff --git a/filters/multi-conn/Makefile.am b/filters/multi-conn/Makefile.am new file mode 100644 index 00000000..778b8947 --- /dev/null +++ b/filters/multi-conn/Makefile.am @@ -0,0 +1,68 @@ +# nbdkit +# Copyright (C) 2021 Red Hat Inc. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * 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. +# +# * 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. +# +# 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. + +include $(top_srcdir)/common-rules.mk + +EXTRA_DIST = nbdkit-multi-conn-filter.pod + +filter_LTLIBRARIES = nbdkit-multi-conn-filter.la + +nbdkit_multi_conn_filter_la_SOURCES = \ + multi-conn.c \ + $(top_srcdir)/include/nbdkit-filter.h \ + $(NULL) + +nbdkit_multi_conn_filter_la_CPPFLAGS = \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/common/include \ + -I$(top_srcdir)/common/utils \ + $(NULL) +nbdkit_multi_conn_filter_la_CFLAGS = $(WARNINGS_CFLAGS) +nbdkit_multi_conn_filter_la_LIBADD = \ + $(top_builddir)/common/utils/libutils.la \ + $(IMPORT_LIBRARY_ON_WINDOWS) \ + $(NULL) +nbdkit_multi_conn_filter_la_LDFLAGS = \ + -module -avoid-version -shared $(NO_UNDEFINED_ON_WINDOWS) \ + -Wl,--version-script=$(top_srcdir)/filters/filters.syms \ + $(NULL) + +if HAVE_POD + +man_MANS = nbdkit-multi-conn-filter.1 +CLEANFILES += $(man_MANS) + +nbdkit-multi-conn-filter.1: nbdkit-multi-conn-filter.pod + $(PODWRAPPER) --section=1 --man $@ \ + --html $(top_builddir)/html/$@.html \ + $< + +endif HAVE_POD diff --git a/tests/Makefile.am b/tests/Makefile.am index e8c9c535..22cafa21 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1544,6 +1544,15 @@ EXTRA_DIST += \ test-log-script-info.sh \ $(NULL) +# multi-conn filter test. +TESTS += \ + test-multi-conn.sh \ + $(NULL) +EXTRA_DIST += \ + test-multi-conn-plugin.sh \ + test-multi-conn.sh \ + $(NULL) + # nofilter test. TESTS += test-nofilter.sh EXTRA_DIST += test-nofilter.sh diff --git a/filters/multi-conn/multi-conn.c b/filters/multi-conn/multi-conn.c new file mode 100644 index 00000000..ed17f7c6 --- /dev/null +++ b/filters/multi-conn/multi-conn.c @@ -0,0 +1,435 @@ +/* nbdkit + * Copyright (C) 2021 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * 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. + * + * 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. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <stdbool.h> +#include <assert.h> +#include <pthread.h> + +#include <nbdkit-filter.h> + +#include "cleanup.h" +#include "vector.h" + +/* Track results of .config */ +static enum MultiConnMode { + AUTO, + EMULATE, + PLUGIN, + UNSAFE, + DISABLE, +} mode; + +static enum TrackDirtyMode { + CONN, + FAST, + OFF, +} track; + +enum dirty { + WRITE = 1, /* A write may have populated a cache */ + READ = 2, /* A read may have populated a cache */ +}; + +/* Coordination between connections. */ +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + +/* The list of handles to active connections. */ +struct handle { + nbdkit_next *next; + enum MultiConnMode mode; /* Runtime resolution of mode==AUTO */ + enum dirty dirty; /* What aspects of this connection are dirty */ +}; +DEFINE_VECTOR_TYPE(conns_vector, struct handle *); +static conns_vector conns = empty_vector; +static bool dirty; /* True if any connection is dirty */ + +/* Accept 'multi-conn-mode=mode' and 'multi-conn-track-dirty=level' */ +static int +multi_conn_config (nbdkit_next_config *next, nbdkit_backend *nxdata, + const char *key, const char *value) +{ + if (strcmp (key, "multi-conn-mode") == 0) { + if (strcmp (value, "auto") == 0) + mode = AUTO; + else if (strcmp (value, "emulate") == 0) + mode = EMULATE; + else if (strcmp (value, "plugin") == 0) + mode = PLUGIN; + else if (strcmp (value, "disable") == 0) + mode = DISABLE; + else if (strcmp (value, "unsafe") == 0) + mode = UNSAFE; + else { + nbdkit_error ("unknown multi-conn mode '%s'", value); + return -1; + } + return 0; + } + else if (strcmp (key, "multi-conn-track-dirty") == 0) { + if (strcmp (value, "connection") == 0 || + strcmp (value, "conn") == 0) + track = CONN; + else if (strcmp (value, "fast") == 0) + track = FAST; + else if (strcmp (value, "off") == 0) + track = OFF; + else { + nbdkit_error ("unknown multi-conn track-dirty setting '%s'", value); + return -1; + } + return 0; + } + return next (nxdata, key, value); +} + +#define multi_conn_config_help \ + "multi-conn-mode=<MODE> 'auto' (default), 'emulate', 'plugin',\n" \ + " 'disable', or 'unsafe'.\n" \ + "multi-conn-track-dirty=<LEVEL> 'conn' (default), 'fast', or 'off'.\n" + +static int +multi_conn_get_ready (nbdkit_next_get_ready *next, nbdkit_backend *nxdata, + int thread_model) +{ + if (thread_model == NBDKIT_THREAD_MODEL_SERIALIZE_CONNECTIONS && + mode == AUTO) + mode = DISABLE; + return next (nxdata); +} + +static void * +multi_conn_open (nbdkit_next_open *next, nbdkit_context *nxdata, + int readonly, const char *exportname, int is_tls) +{ + struct handle *h; + + if (next (nxdata, readonly, exportname) == -1) + return NULL; + + /* Allocate here, but populate and insert into list in .prepare */ + h = calloc (1, sizeof *h); + if (h == NULL) { + nbdkit_error ("calloc: %m"); + return NULL; + } + return h; +} + +static int +multi_conn_prepare (nbdkit_next *next, void *handle, int readonly) +{ + struct handle *h = handle; + int r; + + h->next = next; + if (mode == AUTO) { /* See also .get_ready turning AUTO into DISABLE */ + r = next->can_multi_conn (next); + if (r == -1) + return -1; + if (r == 0) + h->mode = EMULATE; + else + h->mode = PLUGIN; + } + else + h->mode = mode; + if (h->mode == EMULATE && next->can_flush (next) != 1) { + nbdkit_error ("emulating multi-conn requires working flush"); + return -1; + } + + ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); + return conns_vector_append (&conns, h); +} + +static int +multi_conn_finalize (nbdkit_next *next, void *handle) +{ + struct handle *h = handle; + + ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); + assert (h->next == next); + + /* XXX should we add a config param to flush if the client forgot? */ + for (size_t i = 0; i < conns.size; i++) { + if (conns.ptr[i] == h) { + conns_vector_remove (&conns, i); + break; + } + } + return 0; +} + +static void +multi_conn_close (void *handle) +{ + free (handle); +} + +static int +multi_conn_can_fua (nbdkit_next *next, void *handle) +{ + /* If the backend has native FUA support but is not multi-conn + * consistent, and we have to flush on every connection, then we are + * better off advertising emulated fua rather than native. + */ + struct handle *h = handle; + int fua = next->can_fua (next); + + assert (h->mode != AUTO); + if (fua == NBDKIT_FUA_NATIVE && h->mode == EMULATE) + return NBDKIT_FUA_EMULATE; + return fua; +} + +static int +multi_conn_can_multi_conn (nbdkit_next *next, void *handle) +{ + struct handle *h = handle; + + switch (h->mode) { + case EMULATE: + return 1; + case PLUGIN: + return next->can_multi_conn (next); + case DISABLE: + return 0; + case UNSAFE: + return 1; + case AUTO: /* Not possible, see .prepare */ + default: + abort (); + } +} + +static void +mark_dirty (struct handle *h, bool is_write) +{ + /* No need to grab lock here: the NBD spec is clear that a client + * must wait for the response to a flush before sending the next + * command that expects to see the result of that flush, so any race + * in accessing dirty can be traced back to the client improperly + * sending a flush in parallel with other live commands. + */ + switch (track) { + case CONN: + h->dirty |= is_write ? WRITE : READ; + /* fallthrough */ + case FAST: + if (is_write) + dirty = true; + break; + case OFF: + break; + default: + abort (); + } +} + +static int +multi_conn_flush (nbdkit_next *next, + void *handle, uint32_t flags, int *err); + +static int +multi_conn_pread (nbdkit_next *next, + void *handle, void *buf, uint32_t count, uint64_t offs, + uint32_t flags, int *err) +{ + struct handle *h = handle; + + mark_dirty (h, false); + return next->pread (next, buf, count, offs, flags, err); +} + +static int +multi_conn_pwrite (nbdkit_next *next, + void *handle, const void *buf, uint32_t count, + uint64_t offs, uint32_t flags, int *err) +{ + struct handle *h = handle; + bool need_flush = false; + + if (flags & NBDKIT_FLAG_FUA) { + if (h->mode == EMULATE) { + mark_dirty (h, true); + need_flush = true; + flags &= ~NBDKIT_FLAG_FUA; + } + } + else + mark_dirty (h, true); + + if (next->pwrite (next, buf, count, offs, flags, err) == -1) + return -1; + if (need_flush) + return multi_conn_flush (next, h, 0, err); + return 0; +} + +static int +multi_conn_zero (nbdkit_next *next, + void *handle, uint32_t count, uint64_t offs, uint32_t flags, + int *err) +{ + struct handle *h = handle; + bool need_flush = false; + + if (flags & NBDKIT_FLAG_FUA) { + if (h->mode == EMULATE) { + mark_dirty (h, true); + need_flush = true; + flags &= ~NBDKIT_FLAG_FUA; + } + } + else + mark_dirty (h, true); + + if (next->zero (next, count, offs, flags, err) == -1) + return -1; + if (need_flush) + return multi_conn_flush (next, h, 0, err); + return 0; +} + +static int +multi_conn_trim (nbdkit_next *next, + void *handle, uint32_t count, uint64_t offs, uint32_t flags, + int *err) +{ + struct handle *h = handle; + bool need_flush = false; + + if (flags & NBDKIT_FLAG_FUA) { + if (h->mode == EMULATE) { + mark_dirty (h, true); + need_flush = true; + flags &= ~NBDKIT_FLAG_FUA; + } + } + else + mark_dirty (h, true); + + if (next->trim (next, count, offs, flags, err) == -1) + return -1; + if (need_flush) + return multi_conn_flush (next, h, 0, err); + return 0; +} + +static int +multi_conn_cache (nbdkit_next *next, + void *handle, uint32_t count, uint64_t offs, uint32_t flags, + int *err) +{ + struct handle *h = handle; + + mark_dirty (h, false); + return next->cache (next, count, offs, flags, err); +} + +static int +multi_conn_flush (nbdkit_next *next, + void *handle, uint32_t flags, int *err) +{ + struct handle *h = handle, *h2; + size_t i; + + if (h->mode == EMULATE) { + ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); + for (i = 0; i < conns.size; i++) { + h2 = conns.ptr[i]; + if (track == OFF || (dirty && (track == FAST || h2->dirty & READ)) || + h2->dirty & WRITE) { + if (h2->next->flush (h2->next, flags, err) == -1) + return -1; + h2->dirty = 0; + } + } + dirty = 0; + } + else { + /* !EMULATE: Check if the image is clean, allowing us to skip a flush. */ + if (track != OFF && !dirty) + return 0; + /* Perform the flush, then update dirty tracking. */ + if (next->flush (next, flags, err) == -1) + return -1; + switch (track) { + case CONN: + if (next->can_multi_conn (next) == 1) { + ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); + for (i = 0; i < conns.size; i++) + conns.ptr[i]->dirty = 0; + dirty = 0; + } + else + h->dirty = 0; + break; + case FAST: + dirty = false; + break; + case OFF: + break; + default: + abort (); + } + } + return 0; +} + +static struct nbdkit_filter filter = { + .name = "multi-conn", + .longname = "nbdkit multi-conn filter", + .config = multi_conn_config, + .config_help = multi_conn_config_help, + .get_ready = multi_conn_get_ready, + .open = multi_conn_open, + .prepare = multi_conn_prepare, + .finalize = multi_conn_finalize, + .close = multi_conn_close, + .can_fua = multi_conn_can_fua, + .can_multi_conn = multi_conn_can_multi_conn, + .pread = multi_conn_pread, + .pwrite = multi_conn_pwrite, + .trim = multi_conn_trim, + .zero = multi_conn_zero, + .cache = multi_conn_cache, + .flush = multi_conn_flush, +}; + +NBDKIT_REGISTER_FILTER(filter) diff --git a/tests/test-multi-conn-plugin.sh b/tests/test-multi-conn-plugin.sh new file mode 100755 index 00000000..7262a348 --- /dev/null +++ b/tests/test-multi-conn-plugin.sh @@ -0,0 +1,122 @@ +#!/usr/bin/env bash +# nbdkit +# Copyright (C) 2018-2021 Red Hat Inc. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * 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. +# +# * 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. +# +# 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. + +# Test plugin used by test-multi-conn.sh. +# This plugin purposefully maintains a per-connection cache. +# An optional parameter tightfua=true controls whether FUA acts on +# just the given region, or on all pending ops in the current connection. +# Note that an earlier cached write on one connection can overwrite a later +# FUA write on another connection - this is okay (the client is buggy if +# it ever sends overlapping writes without coordinating flushes and still +# expects any particular write to occur last). + +fill_cache() { + if test ! -f "$tmpdir/$1"; then + cp "$tmpdir/0" "$tmpdir/$1" + fi +} +do_fua() { + case ,$4, in + *,fua,*) + if test -f "$tmpdir/strictfua"; then + dd of="$tmpdir/0" if="$tmpdir/$1" skip=$3 seek=$3 count=$2 \ + conv=notrunc iflag=count_bytes,skip_bytes oflag=seek_bytes + else + do_flush $1 + fi ;; + esac +} +do_flush() { + if test -f "$tmpdir/$1-replay"; then + while read cnt off; do + dd of="$tmpdir/0" if="$tmpdir/$1" skip=$off seek=$off count=$cnt \ + conv=notrunc iflag=count_bytes,skip_bytes oflag=seek_bytes + done < "$tmpdir/$1-replay" + fi + rm -f "$tmpdir/$1" "$tmpdir/$1-replay" +} +case "$1" in + config) + case $2 in + strictfua) + case $3 in + true | on | 1) touch "$tmpdir/strictfua" ;; + false | off | 0) ;; + *) echo "unknown value for strictfua $3" >&2; exit 1 ;; + esac ;; + *) echo "unknown config key $2" >&2; exit 1 ;; + esac + ;; + get_ready) + printf "%-32s" 'Initial contents' > "$tmpdir/0" + echo 0 > "$tmpdir/counter" + ;; + get_size) + echo 32 + ;; + can_write | can_zero | can_trim | can_flush) + exit 0 + ;; + can_fua | can_cache) + echo native + ;; + open) + read i < "$tmpdir/counter" + echo $((i+1)) | tee "$tmpdir/counter" + ;; + pread) + fill_cache $2 + dd if="$tmpdir/$2" skip=$4 count=$3 iflag=count_bytes,skip_bytes + ;; + cache) + fill_cache $2 + ;; + pwrite) + fill_cache $2 + dd of="$tmpdir/$2" seek=$4 conv=notrunc oflag=seek_bytes + echo $3 $4 >> "$tmpdir/$2-replay" + do_fua $2 $3 $4 $5 + ;; + zero | trim) + fill_cache $2 + dd of="$tmpdir/$2" if="/dev/zero" count=$3 seek=$4 conv=notrunc\ + oflag=seek_bytes iflag=count_bytes + echo $3 $4 >> "$tmpdir/$2-replay" + do_fua $2 $3 $4 $5 + ;; + flush) + do_flush $2 + ;; + *) + exit 2 + ;; +esac diff --git a/tests/test-multi-conn.sh b/tests/test-multi-conn.sh new file mode 100755 index 00000000..8580608e --- /dev/null +++ b/tests/test-multi-conn.sh @@ -0,0 +1,293 @@ +#!/usr/bin/env bash +# nbdkit +# Copyright (C) 2018-2021 Red Hat Inc. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * 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. +# +# * 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. +# +# 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. + +# Demonstrate various multi-conn filter behaviors. + +source ./functions.sh +set -e +set -x + +requires_plugin sh +requires_nbdsh_uri +requires dd iflag=count_bytes </dev/null + +files="test-multi-conn.out test-multi-conn.stat" +rm -f $files +cleanup_fn rm -f $files + +fail=0 +export handles preamble uri +uri= # will be set by --run later +handles=3 +preamble=' +import os + +uri = os.environ["uri"] +handles = int(os.environ["handles"]) +h = [] +for i in range(handles): + h.append(nbd.NBD()) + h[i].connect_uri(uri) +print(h[0].can_multi_conn()) +' + +# Demonstrate the caching present without use of filter +for filter in '' '--filter=multi-conn multi-conn-mode=plugin'; do + nbdkit -vf -U - sh test-multi-conn-plugin.sh $filter \ + --run 'handles=4 nbdsh -c "$preamble" -c " +# Without flush, reads cache, and writes do not affect persistent data +print(h[0].pread(4, 0)) +h[1].pwrite(b'\''next '\'', 0) +print(h[0].pread(4, 0)) +print(h[1].pread(4, 0)) +print(h[2].pread(4, 0)) +# Flushing an unrelated connection does not make writes persistent +h[2].flush() +print(h[0].pread(4, 0)) +print(h[1].pread(4, 0)) +print(h[2].pread(4, 0)) +# After write is flushed, only connections without cache see new data +h[1].flush() +print(h[0].pread(4, 0)) +print(h[1].pread(4, 0)) +print(h[2].pread(4, 0)) +print(h[3].pread(4, 0)) +# Flushing before reads clears the cache +h[0].flush() +h[2].flush() +print(h[0].pread(4, 0)) +print(h[2].pread(4, 0)) +"' > test-multi-conn.out || fail=1 + diff -u <(cat <<\EOF +False +b'Init' +b'Init' +b'next' +b'Init' +b'Init' +b'next' +b'Init' +b'Init' +b'next' +b'Init' +b'next' +b'next' +b'next' +EOF + ) test-multi-conn.out || fail=1 +done + +# Demonstrate specifics of FUA flag +for filter in '' '--filter=multi-conn multi-conn-mode=plugin'; do + nbdkit -vf -U - sh test-multi-conn-plugin.sh $filter \ + --run 'nbdsh -c "$preamble" -c " +# Some servers let FUA flush all outstanding requests +h[0].pwrite(b'\''hello '\'', 0) +h[0].pwrite(b'\''world.'\'', 6, nbd.CMD_FLAG_FUA) +print(h[1].pread(12, 0)) +"' > test-multi-conn.out || fail=1 + diff -u <(cat <<\EOF +False +b'hello world.' +EOF + ) test-multi-conn.out || fail=1 +done +for filter in '' '--filter=multi-conn multi-conn-mode=plugin'; do + nbdkit -vf -U - sh test-multi-conn-plugin.sh strictfua=1 $filter \ + --run 'nbdsh -c "$preamble" -c " +# But it is also compliant for a server that only flushes the exact request +h[0].pwrite(b'\''hello '\'', 0) +h[0].pwrite(b'\''world.'\'', 6, nbd.CMD_FLAG_FUA) +print(h[1].pread(12, 0)) +# Without multi-conn, data flushed in one connection can later be reverted +# by a flush of earlier data in another connection +h[1].pwrite(b'\''H'\'', 0, nbd.CMD_FLAG_FUA) +h[2].flush() +print(h[2].pread(12, 0)) +h[0].flush() +h[2].flush() +print(h[2].pread(12, 0)) +h[1].flush() +h[2].flush() +print(h[2].pread(12, 0)) +"' > test-multi-conn.out || fail=1 + diff -u <(cat <<\EOF +False +b'Initiaworld.' +b'Hnitiaworld.' +b'hello world.' +b'Hello world.' +EOF + ) test-multi-conn.out || fail=1 +done + +# Demonstrate multi-conn effects. The cache filter in writeback +# mode is also able to supply multi-conn by a different technique. +for filter in '--filter=multi-conn' 'strictfua=1 --filter=multi-conn' \ + '--filter=multi-conn multi-conn-mode=plugin --filter=cache' ; do + nbdkit -vf -U - sh test-multi-conn-plugin.sh $filter \ + --run 'nbdsh -c "$preamble" -c " +# FUA writes are immediately visible on all connections +h[0].cache(12, 0) +h[1].pwrite(b'\''Hello '\'', 0, nbd.CMD_FLAG_FUA) +print(h[0].pread(12, 0)) +# A flush on an unrelated connection makes all other connections consistent +h[1].pwrite(b'\''world.'\'', 6) +h[2].flush() +print(h[0].pread(12, 0)) +"' > test-multi-conn.out || fail=1 + diff -u <(cat <<\EOF +True +b'Hello l cont' +b'Hello world.' +EOF + ) test-multi-conn.out || fail=1 +done + +# unsafe mode intentionally lacks consistency, use at your own risk +nbdkit -vf -U - sh test-multi-conn-plugin.sh \ + --filter=multi-conn multi-conn-mode=unsafe \ + --run 'nbdsh -c "$preamble" -c " +h[0].cache(12, 0) +h[1].pwrite(b'\''Hello '\'', 0, nbd.CMD_FLAG_FUA) +print(h[0].pread(12, 0)) +h[1].pwrite(b'\''world.'\'', 6) +h[2].flush() +print(h[0].pread(12, 0)) +"' > test-multi-conn.out || fail=1 +diff -u <(cat <<\EOF +True +b'Initial cont' +b'Initial cont' +EOF + ) test-multi-conn.out || fail=1 + +# auto mode devolves to multi-conn disable when connections are serialized +nbdkit -vf -U - sh test-multi-conn-plugin.sh --filter=noparallel \ + serialize=connections --filter=multi-conn --filter=cache \ + --run 'handles=1 nbdsh -c "$preamble" +' > test-multi-conn.out || fail=1 +diff -u <(cat <<\EOF +False +EOF + ) test-multi-conn.out || fail=1 + +# Use --filter=stats to show track-dirty effects +for level in off connection fast; do + for mode in emulate 'emulate --filter=cache' \ + plugin 'plugin --filter=cache'; do + echo "setup: $level $mode" >> test-multi-conn.stat + # Flush with no activity + nbdkit -vf -U - sh test-multi-conn-plugin.sh --filter=multi-conn \ + --filter=stats statsfile=test-multi-conn.stat statsappend=true \ + multi-conn-track-dirty=$level multi-conn-mode=$mode \ + --run 'nbdsh -c "$preamble" -c " +h[0].flush() +h[0].pread(1, 0) +h[0].flush() +"' > test-multi-conn.out || fail=1 + # Client that flushes assuming multi-conn semantics + nbdkit -vf -U - sh test-multi-conn-plugin.sh --filter=multi-conn \ + --filter=stats statsfile=test-multi-conn.stat statsappend=true \ + multi-conn-track-dirty=$level multi-conn-mode=$mode \ + --run 'handles=4 nbdsh -c "$preamble" -c " +h[0].pread(1, 0) +h[1].zero(1, 0) +h[3].flush() +h[2].zero(1, 1) +h[0].pread(1, 0) +h[3].flush() +h[3].flush() +"' > test-multi-conn.out || fail=1 + # Client that flushes assuming inconsistent semantics + nbdkit -vf -U - sh test-multi-conn-plugin.sh --filter=multi-conn \ + --filter=stats statsfile=test-multi-conn.stat statsappend=true \ + multi-conn-track-dirty=$level multi-conn-mode=$mode \ + --run 'nbdsh -c "$preamble" -c " +h[0].pread(1, 0) +h[1].trim(1, 0) +h[0].flush() +h[1].flush() +h[0].pread(1, 0) +h[2].trim(1, 1) +h[0].flush() +h[2].flush() +"' > test-multi-conn.out || fail=1 + done +done +cat test-multi-conn.stat +diff -u <(cat <<\EOF +setup: off emulate +flush: 6 ops +flush: 12 ops +flush: 12 ops +setup: off emulate --filter=cache +flush: 6 ops +flush: 12 ops +flush: 12 ops +setup: off plugin +flush: 2 ops +flush: 3 ops +flush: 4 ops +setup: off plugin --filter=cache +flush: 2 ops +flush: 3 ops +flush: 4 ops +setup: connection emulate +flush: 4 ops +flush: 4 ops +setup: connection emulate --filter=cache +flush: 4 ops +flush: 4 ops +setup: connection plugin +flush: 3 ops +flush: 4 ops +setup: connection plugin --filter=cache +flush: 2 ops +flush: 2 ops +setup: fast emulate +flush: 8 ops +flush: 6 ops +setup: fast emulate --filter=cache +flush: 8 ops +flush: 6 ops +setup: fast plugin +flush: 2 ops +flush: 2 ops +setup: fast plugin --filter=cache +flush: 2 ops +flush: 2 ops +EOF + ) <(sed -n 's/\(flush:.*ops\).*/\1/p; /^setup:/p' \ + test-multi-conn.stat) || fail=1 + +exit $fail diff --git a/TODO b/TODO index 2bde2478..6857484a 100644 --- a/TODO +++ b/TODO @@ -210,13 +210,6 @@ Suggestions for filters * masking plugin features for testing clients (see 'nozero' and 'fua' filters for examples) -* multi-conn filter to adjust advertisement of multi-conn bit. In - particular, if the plugin lacks .can_multi_conn, then .open/.close - track all open connections, and .flush and FUA flag will call - next_ops->flush() on all of them. Conversely, if plugin supports - multi-conn, we can cache whether the image is dirty, and avoid - expense of next_ops->flush when it is clean. - * "bandwidth quota" filter which would close a connection after it exceeded a certain amount of bandwidth up or down. -- 2.30.1
Eric Blake
2021-Mar-05 23:31 UTC
[Libguestfs] [nbdkit PATCH v3 16/16] multi-conn: Knob to limit consistency emulation by export name
We can't enable the knob by default since many nbdkit plugins don't care about export name, but it is certainly more efficient to limit consistency to just clients visiting the same export. Thankfully, NBD_CMD_FLUSH does not take size and offset, and therefore is safe (although wasting CPU cycles) to use even when a different export has a different size. Done by adding another layer of indirection: all connections are combined into a group (a singleton when the knob is off, or by name when the knob is on), moving fast dirty tracking into that group. --- .../multi-conn/nbdkit-multi-conn-filter.pod | 27 +++- tests/Makefile.am | 2 + filters/multi-conn/multi-conn.c | 118 +++++++++++++++--- tests/test-multi-conn-name.sh | 88 +++++++++++++ tests/test-multi-conn-plugin.sh | 63 ++++++---- 5 files changed, 255 insertions(+), 43 deletions(-) create mode 100755 tests/test-multi-conn-name.sh diff --git a/filters/multi-conn/nbdkit-multi-conn-filter.pod b/filters/multi-conn/nbdkit-multi-conn-filter.pod index c8f334b3..efeba570 100644 --- a/filters/multi-conn/nbdkit-multi-conn-filter.pod +++ b/filters/multi-conn/nbdkit-multi-conn-filter.pod @@ -5,7 +5,7 @@ nbdkit-multi-conn-filter - nbdkit multi-conn filter =head1 SYNOPSIS nbdkit --filter=multi-conn plugin [multi-conn-mode=MODE] \ - [multi-conn-track-dirty=LEVEL] [plugin-args...] + [multi-conn-track-dirty=LEVEL] [multi-conn-exportname=BOOL] [plugin-args...] =head1 DESCRIPTION @@ -26,7 +26,8 @@ it also has additional modes useful for evaluating performance and correctness of client and plugin multi-conn behaviors. This filter assumes that multiple connections to a plugin will eventually share data, other than any caching effects; it is not suitable for use with -a plugin that produces completely independent data per connection. +a plugin that produces completely independent data per connection from +the same export name. Additional control over the behavior of client flush commands is possible by combining this filter with L<nbdkit-fua-filter(1)>. Note @@ -125,6 +126,27 @@ B<multi-conn-mode=emulate>, a client which disregards NBD_FLAG_MULTI_CONN by flushing on each connection itself results in a quadratic number of flush operations on the plugin. +=item B<multi-conn-exportname=false> + +The exportname switch defaults to false for safety, and causes the +filter to flush across all active connections regardless of the export +name in use by that connection when doing emulation. However, when a +plugin supports distinct data according to export name, this behavior +will penalize the performance of clients visiting an unrelated export +by spending time on replicated flush operations not actually relevant +to that export. + +=item B<multi-conn-exportname=true> + +Setting the exportname switch to true causes the filter to only +synchronize flushes to connections visiting the same export name. +This avoids penalizing clients visiting an unrelated export name (such +as L<nbdkit-file-plugin(1)> in B<dir=> mode), but is unsafe when used +with a plugin that serves shared content across all connections +regardless of the export name requested by the client, if that plugin +is not already multi-conn consistent (such as +L<nbdkit-vddk-plugin(1)>). + =back =head1 EXAMPLES @@ -161,6 +183,7 @@ C<nbdkit-multi-conn-filter> first appeared in nbdkit 1.26. L<nbdkit(1)>, L<nbdkit-file-plugin(1)>, +L<nbdkit-vddk-plugin(1)>, L<nbdkit-filter(3)>, L<nbdkit-cache-filter(1)>, L<nbdkit-fua-filter(1)>, diff --git a/tests/Makefile.am b/tests/Makefile.am index 22cafa21..631d5014 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1547,10 +1547,12 @@ EXTRA_DIST += \ # multi-conn filter test. TESTS += \ test-multi-conn.sh \ + test-multi-conn-name.sh \ $(NULL) EXTRA_DIST += \ test-multi-conn-plugin.sh \ test-multi-conn.sh \ + test-multi-conn-name.sh \ $(NULL) # nofilter test. diff --git a/filters/multi-conn/multi-conn.c b/filters/multi-conn/multi-conn.c index ed17f7c6..1b1c9d8c 100644 --- a/filters/multi-conn/multi-conn.c +++ b/filters/multi-conn/multi-conn.c @@ -60,6 +60,8 @@ static enum TrackDirtyMode { OFF, } track; +static bool byname = false; + enum dirty { WRITE = 1, /* A write may have populated a cache */ READ = 2, /* A read may have populated a cache */ @@ -73,12 +75,21 @@ struct handle { nbdkit_next *next; enum MultiConnMode mode; /* Runtime resolution of mode==AUTO */ enum dirty dirty; /* What aspects of this connection are dirty */ + char *name; /* Used when byname==true to assign group */ + struct group *group; /* All connections grouped with this one */ }; DEFINE_VECTOR_TYPE(conns_vector, struct handle *); -static conns_vector conns = empty_vector; -static bool dirty; /* True if any connection is dirty */ +struct group { + conns_vector conns; + char *name; + bool dirty; /* True if any connection in group is dirty */ +}; +DEFINE_VECTOR_TYPE(group_vector, struct group *); +static group_vector groups = empty_vector; -/* Accept 'multi-conn-mode=mode' and 'multi-conn-track-dirty=level' */ +/* Accept 'multi-conn-mode=mode', 'multi-conn-track-dirty=level', and + * 'multi-conn-exportname=bool'. + */ static int multi_conn_config (nbdkit_next_config *next, nbdkit_backend *nxdata, const char *key, const char *value) @@ -114,13 +125,24 @@ multi_conn_config (nbdkit_next_config *next, nbdkit_backend *nxdata, } return 0; } + else if (strcmp (key, "multi-conn-exportname") == 0 || + strcmp (key, "multi-conn-export-name") == 0) { + int r; + + r = nbdkit_parse_bool (value); + if (r == -1) + return -1; + byname = r; + return 0; + } return next (nxdata, key, value); } #define multi_conn_config_help \ "multi-conn-mode=<MODE> 'auto' (default), 'emulate', 'plugin',\n" \ " 'disable', or 'unsafe'.\n" \ - "multi-conn-track-dirty=<LEVEL> 'conn' (default), 'fast', or 'off'.\n" + "multi-conn-track-dirty=<LEVEL> 'conn' (default), 'fast', or 'off'.\n" \ + "multi-conn-exportname=<BOOL> true to limit emulation by export name.\n" static int multi_conn_get_ready (nbdkit_next_get_ready *next, nbdkit_backend *nxdata, @@ -147,6 +169,13 @@ multi_conn_open (nbdkit_next_open *next, nbdkit_context *nxdata, nbdkit_error ("calloc: %m"); return NULL; } + if (byname) { + h->name = strdup (exportname); + if (h->name == NULL) { + nbdkit_error ("strdup: %m"); + return NULL; + } + } return h; } @@ -154,6 +183,8 @@ static int multi_conn_prepare (nbdkit_next *next, void *handle, int readonly) { struct handle *h = handle; + struct group *g; + bool new_group = false; int r; h->next = next; @@ -174,7 +205,39 @@ multi_conn_prepare (nbdkit_next *next, void *handle, int readonly) } ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); - return conns_vector_append (&conns, h); + if (byname) { + g = NULL; + for (size_t i = 0; i < groups.size; i++) + if (strcmp (groups.ptr[i]->name, h->name) == 0) { + g = groups.ptr[i]; + break; + } + } + else + g = groups.size ? groups.ptr[0] : NULL; + + if (!g) { + g = calloc (1, sizeof *g); + if (g == NULL) { + nbdkit_error ("calloc: %m"); + return -1; + } + if (group_vector_append (&groups, g) == -1) + return -1; + g->name = h->name; + h->name = NULL; + new_group = true; + } + if (conns_vector_append (&g->conns, h) == -1) { + if (new_group) { + group_vector_remove (&groups, groups.size - 1); + free (g->name); + free (g); + } + return -1; + } + h->group = g; + return 0; } static int @@ -184,21 +247,36 @@ multi_conn_finalize (nbdkit_next *next, void *handle) ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); assert (h->next == next); + assert (h->group); /* XXX should we add a config param to flush if the client forgot? */ - for (size_t i = 0; i < conns.size; i++) { - if (conns.ptr[i] == h) { - conns_vector_remove (&conns, i); + for (size_t i = 0; i < h->group->conns.size; i++) { + if (h->group->conns.ptr[i] == h) { + conns_vector_remove (&h->group->conns, i); break; } } + if (h->group->conns.size == 0) { + for (size_t i = 0; i < groups.size; i++) + if (groups.ptr[i] == h->group) { + group_vector_remove (&groups, i); + free (h->group->name); + free (h->group); + break; + } + } + h->group = NULL; return 0; } static void multi_conn_close (void *handle) { - free (handle); + struct handle *h = handle; + + assert (h->group == NULL); + free (h->name); + free (h); } static int @@ -252,7 +330,7 @@ mark_dirty (struct handle *h, bool is_write) /* fallthrough */ case FAST: if (is_write) - dirty = true; + h->group->dirty = true; break; case OFF: break; @@ -369,22 +447,24 @@ multi_conn_flush (nbdkit_next *next, struct handle *h = handle, *h2; size_t i; + assert (h->group); if (h->mode == EMULATE) { ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); - for (i = 0; i < conns.size; i++) { - h2 = conns.ptr[i]; - if (track == OFF || (dirty && (track == FAST || h2->dirty & READ)) || + for (i = 0; i < h->group->conns.size; i++) { + h2 = h->group->conns.ptr[i]; + if (track == OFF || (h->group->dirty && + (track == FAST || h2->dirty & READ)) || h2->dirty & WRITE) { if (h2->next->flush (h2->next, flags, err) == -1) return -1; h2->dirty = 0; } } - dirty = 0; + h->group->dirty = 0; } else { /* !EMULATE: Check if the image is clean, allowing us to skip a flush. */ - if (track != OFF && !dirty) + if (track != OFF && !h->group->dirty) return 0; /* Perform the flush, then update dirty tracking. */ if (next->flush (next, flags, err) == -1) @@ -393,15 +473,15 @@ multi_conn_flush (nbdkit_next *next, case CONN: if (next->can_multi_conn (next) == 1) { ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&lock); - for (i = 0; i < conns.size; i++) - conns.ptr[i]->dirty = 0; - dirty = 0; + for (i = 0; i < h->group->conns.size; i++) + h->group->conns.ptr[i]->dirty = 0; + h->group->dirty = 0; } else h->dirty = 0; break; case FAST: - dirty = false; + h->group->dirty = false; break; case OFF: break; diff --git a/tests/test-multi-conn-name.sh b/tests/test-multi-conn-name.sh new file mode 100755 index 00000000..698d386e --- /dev/null +++ b/tests/test-multi-conn-name.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env bash +# nbdkit +# Copyright (C) 2018-2021 Red Hat Inc. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * 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. +# +# * 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. +# +# 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. + +# Demonstrate effect of multi-conn-exportname config flag + +source ./functions.sh +set -e +set -x + +requires_plugin sh +requires_nbdsh_uri +requires nbdsh -c 'print(h.set_opt_mode)' +requires dd iflag=count_bytes </dev/null + +files="test-multi-conn-name.out" +rm -f $files +cleanup_fn rm -f $files + +fail=0 +export script=' +import os + +uri = os.environ["uri"] +h = {} +for name in ["a", "b"]: + for conn in [1, 2]: + key = "%s%d" % (name, conn) + h[key] = nbd.NBD() + h[key].set_opt_mode(True) + h[key].connect_uri(uri) + h[key].set_export_name(name) + h[key].opt_go() +h["a1"].pread(1, 0) +h["a2"].pwrite(b"A", 0) +h["b1"].pread(1, 0) +h["b2"].pwrite(b"B", 0, nbd.CMD_FLAG_FUA) +print(h["a1"].pread(1, 0)) +print(h["b1"].pread(1, 0)) +' + +# Without the knob we flush all exports +nbdkit -vf -U - sh test-multi-conn-plugin.sh --filter=multi-conn \ + --run 'export uri; nbdsh -c "$script"' > test-multi-conn-name.out || fail=1 +diff -u <(cat <<\EOF +b'A' +b'B' +EOF + ) test-multi-conn-name.out || fail=1 +# But with the knob, our flush is specific to the correct export +nbdkit -vf -U - sh test-multi-conn-plugin.sh --filter=multi-conn \ + multi-conn-exportname=true \ + --run 'export uri; nbdsh -c "$script"' > test-multi-conn-name.out || fail=1 +diff -u <(cat <<\EOF +b'I' +b'B' +EOF + ) test-multi-conn-name.out || fail=1 + +exit $fail diff --git a/tests/test-multi-conn-plugin.sh b/tests/test-multi-conn-plugin.sh index 7262a348..5d627a07 100755 --- a/tests/test-multi-conn-plugin.sh +++ b/tests/test-multi-conn-plugin.sh @@ -39,30 +39,36 @@ # it ever sends overlapping writes without coordinating flushes and still # expects any particular write to occur last). +get_export() { + case $1 in + */*) export="$tmpdir/$(dirname $1)" conn=$(basename $1) ;; + *) export="$tmpdir" conn=$1 ;; + esac +} fill_cache() { - if test ! -f "$tmpdir/$1"; then - cp "$tmpdir/0" "$tmpdir/$1" + if test ! -f "$export/$conn"; then + cp "$export/0" "$export/$conn" fi } do_fua() { - case ,$4, in + case ,$3, in *,fua,*) if test -f "$tmpdir/strictfua"; then - dd of="$tmpdir/0" if="$tmpdir/$1" skip=$3 seek=$3 count=$2 \ + dd of="$export/0" if="$export/$conn" skip=$2 seek=$2 count=$1 \ conv=notrunc iflag=count_bytes,skip_bytes oflag=seek_bytes else - do_flush $1 + do_flush fi ;; esac } do_flush() { - if test -f "$tmpdir/$1-replay"; then + if test -f "$export/$conn-replay"; then while read cnt off; do - dd of="$tmpdir/0" if="$tmpdir/$1" skip=$off seek=$off count=$cnt \ + dd of="$export/0" if="$export/$conn" skip=$off seek=$off count=$cnt \ conv=notrunc iflag=count_bytes,skip_bytes oflag=seek_bytes - done < "$tmpdir/$1-replay" + done < "$export/$conn-replay" fi - rm -f "$tmpdir/$1" "$tmpdir/$1-replay" + rm -f "$export/$conn" "$export/$conn-replay" } case "$1" in config) @@ -91,30 +97,43 @@ case "$1" in ;; open) read i < "$tmpdir/counter" - echo $((i+1)) | tee "$tmpdir/counter" + i=$((i+1)) + echo $i > "$tmpdir/counter" + if test -z "$3"; then + echo $i + else + mkdir -p "$tmpdir/$3" || exit 1 + cp "$tmpdir/0" "$tmpdir/$3/0" + echo "$3/$i" + fi ;; pread) - fill_cache $2 - dd if="$tmpdir/$2" skip=$4 count=$3 iflag=count_bytes,skip_bytes + get_export $2 + fill_cache + dd if="$export/$conn" skip=$4 count=$3 iflag=count_bytes,skip_bytes ;; cache) - fill_cache $2 + get_export $2 + fill_cache ;; pwrite) - fill_cache $2 - dd of="$tmpdir/$2" seek=$4 conv=notrunc oflag=seek_bytes - echo $3 $4 >> "$tmpdir/$2-replay" - do_fua $2 $3 $4 $5 + get_export $2 + fill_cache + dd of="$export/$conn" seek=$4 conv=notrunc oflag=seek_bytes + echo $3 $4 >> "$export/$conn-replay" + do_fua $3 $4 $5 ;; zero | trim) - fill_cache $2 - dd of="$tmpdir/$2" if="/dev/zero" count=$3 seek=$4 conv=notrunc\ + get_export $2 + fill_cache + dd of="$export/$conn" if="/dev/zero" count=$3 seek=$4 conv=notrunc\ oflag=seek_bytes iflag=count_bytes - echo $3 $4 >> "$tmpdir/$2-replay" - do_fua $2 $3 $4 $5 + echo $3 $4 >> "$export/$conn-replay" + do_fua $3 $4 $5 ;; flush) - do_flush $2 + get_export $2 + do_flush ;; *) exit 2 -- 2.30.1