Update Red Hat Copyright Notices
[nbdkit.git] / filters / retry-request / retry-request.c
blobed566080d659ddd7ba73a780f76cdbaf8987027e
1 /* nbdkit
2 * Copyright Red Hat
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
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
30 * SUCH DAMAGE.
33 #include <config.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdint.h>
38 #include <stdbool.h>
39 #include <inttypes.h>
40 #include <string.h>
41 #include <sys/time.h>
43 #include <nbdkit-filter.h>
45 #include "cleanup.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;
52 static int
53 retry_request_thread_model (void)
55 return NBDKIT_THREAD_MODEL_PARALLEL;
58 static int
59 retry_request_config (nbdkit_next_config *next, nbdkit_backend *nxdata,
60 const char *key, const char *value)
62 int r;
64 if (strcmp (key, "retry-request-retries") == 0) {
65 if (nbdkit_parse_unsigned ("retry-request-retries", value, &retries) == -1)
66 return -1;
67 if (retries > 1000) {
68 nbdkit_error ("retry-request-retries: value too large");
69 return -1;
71 return 0;
73 else if (strcmp (key, "retry-request-delay") == 0) {
74 if (nbdkit_parse_unsigned ("retry-request-delay", value, &delay) == -1)
75 return -1;
76 if (delay == 0) {
77 nbdkit_error ("retry-request-delay cannot be 0");
78 return -1;
80 return 0;
82 else if (strcmp (key, "retry-request-open") == 0) {
83 r = nbdkit_parse_bool (value);
84 if (r == -1)
85 return -1;
86 retry_open_call = r;
87 return 0;
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 \
105 unsigned i; \
107 r = -1; \
108 for (i = 0; r == -1 && i <= retries; ++i) { \
109 if (i > 0) { \
110 nbdkit_debug ("retry %u: waiting %u seconds before retrying", \
111 i, delay); \
112 if (nbdkit_nanosleep (delay, 0) == -1) { \
113 if (*err == 0) \
114 *err = errno; \
115 break; \
119 #define RETRY_END \
120 while (0); \
124 static void *
125 retry_request_open (nbdkit_next_open *next, nbdkit_context *nxdata,
126 int readonly, const char *exportname, int is_tls)
128 int r;
130 if (retry_open_call) {
131 int *err = &errno; /* used by the RETRY_* macros */
133 RETRY_START
134 r = next (nxdata, readonly, exportname);
135 RETRY_END;
137 else {
138 r = next (nxdata, readonly, exportname);
141 return r == 0 ? NBDKIT_HANDLE_NOT_NEEDED : NULL;
144 static int
145 retry_request_pread (nbdkit_next *next,
146 void *handle, void *buf, uint32_t count, uint64_t offset,
147 uint32_t flags, int *err)
149 int r;
151 RETRY_START
152 r = next->pread (next, buf, count, offset, flags, err);
153 RETRY_END;
154 return r;
157 static int
158 retry_request_pwrite (nbdkit_next *next,
159 void *handle,
160 const void *buf, uint32_t count, uint64_t offset,
161 uint32_t flags, int *err)
163 int r;
165 RETRY_START
166 r = next->pwrite (next, buf, count, offset, flags, err);
167 RETRY_END;
168 return r;
171 static int
172 retry_request_trim (nbdkit_next *next,
173 void *handle,
174 uint32_t count, uint64_t offset, uint32_t flags,
175 int *err)
177 int r;
179 RETRY_START
180 r = next->trim (next, count, offset, flags, err);
181 RETRY_END;
182 return r;
185 static int
186 retry_request_flush (nbdkit_next *next,
187 void *handle, uint32_t flags,
188 int *err)
190 int r;
192 RETRY_START
193 r = next->flush (next, flags, err);
194 RETRY_END;
195 return r;
198 static int
199 retry_request_zero (nbdkit_next *next,
200 void *handle,
201 uint32_t count, uint64_t offset, uint32_t flags,
202 int *err)
204 int r;
206 RETRY_START
207 r = next->zero (next, count, offset, flags, err);
208 RETRY_END;
209 return r;
212 static int
213 retry_request_extents (nbdkit_next *next,
214 void *handle,
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;
219 int r;
221 RETRY_START {
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) {
226 *err = errno;
227 return -1; /* Not worth a retry after ENOMEM. */
229 r = next->extents (next, count, offset, flags, extents2, err);
230 } RETRY_END;
232 if (r == 0) {
233 size_t i;
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) {
240 *err = errno;
241 return -1;
246 return r;
249 static int
250 retry_request_cache (nbdkit_next *next,
251 void *handle,
252 uint32_t count, uint64_t offset, uint32_t flags,
253 int *err)
255 int r;
257 RETRY_START
258 r = next->cache (next, count, offset, flags, err);
259 RETRY_END;
260 return r;
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)