4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 #include <nbdkit-filter.h>
46 #include "windows-compat.h"
48 static unsigned retries
= 2; /* 0 = filter is disabled */
49 static unsigned delay
= 2;
50 static bool retry_open_call
= true;
53 retry_request_thread_model (void)
55 return NBDKIT_THREAD_MODEL_PARALLEL
;
59 retry_request_config (nbdkit_next_config
*next
, nbdkit_backend
*nxdata
,
60 const char *key
, const char *value
)
64 if (strcmp (key
, "retry-request-retries") == 0) {
65 if (nbdkit_parse_unsigned ("retry-request-retries", value
, &retries
) == -1)
68 nbdkit_error ("retry-request-retries: value too large");
73 else if (strcmp (key
, "retry-request-delay") == 0) {
74 if (nbdkit_parse_unsigned ("retry-request-delay", value
, &delay
) == -1)
77 nbdkit_error ("retry-request-delay cannot be 0");
82 else if (strcmp (key
, "retry-request-open") == 0) {
83 r
= nbdkit_parse_bool (value
);
90 return next (nxdata
, key
, value
);
93 #define retry_request_config_help \
94 "retry-request-retries=<N> Number of retries (default: 2).\n" \
95 "retry-request-delay=<N> Seconds to wait before retry (default: 2).\n" \
96 "retry-request-open=false Do not retry opening the plugin (default: true).\n"
98 /* These macros encapsulate the logic of retrying.
100 * The code between RETRY_START...RETRY_END must set r to 0 or -1 on
101 * success or failure. *err may also be implicitly assigned.
103 #define RETRY_START \
108 for (i = 0; r == -1 && i <= retries; ++i) { \
110 nbdkit_debug ("retry %u: waiting %u seconds before retrying", \
112 if (nbdkit_nanosleep (delay, 0) == -1) { \
125 retry_request_open (nbdkit_next_open
*next
, nbdkit_context
*nxdata
,
126 int readonly
, const char *exportname
, int is_tls
)
130 if (retry_open_call
) {
131 int *err
= &errno
; /* used by the RETRY_* macros */
134 r
= next (nxdata
, readonly
, exportname
);
138 r
= next (nxdata
, readonly
, exportname
);
141 return r
== 0 ? NBDKIT_HANDLE_NOT_NEEDED
: NULL
;
145 retry_request_pread (nbdkit_next
*next
,
146 void *handle
, void *buf
, uint32_t count
, uint64_t offset
,
147 uint32_t flags
, int *err
)
152 r
= next
->pread (next
, buf
, count
, offset
, flags
, err
);
158 retry_request_pwrite (nbdkit_next
*next
,
160 const void *buf
, uint32_t count
, uint64_t offset
,
161 uint32_t flags
, int *err
)
166 r
= next
->pwrite (next
, buf
, count
, offset
, flags
, err
);
172 retry_request_trim (nbdkit_next
*next
,
174 uint32_t count
, uint64_t offset
, uint32_t flags
,
180 r
= next
->trim (next
, count
, offset
, flags
, err
);
186 retry_request_flush (nbdkit_next
*next
,
187 void *handle
, uint32_t flags
,
193 r
= next
->flush (next
, flags
, err
);
199 retry_request_zero (nbdkit_next
*next
,
201 uint32_t count
, uint64_t offset
, uint32_t flags
,
207 r
= next
->zero (next
, count
, offset
, flags
, err
);
213 retry_request_extents (nbdkit_next
*next
,
215 uint32_t count
, uint64_t offset
, uint32_t flags
,
216 struct nbdkit_extents
*extents
, int *err
)
218 CLEANUP_EXTENTS_FREE
struct nbdkit_extents
*extents2
= NULL
;
222 /* Each retry must begin with extents reset to the right beginning. */
223 nbdkit_extents_free (extents2
);
224 extents2
= nbdkit_extents_new (offset
, next
->get_size (next
));
225 if (extents2
== NULL
) {
227 return -1; /* Not worth a retry after ENOMEM. */
229 r
= next
->extents (next
, count
, offset
, flags
, extents2
, err
);
235 /* Transfer the successful extents back to the caller. */
236 for (i
= 0; i
< nbdkit_extents_count (extents2
); ++i
) {
237 struct nbdkit_extent e
= nbdkit_get_extent (extents2
, i
);
239 if (nbdkit_add_extent (extents
, e
.offset
, e
.length
, e
.type
) == -1) {
250 retry_request_cache (nbdkit_next
*next
,
252 uint32_t count
, uint64_t offset
, uint32_t flags
,
258 r
= next
->cache (next
, count
, offset
, flags
, err
);
263 static struct nbdkit_filter filter
= {
264 .name
= "retry-request",
265 .longname
= "nbdkit retry request filter",
266 .thread_model
= retry_request_thread_model
,
267 .config
= retry_request_config
,
268 .config_help
= retry_request_config_help
,
269 .open
= retry_request_open
,
270 .pread
= retry_request_pread
,
271 .pwrite
= retry_request_pwrite
,
272 .trim
= retry_request_trim
,
273 .flush
= retry_request_flush
,
274 .zero
= retry_request_zero
,
275 .extents
= retry_request_extents
,
276 .cache
= retry_request_cache
,
279 NBDKIT_REGISTER_FILTER (filter
)