Skip to content

Commit 03dcd2d

Browse files
committed
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.
1 parent df55ba6 commit 03dcd2d

17 files changed

+129
-194
lines changed

docs/nbdkit-filter.pod

+17-16
Original file line numberDiff line numberDiff line change
@@ -132,18 +132,19 @@ C<nbdkit_next_after_fork>, C<nbdkit_next_preconnect>,
132132
C<nbdkit_next_list_exports>, C<nbdkit_next_default_export>,
133133
C<nbdkit_next_open>) and a structure called C<struct nbdkit_next_ops>.
134134
These abstract the next plugin or filter in the chain. There is also
135-
an opaque pointer C<backend> or C<nxdata> which must be passed along
136-
when calling these functions. The value of C<nxdata> passed to
137-
C<.prepare> has a stable lifetime that lasts to the corresponding
138-
C<.finalize>, with all intermediate functions (such as C<.pread>)
139-
receiving the same value for convenience. Functions where C<nxdata>
140-
is not reused are C<.config>, C<.config_complete>, C<.get_ready>, and
141-
C<.after_fork>, which are called during initialization outside any
142-
connections, and C<.preconnect>, C<.list_exports>, C<.default_export>,
143-
and C<.open> which are called based on client connections but prior to
144-
the stable lifetime of C<.prepare>. The value of C<backend> passed to
145-
C<.open> has a lifetime that lasts until the matching C<.close> for
146-
use by C<nbdkit_backend_reopen>.
135+
an opaque pointer C<backend>, C<context> or C<nxdata> which must be
136+
passed along when calling these functions. The value of C<nxdata>
137+
passed to C<.prepare> has a stable lifetime that lasts to the
138+
corresponding C<.finalize>, with all intermediate functions (such as
139+
C<.pread>) receiving the same value for convenience. Functions where
140+
C<nxdata> is not reused are C<.config>, C<.config_complete>,
141+
C<.get_ready>, and C<.after_fork>, which are called during
142+
initialization outside any connections, and C<.preconnect>,
143+
C<.list_exports>, C<.default_export>, and C<.open> which are called
144+
based on client connections but prior to the stable lifetime of
145+
C<.prepare>. The value of C<context> passed to C<.open> has a
146+
lifetime that lasts until the matching C<.close> for use by
147+
C<nbdkit_backend_reopen>.
147148

148149
=head2 Next config, open and close
149150

@@ -429,7 +430,7 @@ C<next> because it cannot be altered.
429430

430431
=head2 C<.open>
431432

