nbd: Permit simple error to NBD_CMD_BLOCK_STATUS
[qemu/ericb.git] / slirp / src / vmstate.c
blob43bb3ebc6f801d4117c482af597a35f4d065c56e
1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /*
3 * VMState interpreter
5 * Copyright (c) 2009-2018 Red Hat Inc
7 * Authors:
8 * Juan Quintela <quintela@redhat.com>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
14 * 1. Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer.
18 * 2. Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials provided
21 * with the distribution.
23 * 3. Neither the name of the copyright holder nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
31 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
32 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
38 * OF THE POSSIBILITY OF SUCH DAMAGE.
40 #include <assert.h>
41 #include <errno.h>
42 #include <string.h>
43 #include <glib.h>
45 #include "stream.h"
46 #include "vmstate.h"
48 static int get_nullptr(SlirpIStream *f, void *pv, size_t size,
49 const VMStateField *field)
51 if (slirp_istream_read_u8(f) == VMS_NULLPTR_MARKER) {
52 return 0;
54 g_warning("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
55 return -EINVAL;
58 static int put_nullptr(SlirpOStream *f, void *pv, size_t size,
59 const VMStateField *field)
62 if (pv == NULL) {
63 slirp_ostream_write_u8(f, VMS_NULLPTR_MARKER);
64 return 0;
66 g_warning("vmstate: put_nullptr must be called with pv == NULL");
67 return -EINVAL;
70 const VMStateInfo slirp_vmstate_info_nullptr = {
71 .name = "uint64",
72 .get = get_nullptr,
73 .put = put_nullptr,
76 /* 8 bit unsigned int */
78 static int get_uint8(SlirpIStream *f, void *pv, size_t size, const VMStateField *field)
80 uint8_t *v = pv;
81 *v = slirp_istream_read_u8(f);
82 return 0;
85 static int put_uint8(SlirpOStream *f, void *pv, size_t size, const VMStateField *field)
87 uint8_t *v = pv;
88 slirp_ostream_write_u8(f, *v);
89 return 0;
92 const VMStateInfo slirp_vmstate_info_uint8 = {
93 .name = "uint8",
94 .get = get_uint8,
95 .put = put_uint8,
98 /* 16 bit unsigned int */
100 static int get_uint16(SlirpIStream *f, void *pv, size_t size,
101 const VMStateField *field)
103 uint16_t *v = pv;
104 *v = slirp_istream_read_u16(f);
105 return 0;
108 static int put_uint16(SlirpOStream *f, void *pv, size_t size,
109 const VMStateField *field)
111 uint16_t *v = pv;
112 slirp_ostream_write_u16(f, *v);
113 return 0;
116 const VMStateInfo slirp_vmstate_info_uint16 = {
117 .name = "uint16",
118 .get = get_uint16,
119 .put = put_uint16,
122 /* 32 bit unsigned int */
124 static int get_uint32(SlirpIStream *f, void *pv, size_t size,
125 const VMStateField *field)
127 uint32_t *v = pv;
128 *v = slirp_istream_read_u32(f);
129 return 0;
132 static int put_uint32(SlirpOStream *f, void *pv, size_t size,
133 const VMStateField *field)
135 uint32_t *v = pv;
136 slirp_ostream_write_u32(f, *v);
137 return 0;
140 const VMStateInfo slirp_vmstate_info_uint32 = {
141 .name = "uint32",
142 .get = get_uint32,
143 .put = put_uint32,
146 /* 16 bit int */
148 static int get_int16(SlirpIStream *f, void *pv, size_t size, const VMStateField *field)
150 int16_t *v = pv;
151 *v = slirp_istream_read_i16(f);
152 return 0;
155 static int put_int16(SlirpOStream *f, void *pv, size_t size, const VMStateField *field)
157 int16_t *v = pv;
158 slirp_ostream_write_i16(f, *v);
159 return 0;
162 const VMStateInfo slirp_vmstate_info_int16 = {
163 .name = "int16",
164 .get = get_int16,
165 .put = put_int16,
168 /* 32 bit int */
170 static int get_int32(SlirpIStream *f, void *pv, size_t size, const VMStateField *field)
172 int32_t *v = pv;
173 *v = slirp_istream_read_i32(f);
174 return 0;
177 static int put_int32(SlirpOStream *f, void *pv, size_t size, const VMStateField *field)
179 int32_t *v = pv;
180 slirp_ostream_write_i32(f, *v);
181 return 0;
184 const VMStateInfo slirp_vmstate_info_int32 = {
185 .name = "int32",
186 .get = get_int32,
187 .put = put_int32,
190 /* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
191 * a temporary buffer and the pre_load/pre_save methods in the child vmsd
192 * copy stuff from the parent into the child and do calculations to fill
193 * in fields that don't really exist in the parent but need to be in the
194 * stream.
196 static int get_tmp(SlirpIStream *f, void *pv, size_t size, const VMStateField *field)
198 int ret;
199 const VMStateDescription *vmsd = field->vmsd;
200 int version_id = field->version_id;
201 void *tmp = g_malloc(size);
203 /* Writes the parent field which is at the start of the tmp */
204 *(void **)tmp = pv;
205 ret = slirp_vmstate_load_state(f, vmsd, tmp, version_id);
206 g_free(tmp);
207 return ret;
210 static int put_tmp(SlirpOStream *f, void *pv, size_t size, const VMStateField *field)
212 const VMStateDescription *vmsd = field->vmsd;
213 void *tmp = g_malloc(size);
214 int ret;
216 /* Writes the parent field which is at the start of the tmp */
217 *(void **)tmp = pv;
218 ret = slirp_vmstate_save_state(f, vmsd, tmp);
219 g_free(tmp);
221 return ret;
224 const VMStateInfo slirp_vmstate_info_tmp = {
225 .name = "tmp",
226 .get = get_tmp,
227 .put = put_tmp,
230 /* uint8_t buffers */
232 static int get_buffer(SlirpIStream *f, void *pv, size_t size,
233 const VMStateField *field)
235 slirp_istream_read(f, pv, size);
236 return 0;
239 static int put_buffer(SlirpOStream *f, void *pv, size_t size,
240 const VMStateField *field)
242 slirp_ostream_write(f, pv, size);
243 return 0;
246 const VMStateInfo slirp_vmstate_info_buffer = {
247 .name = "buffer",
248 .get = get_buffer,
249 .put = put_buffer,
252 static int vmstate_n_elems(void *opaque, const VMStateField *field)
254 int n_elems = 1;
256 if (field->flags & VMS_ARRAY) {
257 n_elems = field->num;
258 } else if (field->flags & VMS_VARRAY_INT32) {
259 n_elems = *(int32_t *)(opaque + field->num_offset);
260 } else if (field->flags & VMS_VARRAY_UINT32) {
261 n_elems = *(uint32_t *)(opaque + field->num_offset);
262 } else if (field->flags & VMS_VARRAY_UINT16) {
263 n_elems = *(uint16_t *)(opaque + field->num_offset);
264 } else if (field->flags & VMS_VARRAY_UINT8) {
265 n_elems = *(uint8_t *)(opaque + field->num_offset);
268 if (field->flags & VMS_MULTIPLY_ELEMENTS) {
269 n_elems *= field->num;
272 return n_elems;
275 static int vmstate_size(void *opaque, const VMStateField *field)
277 int size = field->size;
279 if (field->flags & VMS_VBUFFER) {
280 size = *(int32_t *)(opaque + field->size_offset);
281 if (field->flags & VMS_MULTIPLY) {
282 size *= field->size;
286 return size;
289 static int
290 vmstate_save_state_v(SlirpOStream *f, const VMStateDescription *vmsd,
291 void *opaque, int version_id)
293 int ret = 0;
294 const VMStateField *field = vmsd->fields;
296 if (vmsd->pre_save) {
297 ret = vmsd->pre_save(opaque);
298 if (ret) {
299 g_warning("pre-save failed: %s", vmsd->name);
300 return ret;
304 while (field->name) {
305 if ((field->field_exists &&
306 field->field_exists(opaque, version_id)) ||
307 (!field->field_exists &&
308 field->version_id <= version_id)) {
309 void *first_elem = opaque + field->offset;
310 int i, n_elems = vmstate_n_elems(opaque, field);
311 int size = vmstate_size(opaque, field);
313 if (field->flags & VMS_POINTER) {
314 first_elem = *(void **)first_elem;
315 assert(first_elem || !n_elems || !size);
317 for (i = 0; i < n_elems; i++) {
318 void *curr_elem = first_elem + size * i;
319 ret = 0;
321 if (field->flags & VMS_ARRAY_OF_POINTER) {
322 assert(curr_elem);
323 curr_elem = *(void **)curr_elem;
325 if (!curr_elem && size) {
326 /* if null pointer write placeholder and do not follow */
327 assert(field->flags & VMS_ARRAY_OF_POINTER);
328 ret = slirp_vmstate_info_nullptr.put(f, curr_elem, size, NULL);
329 } else if (field->flags & VMS_STRUCT) {
330 ret = slirp_vmstate_save_state(f, field->vmsd, curr_elem);
331 } else if (field->flags & VMS_VSTRUCT) {
332 ret = vmstate_save_state_v(f, field->vmsd, curr_elem,
333 field->struct_version_id);
334 } else {
335 ret = field->info->put(f, curr_elem, size, field);
337 if (ret) {
338 g_warning("Save of field %s/%s failed",
339 vmsd->name, field->name);
340 return ret;
343 } else {
344 if (field->flags & VMS_MUST_EXIST) {
345 g_warning("Output state validation failed: %s/%s",
346 vmsd->name, field->name);
347 assert(!(field->flags & VMS_MUST_EXIST));
350 field++;
353 return 0;
356 int slirp_vmstate_save_state(SlirpOStream *f, const VMStateDescription *vmsd,
357 void *opaque)
359 return vmstate_save_state_v(f, vmsd, opaque, vmsd->version_id);
362 static void vmstate_handle_alloc(void *ptr, VMStateField *field, void *opaque)
364 if (field->flags & VMS_POINTER && field->flags & VMS_ALLOC) {
365 size_t size = vmstate_size(opaque, field);
366 size *= vmstate_n_elems(opaque, field);
367 if (size) {
368 *(void **)ptr = g_malloc(size);
373 int slirp_vmstate_load_state(SlirpIStream *f, const VMStateDescription *vmsd,
374 void *opaque, int version_id)
376 VMStateField *field = vmsd->fields;
377 int ret = 0;
379 if (version_id > vmsd->version_id) {
380 g_warning("%s: incoming version_id %d is too new "
381 "for local version_id %d",
382 vmsd->name, version_id, vmsd->version_id);
383 return -EINVAL;
385 if (vmsd->pre_load) {
386 int ret = vmsd->pre_load(opaque);
387 if (ret) {
388 return ret;
391 while (field->name) {
392 if ((field->field_exists &&
393 field->field_exists(opaque, version_id)) ||
394 (!field->field_exists &&
395 field->version_id <= version_id)) {
396 void *first_elem = opaque + field->offset;
397 int i, n_elems = vmstate_n_elems(opaque, field);
398 int size = vmstate_size(opaque, field);
400 vmstate_handle_alloc(first_elem, field, opaque);
401 if (field->flags & VMS_POINTER) {
402 first_elem = *(void **)first_elem;
403 assert(first_elem || !n_elems || !size);
405 for (i = 0; i < n_elems; i++) {
406 void *curr_elem = first_elem + size * i;
408 if (field->flags & VMS_ARRAY_OF_POINTER) {
409 curr_elem = *(void **)curr_elem;
411 if (!curr_elem && size) {
412 /* if null pointer check placeholder and do not follow */
413 assert(field->flags & VMS_ARRAY_OF_POINTER);
414 ret = slirp_vmstate_info_nullptr.get(f, curr_elem, size, NULL);
415 } else if (field->flags & VMS_STRUCT) {
416 ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem,
417 field->vmsd->version_id);
418 } else if (field->flags & VMS_VSTRUCT) {
419 ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem,
420 field->struct_version_id);
421 } else {
422 ret = field->info->get(f, curr_elem, size, field);
424 if (ret < 0) {
425 g_warning("Failed to load %s:%s", vmsd->name,
426 field->name);
427 return ret;
430 } else if (field->flags & VMS_MUST_EXIST) {
431 g_warning("Input validation failed: %s/%s",
432 vmsd->name, field->name);
433 return -1;
435 field++;
437 if (vmsd->post_load) {
438 ret = vmsd->post_load(opaque, version_id);
440 return ret;