Update Red Hat Copyright Notices
[nbdkit.git] / filters / fua / fua.c
blob1dd3844ec451e04ab1dfc49188acc8f027ee3ad6
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 <string.h>
39 #include <stdbool.h>
40 #include <assert.h>
42 #include <nbdkit-filter.h>
44 static enum FuaMode {
45 NONE,
46 EMULATE,
47 NATIVE,
48 FORCE,
49 PASS,
50 DISCARD,
51 } fuamode;
53 static int
54 fua_config (nbdkit_next_config *next, nbdkit_backend *nxdata,
55 const char *key, const char *value)
57 if (strcmp (key, "fuamode") == 0) {
58 if (strcmp (value, "none") == 0)
59 fuamode = NONE;
60 if (strcmp (value, "emulate") == 0)
61 fuamode = EMULATE;
62 else if (strcmp (value, "native") == 0)
63 fuamode = NATIVE;
64 else if (strcmp (value, "force") == 0)
65 fuamode = FORCE;
66 else if (strcmp (value, "pass") == 0)
67 fuamode = PASS;
68 else if (strcmp (value, "discard") == 0)
69 fuamode = DISCARD;
70 else {
71 nbdkit_error ("unknown fuamode '%s'", value);
72 return -1;
74 return 0;
76 return next (nxdata, key, value);
79 #define fua_config_help \
80 "fuamode=<MODE> One of 'none' (default), 'emulate', 'native',\n" \
81 " 'force', 'pass'."
83 /* Check that desired mode is supported by plugin. */
84 static int
85 fua_prepare (nbdkit_next *next, void *handle,
86 int readonly)
88 int r;
90 /* If we are opened readonly, this filter has no impact */
91 if (readonly)
92 return 0;
94 switch (fuamode) {
95 case NONE:
96 case PASS:
97 case DISCARD:
98 break;
99 case EMULATE:
100 r = next->can_flush (next);
101 if (r == -1)
102 return -1;
103 if (r == 0) {
104 nbdkit_error ("fuamode 'emulate' requires plugin flush support");
105 return -1;
107 break;
108 case NATIVE:
109 case FORCE:
110 r = next->can_fua (next);
111 if (r == -1)
112 return -1;
113 if (r == NBDKIT_FUA_NONE) {
114 nbdkit_error ("fuamode '%s' requires plugin fua support",
115 fuamode == EMULATE ? "emulate" : "force");
116 return -1;
118 break;
120 return 0;
123 /* Advertise proper flush support. */
124 static int
125 fua_can_flush (nbdkit_next *next, void *handle)
127 switch (fuamode) {
128 case FORCE:
129 case DISCARD:
130 return 1; /* Advertise our no-op flush, even if plugin lacks it */
131 case NONE:
132 case EMULATE:
133 case NATIVE:
134 case PASS:
135 return next->can_flush (next);
137 abort ();
140 /* Advertise desired fua mode. */
141 static int
142 fua_can_fua (nbdkit_next *next, void *handle)
144 switch (fuamode) {
145 case NONE:
146 return NBDKIT_FUA_NONE;
147 case EMULATE:
148 return NBDKIT_FUA_EMULATE;
149 case NATIVE:
150 case FORCE:
151 case DISCARD:
152 return NBDKIT_FUA_NATIVE;
153 case PASS:
154 return next->can_fua (next);
156 abort ();
159 static int
160 fua_pwrite (nbdkit_next *next,
161 void *handle, const void *buf, uint32_t count, uint64_t offs,
162 uint32_t flags, int *err)
164 int r;
165 bool need_flush = false;
167 switch (fuamode) {
168 case NONE:
169 assert (!(flags & NBDKIT_FLAG_FUA));
170 break;
171 case EMULATE:
172 if (flags & NBDKIT_FLAG_FUA) {
173 need_flush = true;
174 flags &= ~NBDKIT_FLAG_FUA;
176 break;
177 case NATIVE:
178 case PASS:
179 break;
180 case FORCE:
181 flags |= NBDKIT_FLAG_FUA;
182 break;
183 case DISCARD:
184 flags &= ~NBDKIT_FLAG_FUA;
185 break;
187 r = next->pwrite (next, buf, count, offs, flags, err);
188 if (r != -1 && need_flush)
189 r = next->flush (next, 0, err);
190 return r;
193 static int
194 fua_flush (nbdkit_next *next,
195 void *handle, uint32_t flags, int *err)
197 switch (fuamode) {
198 case FORCE:
199 return 0; /* Nothing to flush, since all writes already used FUA */
200 case DISCARD:
201 return 0; /* Drop flushes! */
202 case NONE:
203 case EMULATE:
204 case NATIVE:
205 case PASS:
206 return next->flush (next, flags, err);
208 abort ();
211 static int
212 fua_trim (nbdkit_next *next,
213 void *handle, uint32_t count, uint64_t offs, uint32_t flags,
214 int *err)
216 int r;
217 bool need_flush = false;
219 switch (fuamode) {
220 case NONE:
221 assert (!(flags & NBDKIT_FLAG_FUA));
222 break;
223 case EMULATE:
224 if (flags & NBDKIT_FLAG_FUA) {
225 need_flush = true;
226 flags &= ~NBDKIT_FLAG_FUA;
228 break;
229 case NATIVE:
230 case PASS:
231 break;
232 case FORCE:
233 flags |= NBDKIT_FLAG_FUA;
234 break;
235 case DISCARD:
236 flags &= ~NBDKIT_FLAG_FUA;
237 break;
239 r = next->trim (next, count, offs, flags, err);
240 if (r != -1 && need_flush)
241 r = next->flush (next, 0, err);
242 return r;
245 static int
246 fua_zero (nbdkit_next *next,
247 void *handle, uint32_t count, uint64_t offs, uint32_t flags,
248 int *err)
250 int r;
251 bool need_flush = false;
253 switch (fuamode) {
254 case NONE:
255 assert (!(flags & NBDKIT_FLAG_FUA));
256 break;
257 case EMULATE:
258 if (flags & NBDKIT_FLAG_FUA) {
259 need_flush = true;
260 flags &= ~NBDKIT_FLAG_FUA;
262 break;
263 case NATIVE:
264 case PASS:
265 break;
266 case FORCE:
267 flags |= NBDKIT_FLAG_FUA;
268 break;
269 case DISCARD:
270 flags &= ~NBDKIT_FLAG_FUA;
271 break;
273 r = next->zero (next, count, offs, flags, err);
274 if (r != -1 && need_flush)
275 r = next->flush (next, 0, err);
276 return r;
279 static struct nbdkit_filter filter = {
280 .name = "fua",
281 .longname = "nbdkit fua filter",
282 .config = fua_config,
283 .config_help = fua_config_help,
284 .prepare = fua_prepare,
285 .can_flush = fua_can_flush,
286 .can_fua = fua_can_fua,
287 .pwrite = fua_pwrite,
288 .flush = fua_flush,
289 .trim = fua_trim,
290 .zero = fua_zero,
293 NBDKIT_REGISTER_FILTER (filter)