432-
void * (*open) (nbdkit_next_open *next, nbdkit_backend *backend,
433+
void * (*open) (nbdkit_next_open *next, nbdkit_context *context,
433434
int readonly, const char *exportname, int is_tls);
434435

435436
This is called when a new client connection is opened and can be used
@@ -471,7 +472,7 @@ outer filter to the plugin will be in reverse. Skipping a call to
471472
C<next> is acceptable if the filter will not access C<next_ops>
472473
during any of the remaining callbacks reached on the same connection.
473474

474-
The value of C<backend> in this call has a lifetime that lasts until
475+
The value of C<context> in this call has a lifetime that lasts until
475476
the counterpart C<.close>, and it is this value (and not the distinct
476477
C<nxdata> of C<.pread> and friends) that must be passed as the first
477478
parameter to C<nbdkit_backend_reopen> by a filter attempting to retry
@@ -481,14 +482,14 @@ a connection into the backend.
481482

482483
Filters have access to a function for reopening the backend:
483484

484-
int nbdkit_backend_reopen (nbdkit_backend *backend, int readonly,
485+
int nbdkit_backend_reopen (nbdkit_context *context, int readonly,
485486
const char *exportname, void **nxdata);
486487

487488
This function is used by L<nbdkit-retry-filter(1)> to close and reopen
488489
the underlying plugin, with possible changes to the C<readonly> and
489490
C<exportname> parameters in relation to the original opening. It
490491
should be used with caution because it is difficult to use safely.
491-
The C<backend> parameter to this function should be the C<backend>
492+
The C<context> parameter to this function should be the C<context>
492493
parameter originally passed in to C<.open>; while the C<nxdata>
493494
pointer should be the address of C<nxdata> from any function with a
494495
C<next_ops> parameter (such as C<.pread>) that wants to call into the

filters/checkwrite/checkwrite.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
#include "minmax.h"
4545

4646
static void *
47-
checkwrite_open (nbdkit_next_open *next, nbdkit_backend *nxdata,
47+
checkwrite_open (nbdkit_next_open *next, nbdkit_context *nxdata,
4848
int readonly, const char *exportname, int is_tls)
4949
{
5050
/* Ignore readonly flag passed in, open the plugin readonly. */

filters/exitlast/exitlast.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
static _Atomic unsigned connections;
5151

5252
static void *
53-
exitlast_open (nbdkit_next_open *next, nbdkit_backend *nxdata,
53+
exitlast_open (nbdkit_next_open *next, nbdkit_context *nxdata,
5454
int readonly, const char *exportname, int is_tls)
5555
{
5656
if (next (nxdata, readonly, exportname) == -1)

filters/exitwhen/exitwhen.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ exitwhen_preconnect (nbdkit_next_preconnect *next, void *nxdata, int readonly)
482482
}
483483

484484
static void *
485-
exitwhen_open (nbdkit_next_open *next, nbdkit_backend *nxdata,
485+
exitwhen_open (nbdkit_next_open *next, nbdkit_context *nxdata,
486486
int readonly, const char *exportname, int is_tls)
487487
{
488488
if (next (nxdata, readonly, exportname) == -1)

filters/gzip/gzip.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ gzip_thread_model (void)
7575
}
7676

7777
static void *
78-
gzip_open (nbdkit_next_open *next, nbdkit_backend *nxdata,
78+
gzip_open (nbdkit_next_open *next, nbdkit_context *nxdata,
7979
int readonly, const char *exportname, int is_tls)
8080
{
8181
/* Always pass readonly=1 to the underlying plugin. */

filters/limit/limit.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ limit_preconnect (nbdkit_next_preconnect *next, nbdkit_backend *nxdata,
9090
}
9191

9292
static void *
93-
limit_open (nbdkit_next_open *next, nbdkit_backend *nxdata,
93+
limit_open (nbdkit_next_open *next, nbdkit_context *nxdata,
9494
int readonly, const char *exportname, int is_tls)
9595
{
9696
if (next (nxdata, readonly, exportname) == -1)

filters/retry/retry.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,13 @@ retry_config (nbdkit_next_config *next, nbdkit_backend *nxdata,
109109
struct retry_handle {
110110
int readonly; /* Save original readonly setting. */
111111
char *exportname; /* Client exportname. */
112-
nbdkit_backend *backend; /* Backend learned during .open. */
112+
nbdkit_context *context; /* Context learned during .open. */
113113
unsigned reopens;
114114
bool open;
115115
};
116116

117117
static void *
118-
retry_open (nbdkit_next_open *next, nbdkit_backend *nxdata,
118+
retry_open (nbdkit_next_open *next, nbdkit_context *nxdata,
119119
int readonly, const char *exportname, int is_tls)
120120
{
121121
struct retry_handle *h;
@@ -131,7 +131,7 @@ retry_open (nbdkit_next_open *next, nbdkit_backend *nxdata,
131131

132132
h->readonly = readonly;
133133
h->exportname = strdup (exportname);
134-
h->backend = nxdata;
134+
h->context = nxdata;
135135
if (h->exportname == NULL) {
136136
nbdkit_error ("strdup: %m");
137137
free (h);
@@ -209,7 +209,7 @@ do_retry (struct retry_handle *h, struct retry_data *data,
209209

210210
/* Reopen the connection. */
211211
h->reopens++;
212-
if (nbdkit_backend_reopen (h->backend, h->readonly || force_readonly,
212+
if (nbdkit_backend_reopen (h->context, h->readonly || force_readonly,
213213
h->exportname, next) == -1) {
214214
/* If the reopen fails we treat it the same way as a command
215215
* failing.

filters/tar/tar.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ struct handle {
112112
};
113113

114114
static void *
115-
tar_open (nbdkit_next_open *next, nbdkit_backend *nxdata,
115+
tar_open (nbdkit_next_open *next, nbdkit_context *nxdata,
116116
int readonly, const char *exportname, int is_tls)
117117
{
118118
struct handle *h;

include/nbdkit-filter.h

+6-3
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,15 @@ extern "C" {
5454
* the next filter or plugin.
5555
*/
5656
typedef struct backend nbdkit_backend;
57+
typedef struct context nbdkit_context;
5758
typedef struct context nbdkit_next;
5859
#elif defined NBDKIT_RETRY_FILTER /* Hack to expose reopen to retry filter */
5960
typedef struct nbdkit_backend nbdkit_backend;
61+
typedef struct nbdkit_context nbdkit_context;
6062
typedef struct nbdkit_next_ops nbdkit_next;
6163
#else
6264
typedef void nbdkit_backend;
65+
typedef void nbdkit_context;
6366
typedef void nbdkit_next;
6467
#endif
6568

@@ -74,7 +77,7 @@ typedef int nbdkit_next_list_exports (nbdkit_backend *nxdata, int readonly,
7477
struct nbdkit_exports *exports);
7578
typedef const char *nbdkit_next_default_export (nbdkit_backend *nxdata,
7679
int readonly);
77-
typedef int nbdkit_next_open (nbdkit_backend *backend,
80+
typedef int nbdkit_next_open (nbdkit_context *context,
7881
int readonly, const char *exportname);
7982

8083
struct nbdkit_next_ops {
@@ -155,7 +158,7 @@ NBDKIT_EXTERN_DECL (const struct nbdkit_export, nbdkit_get_export,
155158
* Used by the retry filter.
156159
*/
157160
NBDKIT_EXTERN_DECL (int, nbdkit_backend_reopen,
158-
(nbdkit_backend *backend, int readonly,
161+
(nbdkit_context *context, int readonly,
159162
const char *exportname, nbdkit_next **nxdata));
160163
#endif
161164

@@ -199,7 +202,7 @@ struct nbdkit_filter {
199202
nbdkit_backend *nxdata,
200203
int readonly, int is_tls);
201204

202-
void * (*open) (nbdkit_next_open *next, nbdkit_backend *backend,
205+
void * (*open) (nbdkit_next_open *next, nbdkit_context *context,
203206
int readonly, const char *exportname, int is_tls);
204207
void (*close) (void *handle);
205208

server/backend.c

+26-44
Original file line numberDiff line numberDiff line change
@@ -163,13 +163,12 @@ backend_list_exports (struct backend *b, int readonly,
163163
struct nbdkit_exports *exports)
164164
{
165165
GET_CONN;
166-
struct context *c = get_context (conn, b);
167166
size_t count;
168167

169168
controlpath_debug ("%s: list_exports readonly=%d tls=%d",
170169
b->name, readonly, conn->using_tls);
171170

172-
assert (c == NULL);
171+
assert (conn->top_context == NULL);
173172

174173
if (b->list_exports (b, readonly, conn->using_tls, exports) == -1 ||
175174
exports_resolve_default (exports, b, readonly) == -1) {
@@ -186,14 +185,13 @@ const char *
186185
backend_default_export (struct backend *b, int readonly)
187186
{
188187
GET_CONN;
189-
struct context *c = get_context (conn, b);
190188
const char *s;
191189

192190
controlpath_debug ("%s: default_export readonly=%d tls=%d",
193191
b->name, readonly, conn->using_tls);
194192

195193
if (conn->default_exportname[b->i] == NULL) {
196-
assert (c == NULL);
194+
assert (conn->top_context == NULL);
197195
s = b->default_export (b, readonly, conn->using_tls);
198196
/* Ignore over-length strings. XXX Also ignore non-UTF8? */
199197
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)
247245
controlpath_debug ("%s: open readonly=%d exportname=\"%s\" tls=%d",
248246
b->name, readonly, exportname, conn->using_tls);
249247

250-
assert (conn->contexts[b->i] == NULL);
251248
c->next = next_ops;
252249
c->handle = NULL;
253250
c->b = b;
251+
c->c_next = NULL;
254252
c->state = 0;
255253
c->exportsize = -1;
256254
c->can_write = readonly ? 0 : -1;
@@ -277,15 +275,12 @@ backend_open (struct backend *b, int readonly, const char *exportname)
277275
/* Most filters will call next_open first, resulting in
278276
* inner-to-outer ordering.
279277
*/
280-
c->handle = b->open (b, readonly, exportname, conn->using_tls);
278+
c->handle = b->open (c, readonly, exportname, conn->using_tls);
281279
controlpath_debug ("%s: open returned handle %p", b->name, c->handle);
282280

283281
if (c->handle == NULL) {
284-
if (b->i) { /* Do not strand backend if this layer failed */
285-
struct context *c2 = get_context (conn, b->next);
286-
if (c2 != NULL)
287-
backend_close (c2);
288-
}
282+
if (b->i && c->c_next != NULL)
283+
backend_close (c->c_next);
289284
free (c);
290285
return NULL;
291286
}
@@ -297,7 +292,6 @@ backend_open (struct backend *b, int readonly, const char *exportname)
297292
int
298293
backend_prepare (struct context *c)
299294
{
300-
GET_CONN;
301295
struct backend *b = c->b;
302296

303297
assert (c->handle);
@@ -307,11 +301,8 @@ backend_prepare (struct context *c)
307301
* plugin, similar to typical .open order. But remember that
308302
* a filter may skip opening its backend.
309303
*/
310-
if (b->i) {
311-
struct context *c2 = get_context (conn, b->next);
312-
if (c2 != NULL && backend_prepare (c2) == -1)
313-
return -1;
314-
}
304+
if (b->i && c->c_next != NULL && backend_prepare (c->c_next) == -1)
305+
return -1;
315306

316307
controlpath_debug ("%s: prepare readonly=%d", b->name, c->can_write == 0);
317308

@@ -324,7 +315,6 @@ backend_prepare (struct context *c)
324315
int
325316
backend_finalize (struct context *c)
326317
{
327-
GET_CONN;
328318
struct backend *b = c->b;
329319

330320
/* Call these in reverse order to .prepare above, starting from the
@@ -344,32 +334,25 @@ backend_finalize (struct context *c)
344334
}
345335
}
346336

347-
if (b->i) {
348-
struct context *c2 = get_context (conn, b->next);
349-
if (c2 != NULL)
350-
return backend_finalize (c2);
351-
}
337+
if (b->i && c->c_next != NULL)
338+
return backend_finalize (c->c_next);
352339
return 0;
353340
}
354341

355342
void
356343
backend_close (struct context *c)
357344
{
358-
GET_CONN;
359345
struct backend *b = c->b;
346+
struct context *c_next = c->c_next;
360347

361348
/* outer-to-inner order, opposite .open */
362349
assert (c->handle);
363350
assert (c->state & HANDLE_OPEN);
364351
controlpath_debug ("%s: close", b->name);
365352
b->close (c);
366353
free (c);
367-
set_context (conn, b, NULL);
368-
if (b->i) {
369-
struct context *c2 = get_context (conn, b->next);
370-
if (c2 != NULL)
371-
backend_close (c2);
372-
}
354+
if (c_next != NULL)
355+
backend_close (c_next);
373356
}
374357

375358
bool
@@ -383,27 +366,26 @@ backend_valid_range (struct context *c, uint64_t offset, uint32_t count)
383366
/* Core functionality of nbdkit_backend_reopen for retry filter */
384367

385368
int
386-
backend_reopen (struct backend *b, int readonly, const char *exportname)
369+
backend_reopen (struct context *c, int readonly, const char *exportname)
387370
{
388-
GET_CONN;
389-
struct context *c;
371+
struct backend *b = c->b;
390372

391373
controlpath_debug ("%s: reopen readonly=%d exportname=\"%s\"",
392-
b->name, readonly, exportname);
374+
b->next->name, readonly, exportname);
393375

394-
c = get_context (conn, b);
395-
if (c) {
396-
if (backend_finalize (c) == -1)
376+
if (c->c_next) {
377+
if (backend_finalize (c->c_next) == -1)
397378
return -1;
398-
backend_close (c);
379+
backend_close (c->c_next);
380+
c->c_next = NULL;
399381
}
400-
c = backend_open (b, readonly, exportname);
401-
if (c == NULL)
382+
c->c_next = backend_open (b->next, readonly, exportname);
383+
if (c->c_next == NULL)
402384
return -1;
403-
set_context (conn, b, c);
404-
if (backend_prepare (c) == -1) {
405-
backend_finalize (c);
406-
backend_close (c);
385+
if (backend_prepare (c->c_next) == -1) {
386+
backend_finalize (c->c_next);
387+
backend_close (c->c_next);
388+
c->c_next = NULL;
407389
return -1;
408390
}
409391
return 0;

0 commit comments

Comments
 (0)