1de08c606SWenchao Xia /*
2de08c606SWenchao Xia * Block layer snapshot related functions
3de08c606SWenchao Xia *
4de08c606SWenchao Xia * Copyright (c) 2003-2008 Fabrice Bellard
5de08c606SWenchao Xia *
6de08c606SWenchao Xia * Permission is hereby granted, free of charge, to any person obtaining a copy
7de08c606SWenchao Xia * of this software and associated documentation files (the "Software"), to deal
8de08c606SWenchao Xia * in the Software without restriction, including without limitation the rights
9de08c606SWenchao Xia * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10de08c606SWenchao Xia * copies of the Software, and to permit persons to whom the Software is
11de08c606SWenchao Xia * furnished to do so, subject to the following conditions:
12de08c606SWenchao Xia *
13de08c606SWenchao Xia * The above copyright notice and this permission notice shall be included in
14de08c606SWenchao Xia * all copies or substantial portions of the Software.
15de08c606SWenchao Xia *
16de08c606SWenchao Xia * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17de08c606SWenchao Xia * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18de08c606SWenchao Xia * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19de08c606SWenchao Xia * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20de08c606SWenchao Xia * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21de08c606SWenchao Xia * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22de08c606SWenchao Xia * THE SOFTWARE.
23de08c606SWenchao Xia */
24de08c606SWenchao Xia
2580c71a24SPeter Maydell #include "qemu/osdep.h"
26de08c606SWenchao Xia #include "block/snapshot.h"
27de08c606SWenchao Xia #include "block/block_int.h"
28609f45eaSMax Reitz #include "block/qdict.h"
29da34e65cSMarkus Armbruster #include "qapi/error.h"
30452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h"
317a9e5119SDong Jia Shi #include "qapi/qmp/qstring.h"
32922a01a0SMarkus Armbruster #include "qemu/option.h"
3305f4acedSKevin Wolf #include "sysemu/block-backend.h"
34de08c606SWenchao Xia
358c116b0eSWenchao Xia QemuOptsList internal_snapshot_opts = {
368c116b0eSWenchao Xia .name = "snapshot",
378c116b0eSWenchao Xia .head = QTAILQ_HEAD_INITIALIZER(internal_snapshot_opts.head),
388c116b0eSWenchao Xia .desc = {
398c116b0eSWenchao Xia {
408c116b0eSWenchao Xia .name = SNAPSHOT_OPT_ID,
418c116b0eSWenchao Xia .type = QEMU_OPT_STRING,
428c116b0eSWenchao Xia .help = "snapshot id"
438c116b0eSWenchao Xia },{
448c116b0eSWenchao Xia .name = SNAPSHOT_OPT_NAME,
458c116b0eSWenchao Xia .type = QEMU_OPT_STRING,
468c116b0eSWenchao Xia .help = "snapshot name"
478c116b0eSWenchao Xia },{
488c116b0eSWenchao Xia /* end of list */
498c116b0eSWenchao Xia }
508c116b0eSWenchao Xia },
518c116b0eSWenchao Xia };
528c116b0eSWenchao Xia
bdrv_snapshot_find(BlockDriverState * bs,QEMUSnapshotInfo * sn_info,const char * name)53de08c606SWenchao Xia int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
54de08c606SWenchao Xia const char *name)
55de08c606SWenchao Xia {
56de08c606SWenchao Xia QEMUSnapshotInfo *sn_tab, *sn;
57de08c606SWenchao Xia int nb_sns, i, ret;
58de08c606SWenchao Xia
596b573efeSEmanuele Giuseppe Esposito GLOBAL_STATE_CODE();
606b573efeSEmanuele Giuseppe Esposito
61de08c606SWenchao Xia ret = -ENOENT;
62de08c606SWenchao Xia nb_sns = bdrv_snapshot_list(bs, &sn_tab);
63de08c606SWenchao Xia if (nb_sns < 0) {
64de08c606SWenchao Xia return ret;
65de08c606SWenchao Xia }
66de08c606SWenchao Xia for (i = 0; i < nb_sns; i++) {
67de08c606SWenchao Xia sn = &sn_tab[i];
686ca08045SDaniel Henrique Barboza if (!strcmp(sn->name, name)) {
69de08c606SWenchao Xia *sn_info = *sn;
70de08c606SWenchao Xia ret = 0;
71de08c606SWenchao Xia break;
72de08c606SWenchao Xia }
73de08c606SWenchao Xia }
74de08c606SWenchao Xia g_free(sn_tab);
75de08c606SWenchao Xia return ret;
76de08c606SWenchao Xia }
77de08c606SWenchao Xia
782ea1dd75SWenchao Xia /**
792ea1dd75SWenchao Xia * Look up an internal snapshot by @id and @name.
802ea1dd75SWenchao Xia * @bs: block device to search
812ea1dd75SWenchao Xia * @id: unique snapshot ID, or NULL
822ea1dd75SWenchao Xia * @name: snapshot name, or NULL
832ea1dd75SWenchao Xia * @sn_info: location to store information on the snapshot found
842ea1dd75SWenchao Xia * @errp: location to store error, will be set only for exception
852ea1dd75SWenchao Xia *
862ea1dd75SWenchao Xia * This function will traverse snapshot list in @bs to search the matching
872ea1dd75SWenchao Xia * one, @id and @name are the matching condition:
882ea1dd75SWenchao Xia * If both @id and @name are specified, find the first one with id @id and
892ea1dd75SWenchao Xia * name @name.
902ea1dd75SWenchao Xia * If only @id is specified, find the first one with id @id.
912ea1dd75SWenchao Xia * If only @name is specified, find the first one with name @name.
922ea1dd75SWenchao Xia * if none is specified, abort().
932ea1dd75SWenchao Xia *
942ea1dd75SWenchao Xia * Returns: true when a snapshot is found and @sn_info will be filled, false
952ea1dd75SWenchao Xia * when error or not found. If all operation succeed but no matching one is
962ea1dd75SWenchao Xia * found, @errp will NOT be set.
972ea1dd75SWenchao Xia */
bdrv_snapshot_find_by_id_and_name(BlockDriverState * bs,const char * id,const char * name,QEMUSnapshotInfo * sn_info,Error ** errp)982ea1dd75SWenchao Xia bool bdrv_snapshot_find_by_id_and_name(BlockDriverState *bs,
992ea1dd75SWenchao Xia const char *id,
1002ea1dd75SWenchao Xia const char *name,
1012ea1dd75SWenchao Xia QEMUSnapshotInfo *sn_info,
1022ea1dd75SWenchao Xia Error **errp)
1032ea1dd75SWenchao Xia {
1042ea1dd75SWenchao Xia QEMUSnapshotInfo *sn_tab, *sn;
1052ea1dd75SWenchao Xia int nb_sns, i;
1062ea1dd75SWenchao Xia bool ret = false;
1072ea1dd75SWenchao Xia
1082ea1dd75SWenchao Xia assert(id || name);
1096b573efeSEmanuele Giuseppe Esposito GLOBAL_STATE_CODE();
1102ea1dd75SWenchao Xia
1112ea1dd75SWenchao Xia nb_sns = bdrv_snapshot_list(bs, &sn_tab);
1122ea1dd75SWenchao Xia if (nb_sns < 0) {
1132ea1dd75SWenchao Xia error_setg_errno(errp, -nb_sns, "Failed to get a snapshot list");
1142ea1dd75SWenchao Xia return false;
1152ea1dd75SWenchao Xia } else if (nb_sns == 0) {
1162ea1dd75SWenchao Xia return false;
1172ea1dd75SWenchao Xia }
1182ea1dd75SWenchao Xia
1192ea1dd75SWenchao Xia if (id && name) {
1202ea1dd75SWenchao Xia for (i = 0; i < nb_sns; i++) {
1212ea1dd75SWenchao Xia sn = &sn_tab[i];
1222ea1dd75SWenchao Xia if (!strcmp(sn->id_str, id) && !strcmp(sn->name, name)) {
1232ea1dd75SWenchao Xia *sn_info = *sn;
1242ea1dd75SWenchao Xia ret = true;
1252ea1dd75SWenchao Xia break;
1262ea1dd75SWenchao Xia }
1272ea1dd75SWenchao Xia }
1282ea1dd75SWenchao Xia } else if (id) {
1292ea1dd75SWenchao Xia for (i = 0; i < nb_sns; i++) {
1302ea1dd75SWenchao Xia sn = &sn_tab[i];
1312ea1dd75SWenchao Xia if (!strcmp(sn->id_str, id)) {
1322ea1dd75SWenchao Xia *sn_info = *sn;
1332ea1dd75SWenchao Xia ret = true;
1342ea1dd75SWenchao Xia break;
1352ea1dd75SWenchao Xia }
1362ea1dd75SWenchao Xia }
1372ea1dd75SWenchao Xia } else if (name) {
1382ea1dd75SWenchao Xia for (i = 0; i < nb_sns; i++) {
1392ea1dd75SWenchao Xia sn = &sn_tab[i];
1402ea1dd75SWenchao Xia if (!strcmp(sn->name, name)) {
1412ea1dd75SWenchao Xia *sn_info = *sn;
1422ea1dd75SWenchao Xia ret = true;
1432ea1dd75SWenchao Xia break;
1442ea1dd75SWenchao Xia }
1452ea1dd75SWenchao Xia }
1462ea1dd75SWenchao Xia }
1472ea1dd75SWenchao Xia
1482ea1dd75SWenchao Xia g_free(sn_tab);
1492ea1dd75SWenchao Xia return ret;
1502ea1dd75SWenchao Xia }
1512ea1dd75SWenchao Xia
152c8af8757SMax Reitz /**
153c5c21741SVladimir Sementsov-Ogievskiy * Return a pointer to child of given BDS to which we can fall
154c8af8757SMax Reitz * back if the given BDS does not support snapshots.
155c8af8757SMax Reitz * Return NULL if there is no BDS to (safely) fall back to.
156c8af8757SMax Reitz */
157a32e7818SKevin Wolf static BdrvChild * GRAPH_RDLOCK
bdrv_snapshot_fallback_child(BlockDriverState * bs)158a32e7818SKevin Wolf bdrv_snapshot_fallback_child(BlockDriverState *bs)
159c8af8757SMax Reitz {
160c5c21741SVladimir Sementsov-Ogievskiy BdrvChild *fallback = bdrv_primary_child(bs);
161c5c21741SVladimir Sementsov-Ogievskiy BdrvChild *child;
162c8af8757SMax Reitz
163a32e7818SKevin Wolf GLOBAL_STATE_CODE();
164a32e7818SKevin Wolf assert_bdrv_graph_readable();
165a32e7818SKevin Wolf
1660c6100a7SVladimir Sementsov-Ogievskiy /* We allow fallback only to primary child */
167c5c21741SVladimir Sementsov-Ogievskiy if (!fallback) {
168c8af8757SMax Reitz return NULL;
169c8af8757SMax Reitz }
170c8af8757SMax Reitz
171c8af8757SMax Reitz /*
172c8af8757SMax Reitz * Check that there are no other children that would need to be
173c8af8757SMax Reitz * snapshotted. If there are, it is not safe to fall back to
174c5c21741SVladimir Sementsov-Ogievskiy * fallback.
175c8af8757SMax Reitz */
176c8af8757SMax Reitz QLIST_FOREACH(child, &bs->children, next) {
177c8af8757SMax Reitz if (child->role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA |
178c8af8757SMax Reitz BDRV_CHILD_FILTERED) &&
179c5c21741SVladimir Sementsov-Ogievskiy child != fallback)
180c8af8757SMax Reitz {
181c8af8757SMax Reitz return NULL;
182c8af8757SMax Reitz }
183c8af8757SMax Reitz }
184c8af8757SMax Reitz
185c8af8757SMax Reitz return fallback;
186c8af8757SMax Reitz }
187c8af8757SMax Reitz
188a32e7818SKevin Wolf static BlockDriverState * GRAPH_RDLOCK
bdrv_snapshot_fallback(BlockDriverState * bs)189a32e7818SKevin Wolf bdrv_snapshot_fallback(BlockDriverState *bs)
190c8af8757SMax Reitz {
191a32e7818SKevin Wolf GLOBAL_STATE_CODE();
192c5c21741SVladimir Sementsov-Ogievskiy return child_bs(bdrv_snapshot_fallback_child(bs));
193c8af8757SMax Reitz }
194c8af8757SMax Reitz
bdrv_can_snapshot(BlockDriverState * bs)195de08c606SWenchao Xia int bdrv_can_snapshot(BlockDriverState *bs)
196de08c606SWenchao Xia {
197de08c606SWenchao Xia BlockDriver *drv = bs->drv;
198d3007d34SKevin Wolf
1996b573efeSEmanuele Giuseppe Esposito GLOBAL_STATE_CODE();
200d3007d34SKevin Wolf
201d3007d34SKevin Wolf if (!drv || !bdrv_is_inserted(bs) || !bdrv_is_writable(bs)) {
202de08c606SWenchao Xia return 0;
203de08c606SWenchao Xia }
204de08c606SWenchao Xia
205de08c606SWenchao Xia if (!drv->bdrv_snapshot_create) {
206c8af8757SMax Reitz BlockDriverState *fallback_bs = bdrv_snapshot_fallback(bs);
207c8af8757SMax Reitz if (fallback_bs) {
208c8af8757SMax Reitz return bdrv_can_snapshot(fallback_bs);
209de08c606SWenchao Xia }
210de08c606SWenchao Xia return 0;
211de08c606SWenchao Xia }
212de08c606SWenchao Xia
213de08c606SWenchao Xia return 1;
214de08c606SWenchao Xia }
215de08c606SWenchao Xia
bdrv_snapshot_create(BlockDriverState * bs,QEMUSnapshotInfo * sn_info)216de08c606SWenchao Xia int bdrv_snapshot_create(BlockDriverState *bs,
217de08c606SWenchao Xia QEMUSnapshotInfo *sn_info)
218de08c606SWenchao Xia {
219de08c606SWenchao Xia BlockDriver *drv = bs->drv;
220c8af8757SMax Reitz BlockDriverState *fallback_bs = bdrv_snapshot_fallback(bs);
2216b573efeSEmanuele Giuseppe Esposito
2226b573efeSEmanuele Giuseppe Esposito GLOBAL_STATE_CODE();
2236b573efeSEmanuele Giuseppe Esposito
224de08c606SWenchao Xia if (!drv) {
225de08c606SWenchao Xia return -ENOMEDIUM;
226de08c606SWenchao Xia }
227de08c606SWenchao Xia if (drv->bdrv_snapshot_create) {
228de08c606SWenchao Xia return drv->bdrv_snapshot_create(bs, sn_info);
229de08c606SWenchao Xia }
230c8af8757SMax Reitz if (fallback_bs) {
231c8af8757SMax Reitz return bdrv_snapshot_create(fallback_bs, sn_info);
232de08c606SWenchao Xia }
233de08c606SWenchao Xia return -ENOTSUP;
234de08c606SWenchao Xia }
235de08c606SWenchao Xia
bdrv_snapshot_goto(BlockDriverState * bs,const char * snapshot_id,Error ** errp)236de08c606SWenchao Xia int bdrv_snapshot_goto(BlockDriverState *bs,
2370b62bcbcSKevin Wolf const char *snapshot_id,
2380b62bcbcSKevin Wolf Error **errp)
239de08c606SWenchao Xia {
240de08c606SWenchao Xia BlockDriver *drv = bs->drv;
241c5c21741SVladimir Sementsov-Ogievskiy BdrvChild *fallback;
242de08c606SWenchao Xia int ret, open_ret;
243de08c606SWenchao Xia
2446b573efeSEmanuele Giuseppe Esposito GLOBAL_STATE_CODE();
2456b573efeSEmanuele Giuseppe Esposito
246de08c606SWenchao Xia if (!drv) {
2470b62bcbcSKevin Wolf error_setg(errp, "Block driver is closed");
248de08c606SWenchao Xia return -ENOMEDIUM;
249de08c606SWenchao Xia }
25004dec3c3SVladimir Sementsov-Ogievskiy
25170a5afedSKevin Wolf if (!QLIST_EMPTY(&bs->dirty_bitmaps)) {
25270a5afedSKevin Wolf error_setg(errp, "Device has active dirty bitmaps");
25370a5afedSKevin Wolf return -EBUSY;
25404dec3c3SVladimir Sementsov-Ogievskiy }
25504dec3c3SVladimir Sementsov-Ogievskiy
256de08c606SWenchao Xia if (drv->bdrv_snapshot_goto) {
2570b62bcbcSKevin Wolf ret = drv->bdrv_snapshot_goto(bs, snapshot_id);
2580b62bcbcSKevin Wolf if (ret < 0) {
2590b62bcbcSKevin Wolf error_setg_errno(errp, -ret, "Failed to load snapshot");
2600b62bcbcSKevin Wolf }
2610b62bcbcSKevin Wolf return ret;
262de08c606SWenchao Xia }
263de08c606SWenchao Xia
264a32e7818SKevin Wolf bdrv_graph_rdlock_main_loop();
265c5c21741SVladimir Sementsov-Ogievskiy fallback = bdrv_snapshot_fallback_child(bs);
266a32e7818SKevin Wolf bdrv_graph_rdunlock_main_loop();
267a32e7818SKevin Wolf
268c5c21741SVladimir Sementsov-Ogievskiy if (fallback) {
269c8af8757SMax Reitz QDict *options;
2707a9e5119SDong Jia Shi QDict *file_options;
2710b62bcbcSKevin Wolf Error *local_err = NULL;
272c5c21741SVladimir Sementsov-Ogievskiy BlockDriverState *fallback_bs = fallback->bs;
273c5c21741SVladimir Sementsov-Ogievskiy char *subqdict_prefix = g_strdup_printf("%s.", fallback->name);
2747a9e5119SDong Jia Shi
275c8af8757SMax Reitz options = qdict_clone_shallow(bs->options);
276c8af8757SMax Reitz
2777a9e5119SDong Jia Shi /* Prevent it from getting deleted when detached from bs */
278c8af8757SMax Reitz bdrv_ref(fallback_bs);
2797a9e5119SDong Jia Shi
280c8af8757SMax Reitz qdict_extract_subqdict(options, &file_options, subqdict_prefix);
281cb3e7f08SMarc-André Lureau qobject_unref(file_options);
282c8af8757SMax Reitz g_free(subqdict_prefix);
283c8af8757SMax Reitz
284c5c21741SVladimir Sementsov-Ogievskiy /* Force .bdrv_open() below to re-attach fallback_bs on fallback */
285c5c21741SVladimir Sementsov-Ogievskiy qdict_put_str(options, fallback->name,
286c8af8757SMax Reitz bdrv_get_node_name(fallback_bs));
2877a9e5119SDong Jia Shi
28832a9a245SMax Reitz /* Now close bs, apply the snapshot on fallback_bs, and re-open bs */
2893c005293SVladimir Sementsov-Ogievskiy if (drv->bdrv_close) {
290de08c606SWenchao Xia drv->bdrv_close(bs);
2913c005293SVladimir Sementsov-Ogievskiy }
2927a9e5119SDong Jia Shi
29332a9a245SMax Reitz /* .bdrv_open() will re-attach it */
2946bc30f19SStefan Hajnoczi bdrv_graph_wrlock();
295c5c21741SVladimir Sementsov-Ogievskiy bdrv_unref_child(bs, fallback);
2966bc30f19SStefan Hajnoczi bdrv_graph_wrunlock();
297c8af8757SMax Reitz
298c8af8757SMax Reitz ret = bdrv_snapshot_goto(fallback_bs, snapshot_id, errp);
2990b62bcbcSKevin Wolf open_ret = drv->bdrv_open(bs, options, bs->open_flags, &local_err);
300cb3e7f08SMarc-André Lureau qobject_unref(options);
301de08c606SWenchao Xia if (open_ret < 0) {
302c8af8757SMax Reitz bdrv_unref(fallback_bs);
303de08c606SWenchao Xia bs->drv = NULL;
3040b62bcbcSKevin Wolf /* A bdrv_snapshot_goto() error takes precedence */
3050b62bcbcSKevin Wolf error_propagate(errp, local_err);
3060b62bcbcSKevin Wolf return ret < 0 ? ret : open_ret;
307de08c606SWenchao Xia }
3087a9e5119SDong Jia Shi
30932a9a245SMax Reitz /*
3100c6100a7SVladimir Sementsov-Ogievskiy * fallback was a primary child. It was closed above and set to NULL,
3110c6100a7SVladimir Sementsov-Ogievskiy * but the .bdrv_open() call has opened it again, because we set the
3120c6100a7SVladimir Sementsov-Ogievskiy * respective option (with the qdict_put_str() call above).
3130c6100a7SVladimir Sementsov-Ogievskiy * Assert that .bdrv_open() has attached the right BDS as primary child.
31432a9a245SMax Reitz */
315c0fc5123SKevin Wolf bdrv_graph_rdlock_main_loop();
3160c6100a7SVladimir Sementsov-Ogievskiy assert(bdrv_primary_bs(bs) == fallback_bs);
317c0fc5123SKevin Wolf bdrv_graph_rdunlock_main_loop();
318c0fc5123SKevin Wolf
319c8af8757SMax Reitz bdrv_unref(fallback_bs);
320de08c606SWenchao Xia return ret;
321de08c606SWenchao Xia }
322de08c606SWenchao Xia
3230b62bcbcSKevin Wolf error_setg(errp, "Block driver does not support snapshots");
324de08c606SWenchao Xia return -ENOTSUP;
325de08c606SWenchao Xia }
326de08c606SWenchao Xia
327a89d89d3SWenchao Xia /**
328a89d89d3SWenchao Xia * Delete an internal snapshot by @snapshot_id and @name.
329a89d89d3SWenchao Xia * @bs: block device used in the operation
330a89d89d3SWenchao Xia * @snapshot_id: unique snapshot ID, or NULL
331a89d89d3SWenchao Xia * @name: snapshot name, or NULL
332a89d89d3SWenchao Xia * @errp: location to store error
333a89d89d3SWenchao Xia *
334a89d89d3SWenchao Xia * If both @snapshot_id and @name are specified, delete the first one with
335a89d89d3SWenchao Xia * id @snapshot_id and name @name.
336a89d89d3SWenchao Xia * If only @snapshot_id is specified, delete the first one with id
337a89d89d3SWenchao Xia * @snapshot_id.
338a89d89d3SWenchao Xia * If only @name is specified, delete the first one with name @name.
3397b4c4781SWenchao Xia * if none is specified, return -EINVAL.
340a89d89d3SWenchao Xia *
341a89d89d3SWenchao Xia * Returns: 0 on success, -errno on failure. If @bs is not inserted, return
342a89d89d3SWenchao Xia * -ENOMEDIUM. If @snapshot_id and @name are both NULL, return -EINVAL. If @bs
343a89d89d3SWenchao Xia * does not support internal snapshot deletion, return -ENOTSUP. If @bs does
344a89d89d3SWenchao Xia * not support parameter @snapshot_id or @name, or one of them is not correctly
345a89d89d3SWenchao Xia * specified, return -EINVAL. If @bs can't find one matching @id and @name,
346a89d89d3SWenchao Xia * return -ENOENT. If @errp != NULL, it will always be filled with error
347a89d89d3SWenchao Xia * message on failure.
348a89d89d3SWenchao Xia */
bdrv_snapshot_delete(BlockDriverState * bs,const char * snapshot_id,const char * name,Error ** errp)349a89d89d3SWenchao Xia int bdrv_snapshot_delete(BlockDriverState *bs,
350a89d89d3SWenchao Xia const char *snapshot_id,
351a89d89d3SWenchao Xia const char *name,
352a89d89d3SWenchao Xia Error **errp)
353de08c606SWenchao Xia {
354de08c606SWenchao Xia BlockDriver *drv = bs->drv;
355c8af8757SMax Reitz BlockDriverState *fallback_bs = bdrv_snapshot_fallback(bs);
35627a7649aSPaolo Bonzini int ret;
35727a7649aSPaolo Bonzini
3586b573efeSEmanuele Giuseppe Esposito GLOBAL_STATE_CODE();
3596b573efeSEmanuele Giuseppe Esposito
360de08c606SWenchao Xia if (!drv) {
361*a95921f1SPhilippe Mathieu-Daudé error_setg(errp, "Device '%s' has no medium",
362*a95921f1SPhilippe Mathieu-Daudé bdrv_get_device_name(bs));
363de08c606SWenchao Xia return -ENOMEDIUM;
364de08c606SWenchao Xia }
365a89d89d3SWenchao Xia if (!snapshot_id && !name) {
366a89d89d3SWenchao Xia error_setg(errp, "snapshot_id and name are both NULL");
367a89d89d3SWenchao Xia return -EINVAL;
368a89d89d3SWenchao Xia }
3693432a192SZhang Haoyu
3703432a192SZhang Haoyu /* drain all pending i/o before deleting snapshot */
37127a7649aSPaolo Bonzini bdrv_drained_begin(bs);
3723432a192SZhang Haoyu
373de08c606SWenchao Xia if (drv->bdrv_snapshot_delete) {
37427a7649aSPaolo Bonzini ret = drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp);
375c8af8757SMax Reitz } else if (fallback_bs) {
376c8af8757SMax Reitz ret = bdrv_snapshot_delete(fallback_bs, snapshot_id, name, errp);
37727a7649aSPaolo Bonzini } else {
37881e5f78aSAlberto Garcia error_setg(errp, "Block format '%s' used by device '%s' "
37981e5f78aSAlberto Garcia "does not support internal snapshot deletion",
38081e5f78aSAlberto Garcia drv->format_name, bdrv_get_device_name(bs));
38127a7649aSPaolo Bonzini ret = -ENOTSUP;
38227a7649aSPaolo Bonzini }
38327a7649aSPaolo Bonzini
38427a7649aSPaolo Bonzini bdrv_drained_end(bs);
38527a7649aSPaolo Bonzini return ret;
386de08c606SWenchao Xia }
387de08c606SWenchao Xia
bdrv_snapshot_list(BlockDriverState * bs,QEMUSnapshotInfo ** psn_info)388de08c606SWenchao Xia int bdrv_snapshot_list(BlockDriverState *bs,
389de08c606SWenchao Xia QEMUSnapshotInfo **psn_info)
390de08c606SWenchao Xia {
391a32e7818SKevin Wolf GLOBAL_STATE_CODE();
392a32e7818SKevin Wolf GRAPH_RDLOCK_GUARD_MAINLOOP();
393a32e7818SKevin Wolf
394de08c606SWenchao Xia BlockDriver *drv = bs->drv;
395c8af8757SMax Reitz BlockDriverState *fallback_bs = bdrv_snapshot_fallback(bs);
3966b573efeSEmanuele Giuseppe Esposito
397de08c606SWenchao Xia if (!drv) {
398de08c606SWenchao Xia return -ENOMEDIUM;
399de08c606SWenchao Xia }
400de08c606SWenchao Xia if (drv->bdrv_snapshot_list) {
401de08c606SWenchao Xia return drv->bdrv_snapshot_list(bs, psn_info);
402de08c606SWenchao Xia }
403c8af8757SMax Reitz if (fallback_bs) {
404c8af8757SMax Reitz return bdrv_snapshot_list(fallback_bs, psn_info);
405de08c606SWenchao Xia }
406de08c606SWenchao Xia return -ENOTSUP;
407de08c606SWenchao Xia }
408de08c606SWenchao Xia
4097b4c4781SWenchao Xia /**
4107b4c4781SWenchao Xia * Temporarily load an internal snapshot by @snapshot_id and @name.
4117b4c4781SWenchao Xia * @bs: block device used in the operation
4127b4c4781SWenchao Xia * @snapshot_id: unique snapshot ID, or NULL
4137b4c4781SWenchao Xia * @name: snapshot name, or NULL
4147b4c4781SWenchao Xia * @errp: location to store error
4157b4c4781SWenchao Xia *
4167b4c4781SWenchao Xia * If both @snapshot_id and @name are specified, load the first one with
4177b4c4781SWenchao Xia * id @snapshot_id and name @name.
4187b4c4781SWenchao Xia * If only @snapshot_id is specified, load the first one with id
4197b4c4781SWenchao Xia * @snapshot_id.
4207b4c4781SWenchao Xia * If only @name is specified, load the first one with name @name.
4217b4c4781SWenchao Xia * if none is specified, return -EINVAL.
4227b4c4781SWenchao Xia *
4237b4c4781SWenchao Xia * Returns: 0 on success, -errno on fail. If @bs is not inserted, return
4247b4c4781SWenchao Xia * -ENOMEDIUM. If @bs is not readonly, return -EINVAL. If @bs did not support
4257b4c4781SWenchao Xia * internal snapshot, return -ENOTSUP. If qemu can't find a matching @id and
4267b4c4781SWenchao Xia * @name, return -ENOENT. If @errp != NULL, it will always be filled on
4277b4c4781SWenchao Xia * failure.
4287b4c4781SWenchao Xia */
bdrv_snapshot_load_tmp(BlockDriverState * bs,const char * snapshot_id,const char * name,Error ** errp)429de08c606SWenchao Xia int bdrv_snapshot_load_tmp(BlockDriverState *bs,
4307b4c4781SWenchao Xia const char *snapshot_id,
4317b4c4781SWenchao Xia const char *name,
4327b4c4781SWenchao Xia Error **errp)
433de08c606SWenchao Xia {
434de08c606SWenchao Xia BlockDriver *drv = bs->drv;
4357b4c4781SWenchao Xia
4366b573efeSEmanuele Giuseppe Esposito GLOBAL_STATE_CODE();
4374026f1c4SKevin Wolf GRAPH_RDLOCK_GUARD_MAINLOOP();
4386b573efeSEmanuele Giuseppe Esposito
439de08c606SWenchao Xia if (!drv) {
440*a95921f1SPhilippe Mathieu-Daudé error_setg(errp, "Device '%s' has no medium",
441*a95921f1SPhilippe Mathieu-Daudé bdrv_get_device_name(bs));
442de08c606SWenchao Xia return -ENOMEDIUM;
443de08c606SWenchao Xia }
4447b4c4781SWenchao Xia if (!snapshot_id && !name) {
4457b4c4781SWenchao Xia error_setg(errp, "snapshot_id and name are both NULL");
4467b4c4781SWenchao Xia return -EINVAL;
4477b4c4781SWenchao Xia }
448307261b2SVladimir Sementsov-Ogievskiy if (!bdrv_is_read_only(bs)) {
4497b4c4781SWenchao Xia error_setg(errp, "Device is not readonly");
450de08c606SWenchao Xia return -EINVAL;
451de08c606SWenchao Xia }
452de08c606SWenchao Xia if (drv->bdrv_snapshot_load_tmp) {
4537b4c4781SWenchao Xia return drv->bdrv_snapshot_load_tmp(bs, snapshot_id, name, errp);
454de08c606SWenchao Xia }
45581e5f78aSAlberto Garcia error_setg(errp, "Block format '%s' used by device '%s' "
45681e5f78aSAlberto Garcia "does not support temporarily loading internal snapshots",
45781e5f78aSAlberto Garcia drv->format_name, bdrv_get_device_name(bs));
458de08c606SWenchao Xia return -ENOTSUP;
459de08c606SWenchao Xia }
4607b4c4781SWenchao Xia
bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState * bs,const char * id_or_name,Error ** errp)4617b4c4781SWenchao Xia int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,
4627b4c4781SWenchao Xia const char *id_or_name,
4637b4c4781SWenchao Xia Error **errp)
4647b4c4781SWenchao Xia {
4657b4c4781SWenchao Xia int ret;
4667b4c4781SWenchao Xia Error *local_err = NULL;
4677b4c4781SWenchao Xia
4686b573efeSEmanuele Giuseppe Esposito GLOBAL_STATE_CODE();
4696b573efeSEmanuele Giuseppe Esposito
4707b4c4781SWenchao Xia ret = bdrv_snapshot_load_tmp(bs, id_or_name, NULL, &local_err);
4717b4c4781SWenchao Xia if (ret == -ENOENT || ret == -EINVAL) {
4727b4c4781SWenchao Xia error_free(local_err);
4737b4c4781SWenchao Xia local_err = NULL;
4747b4c4781SWenchao Xia ret = bdrv_snapshot_load_tmp(bs, NULL, id_or_name, &local_err);
4757b4c4781SWenchao Xia }
4767b4c4781SWenchao Xia
4777b4c4781SWenchao Xia error_propagate(errp, local_err);
4787b4c4781SWenchao Xia
4797b4c4781SWenchao Xia return ret;
4807b4c4781SWenchao Xia }
481e9ff957aSDenis V. Lunev
482cf3a74c9SDaniel P. Berrangé
4832b3912f1SKevin Wolf static int GRAPH_RDLOCK
bdrv_all_get_snapshot_devices(bool has_devices,strList * devices,GList ** all_bdrvs,Error ** errp)4842b3912f1SKevin Wolf bdrv_all_get_snapshot_devices(bool has_devices, strList *devices,
4852b3912f1SKevin Wolf GList **all_bdrvs, Error **errp)
486cf3a74c9SDaniel P. Berrangé {
487cf3a74c9SDaniel P. Berrangé g_autoptr(GList) bdrvs = NULL;
488cf3a74c9SDaniel P. Berrangé
489cf3a74c9SDaniel P. Berrangé if (has_devices) {
490cf3a74c9SDaniel P. Berrangé if (!devices) {
491cf3a74c9SDaniel P. Berrangé error_setg(errp, "At least one device is required for snapshot");
492cf3a74c9SDaniel P. Berrangé return -1;
493cf3a74c9SDaniel P. Berrangé }
494cf3a74c9SDaniel P. Berrangé
495cf3a74c9SDaniel P. Berrangé while (devices) {
496cf3a74c9SDaniel P. Berrangé BlockDriverState *bs = bdrv_find_node(devices->value);
497cf3a74c9SDaniel P. Berrangé if (!bs) {
498cf3a74c9SDaniel P. Berrangé error_setg(errp, "No block device node '%s'", devices->value);
499cf3a74c9SDaniel P. Berrangé return -1;
500cf3a74c9SDaniel P. Berrangé }
501cf3a74c9SDaniel P. Berrangé bdrvs = g_list_append(bdrvs, bs);
502cf3a74c9SDaniel P. Berrangé devices = devices->next;
503cf3a74c9SDaniel P. Berrangé }
504cf3a74c9SDaniel P. Berrangé } else {
505cf3a74c9SDaniel P. Berrangé BlockDriverState *bs;
506cf3a74c9SDaniel P. Berrangé BdrvNextIterator it;
507cf3a74c9SDaniel P. Berrangé for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
508cf3a74c9SDaniel P. Berrangé bdrvs = g_list_append(bdrvs, bs);
509cf3a74c9SDaniel P. Berrangé }
510cf3a74c9SDaniel P. Berrangé }
511cf3a74c9SDaniel P. Berrangé
512cf3a74c9SDaniel P. Berrangé *all_bdrvs = g_steal_pointer(&bdrvs);
513cf3a74c9SDaniel P. Berrangé return 0;
514cf3a74c9SDaniel P. Berrangé }
515cf3a74c9SDaniel P. Berrangé
516cf3a74c9SDaniel P. Berrangé
bdrv_all_snapshots_includes_bs(BlockDriverState * bs)5172b3912f1SKevin Wolf static bool GRAPH_RDLOCK bdrv_all_snapshots_includes_bs(BlockDriverState *bs)
51805f4acedSKevin Wolf {
519a32e7818SKevin Wolf GLOBAL_STATE_CODE();
520a32e7818SKevin Wolf assert_bdrv_graph_readable();
521a32e7818SKevin Wolf
52205f4acedSKevin Wolf if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
52305f4acedSKevin Wolf return false;
52405f4acedSKevin Wolf }
52505f4acedSKevin Wolf
52605f4acedSKevin Wolf /* Include all nodes that are either in use by a BlockBackend, or that
52705f4acedSKevin Wolf * aren't attached to any node, but owned by the monitor. */
52805f4acedSKevin Wolf return bdrv_has_blk(bs) || QLIST_EMPTY(&bs->parents);
52905f4acedSKevin Wolf }
530e9ff957aSDenis V. Lunev
531b49f4755SStefan Hajnoczi /* Group operations. All block drivers are involved. */
532e9ff957aSDenis V. Lunev
bdrv_all_can_snapshot(bool has_devices,strList * devices,Error ** errp)533cf3a74c9SDaniel P. Berrangé bool bdrv_all_can_snapshot(bool has_devices, strList *devices,
534cf3a74c9SDaniel P. Berrangé Error **errp)
535e9ff957aSDenis V. Lunev {
536cf3a74c9SDaniel P. Berrangé g_autoptr(GList) bdrvs = NULL;
537cf3a74c9SDaniel P. Berrangé GList *iterbdrvs;
538e9ff957aSDenis V. Lunev
5396b573efeSEmanuele Giuseppe Esposito GLOBAL_STATE_CODE();
5402b3912f1SKevin Wolf GRAPH_RDLOCK_GUARD_MAINLOOP();
5416b573efeSEmanuele Giuseppe Esposito
542cf3a74c9SDaniel P. Berrangé if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
543cf3a74c9SDaniel P. Berrangé return false;
544cf3a74c9SDaniel P. Berrangé }
545cf3a74c9SDaniel P. Berrangé
546cf3a74c9SDaniel P. Berrangé iterbdrvs = bdrvs;
547cf3a74c9SDaniel P. Berrangé while (iterbdrvs) {
548cf3a74c9SDaniel P. Berrangé BlockDriverState *bs = iterbdrvs->data;
549e26f98e2SDaniel P. Berrangé bool ok = true;
550e9ff957aSDenis V. Lunev
551cf3a74c9SDaniel P. Berrangé if (devices || bdrv_all_snapshots_includes_bs(bs)) {
552e9ff957aSDenis V. Lunev ok = bdrv_can_snapshot(bs);
553e9ff957aSDenis V. Lunev }
55488be7b4bSKevin Wolf if (!ok) {
555e26f98e2SDaniel P. Berrangé error_setg(errp, "Device '%s' is writable but does not support "
556e26f98e2SDaniel P. Berrangé "snapshots", bdrv_get_device_or_node_name(bs));
557e26f98e2SDaniel P. Berrangé return false;
55888be7b4bSKevin Wolf }
559cf3a74c9SDaniel P. Berrangé
560cf3a74c9SDaniel P. Berrangé iterbdrvs = iterbdrvs->next;
561e9ff957aSDenis V. Lunev }
562e9ff957aSDenis V. Lunev
563e26f98e2SDaniel P. Berrangé return true;
564e9ff957aSDenis V. Lunev }
5659b00ea37SDenis V. Lunev
bdrv_all_delete_snapshot(const char * name,bool has_devices,strList * devices,Error ** errp)566cf3a74c9SDaniel P. Berrangé int bdrv_all_delete_snapshot(const char *name,
567cf3a74c9SDaniel P. Berrangé bool has_devices, strList *devices,
568cf3a74c9SDaniel P. Berrangé Error **errp)
5699b00ea37SDenis V. Lunev {
570ce33d85dSZhao Liu ERRP_GUARD();
571cf3a74c9SDaniel P. Berrangé g_autoptr(GList) bdrvs = NULL;
572cf3a74c9SDaniel P. Berrangé GList *iterbdrvs;
5739b00ea37SDenis V. Lunev
5746b573efeSEmanuele Giuseppe Esposito GLOBAL_STATE_CODE();
5752b3912f1SKevin Wolf GRAPH_RDLOCK_GUARD_MAINLOOP();
5766b573efeSEmanuele Giuseppe Esposito
577cf3a74c9SDaniel P. Berrangé if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
578cf3a74c9SDaniel P. Berrangé return -1;
579cf3a74c9SDaniel P. Berrangé }
580cf3a74c9SDaniel P. Berrangé
581cf3a74c9SDaniel P. Berrangé iterbdrvs = bdrvs;
582cf3a74c9SDaniel P. Berrangé while (iterbdrvs) {
583cf3a74c9SDaniel P. Berrangé BlockDriverState *bs = iterbdrvs->data;
584cf3a74c9SDaniel P. Berrangé QEMUSnapshotInfo sn1, *snapshot = &sn1;
585e26f98e2SDaniel P. Berrangé int ret = 0;
5869b00ea37SDenis V. Lunev
587cf3a74c9SDaniel P. Berrangé if ((devices || bdrv_all_snapshots_includes_bs(bs)) &&
58805f4acedSKevin Wolf bdrv_snapshot_find(bs, snapshot, name) >= 0)
58905f4acedSKevin Wolf {
5906ca08045SDaniel Henrique Barboza ret = bdrv_snapshot_delete(bs, snapshot->id_str,
591e53a578aSVladimir Sementsov-Ogievskiy snapshot->name, errp);
5929b00ea37SDenis V. Lunev }
59388be7b4bSKevin Wolf if (ret < 0) {
594e26f98e2SDaniel P. Berrangé error_prepend(errp, "Could not delete snapshot '%s' on '%s': ",
595e26f98e2SDaniel P. Berrangé name, bdrv_get_device_or_node_name(bs));
596e26f98e2SDaniel P. Berrangé return -1;
59788be7b4bSKevin Wolf }
598cf3a74c9SDaniel P. Berrangé
599cf3a74c9SDaniel P. Berrangé iterbdrvs = iterbdrvs->next;
6009b00ea37SDenis V. Lunev }
6019b00ea37SDenis V. Lunev
602e26f98e2SDaniel P. Berrangé return 0;
6039b00ea37SDenis V. Lunev }
6044c1cdbaaSDenis V. Lunev
6054c1cdbaaSDenis V. Lunev
bdrv_all_goto_snapshot(const char * name,bool has_devices,strList * devices,Error ** errp)606cf3a74c9SDaniel P. Berrangé int bdrv_all_goto_snapshot(const char *name,
607cf3a74c9SDaniel P. Berrangé bool has_devices, strList *devices,
608cf3a74c9SDaniel P. Berrangé Error **errp)
6094c1cdbaaSDenis V. Lunev {
610ce33d85dSZhao Liu ERRP_GUARD();
611cf3a74c9SDaniel P. Berrangé g_autoptr(GList) bdrvs = NULL;
612cf3a74c9SDaniel P. Berrangé GList *iterbdrvs;
613a32e7818SKevin Wolf int ret;
6144c1cdbaaSDenis V. Lunev
6156b573efeSEmanuele Giuseppe Esposito GLOBAL_STATE_CODE();
6166b573efeSEmanuele Giuseppe Esposito
617a32e7818SKevin Wolf bdrv_graph_rdlock_main_loop();
618a32e7818SKevin Wolf ret = bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp);
619a32e7818SKevin Wolf bdrv_graph_rdunlock_main_loop();
620a32e7818SKevin Wolf
621a32e7818SKevin Wolf if (ret < 0) {
622cf3a74c9SDaniel P. Berrangé return -1;
623cf3a74c9SDaniel P. Berrangé }
624cf3a74c9SDaniel P. Berrangé
625cf3a74c9SDaniel P. Berrangé iterbdrvs = bdrvs;
626cf3a74c9SDaniel P. Berrangé while (iterbdrvs) {
627cf3a74c9SDaniel P. Berrangé BlockDriverState *bs = iterbdrvs->data;
628a32e7818SKevin Wolf bool all_snapshots_includes_bs;
6294c1cdbaaSDenis V. Lunev
630a32e7818SKevin Wolf bdrv_graph_rdlock_main_loop();
631a32e7818SKevin Wolf all_snapshots_includes_bs = bdrv_all_snapshots_includes_bs(bs);
632a32e7818SKevin Wolf bdrv_graph_rdunlock_main_loop();
633a32e7818SKevin Wolf
6346ab4f1c9SThomas Huth ret = (devices || all_snapshots_includes_bs) ?
6356ab4f1c9SThomas Huth bdrv_snapshot_goto(bs, name, errp) : 0;
6362b624fe0SKevin Wolf if (ret < 0) {
6374026f1c4SKevin Wolf bdrv_graph_rdlock_main_loop();
638e26f98e2SDaniel P. Berrangé error_prepend(errp, "Could not load snapshot '%s' on '%s': ",
639e26f98e2SDaniel P. Berrangé name, bdrv_get_device_or_node_name(bs));
6404026f1c4SKevin Wolf bdrv_graph_rdunlock_main_loop();
641e26f98e2SDaniel P. Berrangé return -1;
64288be7b4bSKevin Wolf }
643cf3a74c9SDaniel P. Berrangé
644cf3a74c9SDaniel P. Berrangé iterbdrvs = iterbdrvs->next;
6454c1cdbaaSDenis V. Lunev }
6464c1cdbaaSDenis V. Lunev
647e26f98e2SDaniel P. Berrangé return 0;
6484c1cdbaaSDenis V. Lunev }
649723ccda1SDenis V. Lunev
bdrv_all_has_snapshot(const char * name,bool has_devices,strList * devices,Error ** errp)6503d3e9b1fSDaniel P. Berrangé int bdrv_all_has_snapshot(const char *name,
651cf3a74c9SDaniel P. Berrangé bool has_devices, strList *devices,
652cf3a74c9SDaniel P. Berrangé Error **errp)
653723ccda1SDenis V. Lunev {
654cf3a74c9SDaniel P. Berrangé g_autoptr(GList) bdrvs = NULL;
655cf3a74c9SDaniel P. Berrangé GList *iterbdrvs;
656723ccda1SDenis V. Lunev
6576b573efeSEmanuele Giuseppe Esposito GLOBAL_STATE_CODE();
6582b3912f1SKevin Wolf GRAPH_RDLOCK_GUARD_MAINLOOP();
6596b573efeSEmanuele Giuseppe Esposito
660cf3a74c9SDaniel P. Berrangé if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
661cf3a74c9SDaniel P. Berrangé return -1;
662cf3a74c9SDaniel P. Berrangé }
663cf3a74c9SDaniel P. Berrangé
664cf3a74c9SDaniel P. Berrangé iterbdrvs = bdrvs;
665cf3a74c9SDaniel P. Berrangé while (iterbdrvs) {
666cf3a74c9SDaniel P. Berrangé BlockDriverState *bs = iterbdrvs->data;
667cf3a74c9SDaniel P. Berrangé QEMUSnapshotInfo sn;
668e26f98e2SDaniel P. Berrangé int ret = 0;
669723ccda1SDenis V. Lunev
670cf3a74c9SDaniel P. Berrangé if (devices || bdrv_all_snapshots_includes_bs(bs)) {
671e26f98e2SDaniel P. Berrangé ret = bdrv_snapshot_find(bs, &sn, name);
672723ccda1SDenis V. Lunev }
673e26f98e2SDaniel P. Berrangé if (ret < 0) {
6743d3e9b1fSDaniel P. Berrangé if (ret == -ENOENT) {
6753d3e9b1fSDaniel P. Berrangé return 0;
6763d3e9b1fSDaniel P. Berrangé } else {
6773d3e9b1fSDaniel P. Berrangé error_setg_errno(errp, errno,
6783d3e9b1fSDaniel P. Berrangé "Could not check snapshot '%s' on '%s'",
679e26f98e2SDaniel P. Berrangé name, bdrv_get_device_or_node_name(bs));
680e26f98e2SDaniel P. Berrangé return -1;
68188be7b4bSKevin Wolf }
6823d3e9b1fSDaniel P. Berrangé }
683cf3a74c9SDaniel P. Berrangé
684cf3a74c9SDaniel P. Berrangé iterbdrvs = iterbdrvs->next;
685723ccda1SDenis V. Lunev }
686723ccda1SDenis V. Lunev
6873d3e9b1fSDaniel P. Berrangé return 1;
688723ccda1SDenis V. Lunev }
689a9085f9bSDenis V. Lunev
bdrv_all_create_snapshot(QEMUSnapshotInfo * sn,BlockDriverState * vm_state_bs,uint64_t vm_state_size,bool has_devices,strList * devices,Error ** errp)690a9085f9bSDenis V. Lunev int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn,
691a9085f9bSDenis V. Lunev BlockDriverState *vm_state_bs,
692a9085f9bSDenis V. Lunev uint64_t vm_state_size,
693cf3a74c9SDaniel P. Berrangé bool has_devices, strList *devices,
694e26f98e2SDaniel P. Berrangé Error **errp)
695a9085f9bSDenis V. Lunev {
696cf3a74c9SDaniel P. Berrangé g_autoptr(GList) bdrvs = NULL;
697cf3a74c9SDaniel P. Berrangé GList *iterbdrvs;
6982b3912f1SKevin Wolf
6996b573efeSEmanuele Giuseppe Esposito GLOBAL_STATE_CODE();
7002b3912f1SKevin Wolf GRAPH_RDLOCK_GUARD_MAINLOOP();
701a9085f9bSDenis V. Lunev
702cf3a74c9SDaniel P. Berrangé if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
703cf3a74c9SDaniel P. Berrangé return -1;
704cf3a74c9SDaniel P. Berrangé }
705cf3a74c9SDaniel P. Berrangé
706cf3a74c9SDaniel P. Berrangé iterbdrvs = bdrvs;
707cf3a74c9SDaniel P. Berrangé while (iterbdrvs) {
708cf3a74c9SDaniel P. Berrangé BlockDriverState *bs = iterbdrvs->data;
709e26f98e2SDaniel P. Berrangé int ret = 0;
710a9085f9bSDenis V. Lunev
711a9085f9bSDenis V. Lunev if (bs == vm_state_bs) {
712a9085f9bSDenis V. Lunev sn->vm_state_size = vm_state_size;
713e26f98e2SDaniel P. Berrangé ret = bdrv_snapshot_create(bs, sn);
714cf3a74c9SDaniel P. Berrangé } else if (devices || bdrv_all_snapshots_includes_bs(bs)) {
715a9085f9bSDenis V. Lunev sn->vm_state_size = 0;
716e26f98e2SDaniel P. Berrangé ret = bdrv_snapshot_create(bs, sn);
717a9085f9bSDenis V. Lunev }
718e26f98e2SDaniel P. Berrangé if (ret < 0) {
719e26f98e2SDaniel P. Berrangé error_setg(errp, "Could not create snapshot '%s' on '%s'",
720e26f98e2SDaniel P. Berrangé sn->name, bdrv_get_device_or_node_name(bs));
721e26f98e2SDaniel P. Berrangé return -1;
72288be7b4bSKevin Wolf }
723cf3a74c9SDaniel P. Berrangé
724cf3a74c9SDaniel P. Berrangé iterbdrvs = iterbdrvs->next;
725a9085f9bSDenis V. Lunev }
726a9085f9bSDenis V. Lunev
727e26f98e2SDaniel P. Berrangé return 0;
728a9085f9bSDenis V. Lunev }
7297cb14481SDenis V. Lunev
730c22d644cSDaniel P. Berrangé
bdrv_all_find_vmstate_bs(const char * vmstate_bs,bool has_devices,strList * devices,Error ** errp)731c22d644cSDaniel P. Berrangé BlockDriverState *bdrv_all_find_vmstate_bs(const char *vmstate_bs,
732c22d644cSDaniel P. Berrangé bool has_devices, strList *devices,
733cf3a74c9SDaniel P. Berrangé Error **errp)
7347cb14481SDenis V. Lunev {
735cf3a74c9SDaniel P. Berrangé g_autoptr(GList) bdrvs = NULL;
736cf3a74c9SDaniel P. Berrangé GList *iterbdrvs;
7377cb14481SDenis V. Lunev
7386b573efeSEmanuele Giuseppe Esposito GLOBAL_STATE_CODE();
7392b3912f1SKevin Wolf GRAPH_RDLOCK_GUARD_MAINLOOP();
7406b573efeSEmanuele Giuseppe Esposito
741cf3a74c9SDaniel P. Berrangé if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
742cf3a74c9SDaniel P. Berrangé return NULL;
743cf3a74c9SDaniel P. Berrangé }
744cf3a74c9SDaniel P. Berrangé
745cf3a74c9SDaniel P. Berrangé iterbdrvs = bdrvs;
746cf3a74c9SDaniel P. Berrangé while (iterbdrvs) {
747cf3a74c9SDaniel P. Berrangé BlockDriverState *bs = iterbdrvs->data;
748cf3a74c9SDaniel P. Berrangé bool found = false;
7497cb14481SDenis V. Lunev
750cf3a74c9SDaniel P. Berrangé found = (devices || bdrv_all_snapshots_includes_bs(bs)) &&
751cf3a74c9SDaniel P. Berrangé bdrv_can_snapshot(bs);
75288be7b4bSKevin Wolf
753c22d644cSDaniel P. Berrangé if (vmstate_bs) {
754c22d644cSDaniel P. Berrangé if (g_str_equal(vmstate_bs,
755c22d644cSDaniel P. Berrangé bdrv_get_node_name(bs))) {
75688be7b4bSKevin Wolf if (found) {
7577cb14481SDenis V. Lunev return bs;
758c22d644cSDaniel P. Berrangé } else {
759c22d644cSDaniel P. Berrangé error_setg(errp,
760c22d644cSDaniel P. Berrangé "vmstate block device '%s' does not support snapshots",
761c22d644cSDaniel P. Berrangé vmstate_bs);
762c22d644cSDaniel P. Berrangé return NULL;
763c22d644cSDaniel P. Berrangé }
764c22d644cSDaniel P. Berrangé }
765c22d644cSDaniel P. Berrangé } else if (found) {
766c22d644cSDaniel P. Berrangé return bs;
7677cb14481SDenis V. Lunev }
768cf3a74c9SDaniel P. Berrangé
769cf3a74c9SDaniel P. Berrangé iterbdrvs = iterbdrvs->next;
770cf3a74c9SDaniel P. Berrangé }
771cf3a74c9SDaniel P. Berrangé
772c22d644cSDaniel P. Berrangé if (vmstate_bs) {
773c22d644cSDaniel P. Berrangé error_setg(errp,
774c22d644cSDaniel P. Berrangé "vmstate block device '%s' does not exist", vmstate_bs);
775c22d644cSDaniel P. Berrangé } else {
776c22d644cSDaniel P. Berrangé error_setg(errp,
777c22d644cSDaniel P. Berrangé "no block device can store vmstate for snapshot");
778c22d644cSDaniel P. Berrangé }
779cf3a74c9SDaniel P. Berrangé return NULL;
780cf3a74c9SDaniel P. Berrangé }
781