xref: /qemu/block/snapshot.c (revision 0c6100a7)
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"
31cc7a8ea7SMarkus Armbruster #include "qapi/qmp/qerror.h"
327a9e5119SDong Jia Shi #include "qapi/qmp/qstring.h"
33922a01a0SMarkus Armbruster #include "qemu/option.h"
3405f4acedSKevin Wolf #include "sysemu/block-backend.h"
35de08c606SWenchao Xia 
368c116b0eSWenchao Xia QemuOptsList internal_snapshot_opts = {
378c116b0eSWenchao Xia     .name = "snapshot",
388c116b0eSWenchao Xia     .head = QTAILQ_HEAD_INITIALIZER(internal_snapshot_opts.head),
398c116b0eSWenchao Xia     .desc = {
408c116b0eSWenchao Xia         {
418c116b0eSWenchao Xia             .name = SNAPSHOT_OPT_ID,
428c116b0eSWenchao Xia             .type = QEMU_OPT_STRING,
438c116b0eSWenchao Xia             .help = "snapshot id"
448c116b0eSWenchao Xia         },{
458c116b0eSWenchao Xia             .name = SNAPSHOT_OPT_NAME,
468c116b0eSWenchao Xia             .type = QEMU_OPT_STRING,
478c116b0eSWenchao Xia             .help = "snapshot name"
488c116b0eSWenchao Xia         },{
498c116b0eSWenchao Xia             /* end of list */
508c116b0eSWenchao Xia         }
518c116b0eSWenchao Xia     },
528c116b0eSWenchao Xia };
538c116b0eSWenchao Xia 
54de08c606SWenchao Xia int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
55de08c606SWenchao Xia                        const char *name)
56de08c606SWenchao Xia {
57de08c606SWenchao Xia     QEMUSnapshotInfo *sn_tab, *sn;
58de08c606SWenchao Xia     int nb_sns, i, ret;
59de08c606SWenchao Xia 
606b573efeSEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
616b573efeSEmanuele Giuseppe Esposito 
62de08c606SWenchao Xia     ret = -ENOENT;
63de08c606SWenchao Xia     nb_sns = bdrv_snapshot_list(bs, &sn_tab);
64de08c606SWenchao Xia     if (nb_sns < 0) {
65de08c606SWenchao Xia         return ret;
66de08c606SWenchao Xia     }
67de08c606SWenchao Xia     for (i = 0; i < nb_sns; i++) {
68de08c606SWenchao Xia         sn = &sn_tab[i];
696ca08045SDaniel Henrique Barboza         if (!strcmp(sn->name, name)) {
70de08c606SWenchao Xia             *sn_info = *sn;
71de08c606SWenchao Xia             ret = 0;
72de08c606SWenchao Xia             break;
73de08c606SWenchao Xia         }
74de08c606SWenchao Xia     }
75de08c606SWenchao Xia     g_free(sn_tab);
76de08c606SWenchao Xia     return ret;
77de08c606SWenchao Xia }
78de08c606SWenchao Xia 
792ea1dd75SWenchao Xia /**
802ea1dd75SWenchao Xia  * Look up an internal snapshot by @id and @name.
812ea1dd75SWenchao Xia  * @bs: block device to search
822ea1dd75SWenchao Xia  * @id: unique snapshot ID, or NULL
832ea1dd75SWenchao Xia  * @name: snapshot name, or NULL
842ea1dd75SWenchao Xia  * @sn_info: location to store information on the snapshot found
852ea1dd75SWenchao Xia  * @errp: location to store error, will be set only for exception
862ea1dd75SWenchao Xia  *
872ea1dd75SWenchao Xia  * This function will traverse snapshot list in @bs to search the matching
882ea1dd75SWenchao Xia  * one, @id and @name are the matching condition:
892ea1dd75SWenchao Xia  * If both @id and @name are specified, find the first one with id @id and
902ea1dd75SWenchao Xia  * name @name.
912ea1dd75SWenchao Xia  * If only @id is specified, find the first one with id @id.
922ea1dd75SWenchao Xia  * If only @name is specified, find the first one with name @name.
932ea1dd75SWenchao Xia  * if none is specified, abort().
942ea1dd75SWenchao Xia  *
952ea1dd75SWenchao Xia  * Returns: true when a snapshot is found and @sn_info will be filled, false
962ea1dd75SWenchao Xia  * when error or not found. If all operation succeed but no matching one is
972ea1dd75SWenchao Xia  * found, @errp will NOT be set.
982ea1dd75SWenchao Xia  */
992ea1dd75SWenchao Xia bool bdrv_snapshot_find_by_id_and_name(BlockDriverState *bs,
1002ea1dd75SWenchao Xia                                        const char *id,
1012ea1dd75SWenchao Xia                                        const char *name,
1022ea1dd75SWenchao Xia                                        QEMUSnapshotInfo *sn_info,
1032ea1dd75SWenchao Xia                                        Error **errp)
1042ea1dd75SWenchao Xia {
1052ea1dd75SWenchao Xia     QEMUSnapshotInfo *sn_tab, *sn;
1062ea1dd75SWenchao Xia     int nb_sns, i;
1072ea1dd75SWenchao Xia     bool ret = false;
1082ea1dd75SWenchao Xia 
1092ea1dd75SWenchao Xia     assert(id || name);
1106b573efeSEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
1112ea1dd75SWenchao Xia 
1122ea1dd75SWenchao Xia     nb_sns = bdrv_snapshot_list(bs, &sn_tab);
1132ea1dd75SWenchao Xia     if (nb_sns < 0) {
1142ea1dd75SWenchao Xia         error_setg_errno(errp, -nb_sns, "Failed to get a snapshot list");
1152ea1dd75SWenchao Xia         return false;
1162ea1dd75SWenchao Xia     } else if (nb_sns == 0) {
1172ea1dd75SWenchao Xia         return false;
1182ea1dd75SWenchao Xia     }
1192ea1dd75SWenchao Xia 
1202ea1dd75SWenchao Xia     if (id && name) {
1212ea1dd75SWenchao Xia         for (i = 0; i < nb_sns; i++) {
1222ea1dd75SWenchao Xia             sn = &sn_tab[i];
1232ea1dd75SWenchao Xia             if (!strcmp(sn->id_str, id) && !strcmp(sn->name, name)) {
1242ea1dd75SWenchao Xia                 *sn_info = *sn;
1252ea1dd75SWenchao Xia                 ret = true;
1262ea1dd75SWenchao Xia                 break;
1272ea1dd75SWenchao Xia             }
1282ea1dd75SWenchao Xia         }
1292ea1dd75SWenchao Xia     } else if (id) {
1302ea1dd75SWenchao Xia         for (i = 0; i < nb_sns; i++) {
1312ea1dd75SWenchao Xia             sn = &sn_tab[i];
1322ea1dd75SWenchao Xia             if (!strcmp(sn->id_str, id)) {
1332ea1dd75SWenchao Xia                 *sn_info = *sn;
1342ea1dd75SWenchao Xia                 ret = true;
1352ea1dd75SWenchao Xia                 break;
1362ea1dd75SWenchao Xia             }
1372ea1dd75SWenchao Xia         }
1382ea1dd75SWenchao Xia     } else if (name) {
1392ea1dd75SWenchao Xia         for (i = 0; i < nb_sns; i++) {
1402ea1dd75SWenchao Xia             sn = &sn_tab[i];
1412ea1dd75SWenchao Xia             if (!strcmp(sn->name, name)) {
1422ea1dd75SWenchao Xia                 *sn_info = *sn;
1432ea1dd75SWenchao Xia                 ret = true;
1442ea1dd75SWenchao Xia                 break;
1452ea1dd75SWenchao Xia             }
1462ea1dd75SWenchao Xia         }
1472ea1dd75SWenchao Xia     }
1482ea1dd75SWenchao Xia 
1492ea1dd75SWenchao Xia     g_free(sn_tab);
1502ea1dd75SWenchao Xia     return ret;
1512ea1dd75SWenchao Xia }
1522ea1dd75SWenchao Xia 
153c8af8757SMax Reitz /**
154c8af8757SMax Reitz  * Return a pointer to the child BDS pointer to which we can fall
155c8af8757SMax Reitz  * back if the given BDS does not support snapshots.
156c8af8757SMax Reitz  * Return NULL if there is no BDS to (safely) fall back to.
157c8af8757SMax Reitz  *
158c8af8757SMax Reitz  * We need to return an indirect pointer because bdrv_snapshot_goto()
159c8af8757SMax Reitz  * has to modify the BdrvChild pointer.
160c8af8757SMax Reitz  */
161c8af8757SMax Reitz static BdrvChild **bdrv_snapshot_fallback_ptr(BlockDriverState *bs)
162c8af8757SMax Reitz {
163c8af8757SMax Reitz     BdrvChild **fallback;
1640c6100a7SVladimir Sementsov-Ogievskiy     BdrvChild *child = bdrv_primary_child(bs);
165c8af8757SMax Reitz 
1660c6100a7SVladimir Sementsov-Ogievskiy     /* We allow fallback only to primary child */
1670c6100a7SVladimir Sementsov-Ogievskiy     if (!child) {
168c8af8757SMax Reitz         return NULL;
169c8af8757SMax Reitz     }
1700c6100a7SVladimir Sementsov-Ogievskiy     fallback = (child == bs->file ? &bs->file : &bs->backing);
1710c6100a7SVladimir Sementsov-Ogievskiy     assert(*fallback == child);
172c8af8757SMax Reitz 
173c8af8757SMax Reitz     /*
174c8af8757SMax Reitz      * Check that there are no other children that would need to be
175c8af8757SMax Reitz      * snapshotted.  If there are, it is not safe to fall back to
176c8af8757SMax Reitz      * *fallback.
177c8af8757SMax Reitz      */
178c8af8757SMax Reitz     QLIST_FOREACH(child, &bs->children, next) {
179c8af8757SMax Reitz         if (child->role & (BDRV_CHILD_DATA | BDRV_CHILD_METADATA |
180c8af8757SMax Reitz                            BDRV_CHILD_FILTERED) &&
181c8af8757SMax Reitz             child != *fallback)
182c8af8757SMax Reitz         {
183c8af8757SMax Reitz             return NULL;
184c8af8757SMax Reitz         }
185c8af8757SMax Reitz     }
186c8af8757SMax Reitz 
187c8af8757SMax Reitz     return fallback;
188c8af8757SMax Reitz }
189c8af8757SMax Reitz 
190c8af8757SMax Reitz static BlockDriverState *bdrv_snapshot_fallback(BlockDriverState *bs)
191c8af8757SMax Reitz {
192c8af8757SMax Reitz     BdrvChild **child_ptr = bdrv_snapshot_fallback_ptr(bs);
193c8af8757SMax Reitz     return child_ptr ? (*child_ptr)->bs : NULL;
194c8af8757SMax Reitz }
195c8af8757SMax Reitz 
196de08c606SWenchao Xia int bdrv_can_snapshot(BlockDriverState *bs)
197de08c606SWenchao Xia {
198de08c606SWenchao Xia     BlockDriver *drv = bs->drv;
1996b573efeSEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
200de08c606SWenchao Xia     if (!drv || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
201de08c606SWenchao Xia         return 0;
202de08c606SWenchao Xia     }
203de08c606SWenchao Xia 
204de08c606SWenchao Xia     if (!drv->bdrv_snapshot_create) {
205c8af8757SMax Reitz         BlockDriverState *fallback_bs = bdrv_snapshot_fallback(bs);
206c8af8757SMax Reitz         if (fallback_bs) {
207c8af8757SMax Reitz             return bdrv_can_snapshot(fallback_bs);
208de08c606SWenchao Xia         }
209de08c606SWenchao Xia         return 0;
210de08c606SWenchao Xia     }
211de08c606SWenchao Xia 
212de08c606SWenchao Xia     return 1;
213de08c606SWenchao Xia }
214de08c606SWenchao Xia 
215de08c606SWenchao Xia int bdrv_snapshot_create(BlockDriverState *bs,
216de08c606SWenchao Xia                          QEMUSnapshotInfo *sn_info)
217de08c606SWenchao Xia {
218de08c606SWenchao Xia     BlockDriver *drv = bs->drv;
219c8af8757SMax Reitz     BlockDriverState *fallback_bs = bdrv_snapshot_fallback(bs);
2206b573efeSEmanuele Giuseppe Esposito 
2216b573efeSEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
2226b573efeSEmanuele Giuseppe Esposito 
223de08c606SWenchao Xia     if (!drv) {
224de08c606SWenchao Xia         return -ENOMEDIUM;
225de08c606SWenchao Xia     }
226de08c606SWenchao Xia     if (drv->bdrv_snapshot_create) {
227de08c606SWenchao Xia         return drv->bdrv_snapshot_create(bs, sn_info);
228de08c606SWenchao Xia     }
229c8af8757SMax Reitz     if (fallback_bs) {
230c8af8757SMax Reitz         return bdrv_snapshot_create(fallback_bs, sn_info);
231de08c606SWenchao Xia     }
232de08c606SWenchao Xia     return -ENOTSUP;
233de08c606SWenchao Xia }
234de08c606SWenchao Xia 
235de08c606SWenchao Xia int bdrv_snapshot_goto(BlockDriverState *bs,
2360b62bcbcSKevin Wolf                        const char *snapshot_id,
2370b62bcbcSKevin Wolf                        Error **errp)
238de08c606SWenchao Xia {
239de08c606SWenchao Xia     BlockDriver *drv = bs->drv;
240c8af8757SMax Reitz     BdrvChild **fallback_ptr;
241de08c606SWenchao Xia     int ret, open_ret;
242de08c606SWenchao Xia 
2436b573efeSEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
2446b573efeSEmanuele Giuseppe Esposito 
245de08c606SWenchao Xia     if (!drv) {
2460b62bcbcSKevin Wolf         error_setg(errp, "Block driver is closed");
247de08c606SWenchao Xia         return -ENOMEDIUM;
248de08c606SWenchao Xia     }
24904dec3c3SVladimir Sementsov-Ogievskiy 
25070a5afedSKevin Wolf     if (!QLIST_EMPTY(&bs->dirty_bitmaps)) {
25170a5afedSKevin Wolf         error_setg(errp, "Device has active dirty bitmaps");
25270a5afedSKevin Wolf         return -EBUSY;
25304dec3c3SVladimir Sementsov-Ogievskiy     }
25404dec3c3SVladimir Sementsov-Ogievskiy 
255de08c606SWenchao Xia     if (drv->bdrv_snapshot_goto) {
2560b62bcbcSKevin Wolf         ret = drv->bdrv_snapshot_goto(bs, snapshot_id);
2570b62bcbcSKevin Wolf         if (ret < 0) {
2580b62bcbcSKevin Wolf             error_setg_errno(errp, -ret, "Failed to load snapshot");
2590b62bcbcSKevin Wolf         }
2600b62bcbcSKevin Wolf         return ret;
261de08c606SWenchao Xia     }
262de08c606SWenchao Xia 
263c8af8757SMax Reitz     fallback_ptr = bdrv_snapshot_fallback_ptr(bs);
264c8af8757SMax Reitz     if (fallback_ptr) {
265c8af8757SMax Reitz         QDict *options;
2667a9e5119SDong Jia Shi         QDict *file_options;
2670b62bcbcSKevin Wolf         Error *local_err = NULL;
268c8af8757SMax Reitz         BlockDriverState *fallback_bs = (*fallback_ptr)->bs;
269c8af8757SMax Reitz         char *subqdict_prefix = g_strdup_printf("%s.", (*fallback_ptr)->name);
2707a9e5119SDong Jia Shi 
271c8af8757SMax Reitz         options = qdict_clone_shallow(bs->options);
272c8af8757SMax Reitz 
2737a9e5119SDong Jia Shi         /* Prevent it from getting deleted when detached from bs */
274c8af8757SMax Reitz         bdrv_ref(fallback_bs);
2757a9e5119SDong Jia Shi 
276c8af8757SMax Reitz         qdict_extract_subqdict(options, &file_options, subqdict_prefix);
277cb3e7f08SMarc-André Lureau         qobject_unref(file_options);
278c8af8757SMax Reitz         g_free(subqdict_prefix);
279c8af8757SMax Reitz 
28032a9a245SMax Reitz         /* Force .bdrv_open() below to re-attach fallback_bs on *fallback_ptr */
281c8af8757SMax Reitz         qdict_put_str(options, (*fallback_ptr)->name,
282c8af8757SMax Reitz                       bdrv_get_node_name(fallback_bs));
2837a9e5119SDong Jia Shi 
28432a9a245SMax Reitz         /* Now close bs, apply the snapshot on fallback_bs, and re-open bs */
2853c005293SVladimir Sementsov-Ogievskiy         if (drv->bdrv_close) {
286de08c606SWenchao Xia             drv->bdrv_close(bs);
2873c005293SVladimir Sementsov-Ogievskiy         }
2887a9e5119SDong Jia Shi 
28932a9a245SMax Reitz         /* .bdrv_open() will re-attach it */
290c8af8757SMax Reitz         bdrv_unref_child(bs, *fallback_ptr);
291c8af8757SMax Reitz         *fallback_ptr = NULL;
292c8af8757SMax Reitz 
293c8af8757SMax Reitz         ret = bdrv_snapshot_goto(fallback_bs, snapshot_id, errp);
2940b62bcbcSKevin Wolf         open_ret = drv->bdrv_open(bs, options, bs->open_flags, &local_err);
295cb3e7f08SMarc-André Lureau         qobject_unref(options);
296de08c606SWenchao Xia         if (open_ret < 0) {
297c8af8757SMax Reitz             bdrv_unref(fallback_bs);
298de08c606SWenchao Xia             bs->drv = NULL;
2990b62bcbcSKevin Wolf             /* A bdrv_snapshot_goto() error takes precedence */
3000b62bcbcSKevin Wolf             error_propagate(errp, local_err);
3010b62bcbcSKevin Wolf             return ret < 0 ? ret : open_ret;
302de08c606SWenchao Xia         }
3037a9e5119SDong Jia Shi 
30432a9a245SMax Reitz         /*
3050c6100a7SVladimir Sementsov-Ogievskiy          * fallback was a primary child. It was closed above and set to NULL,
3060c6100a7SVladimir Sementsov-Ogievskiy          * but the .bdrv_open() call has opened it again, because we set the
3070c6100a7SVladimir Sementsov-Ogievskiy          * respective option (with the qdict_put_str() call above).
3080c6100a7SVladimir Sementsov-Ogievskiy          * Assert that .bdrv_open() has attached the right BDS as primary child.
30932a9a245SMax Reitz          */
3100c6100a7SVladimir Sementsov-Ogievskiy         assert(bdrv_primary_bs(bs) == fallback_bs);
311c8af8757SMax Reitz         bdrv_unref(fallback_bs);
312de08c606SWenchao Xia         return ret;
313de08c606SWenchao Xia     }
314de08c606SWenchao Xia 
3150b62bcbcSKevin Wolf     error_setg(errp, "Block driver does not support snapshots");
316de08c606SWenchao Xia     return -ENOTSUP;
317de08c606SWenchao Xia }
318de08c606SWenchao Xia 
319a89d89d3SWenchao Xia /**
320a89d89d3SWenchao Xia  * Delete an internal snapshot by @snapshot_id and @name.
321a89d89d3SWenchao Xia  * @bs: block device used in the operation
322a89d89d3SWenchao Xia  * @snapshot_id: unique snapshot ID, or NULL
323a89d89d3SWenchao Xia  * @name: snapshot name, or NULL
324a89d89d3SWenchao Xia  * @errp: location to store error
325a89d89d3SWenchao Xia  *
326a89d89d3SWenchao Xia  * If both @snapshot_id and @name are specified, delete the first one with
327a89d89d3SWenchao Xia  * id @snapshot_id and name @name.
328a89d89d3SWenchao Xia  * If only @snapshot_id is specified, delete the first one with id
329a89d89d3SWenchao Xia  * @snapshot_id.
330a89d89d3SWenchao Xia  * If only @name is specified, delete the first one with name @name.
3317b4c4781SWenchao Xia  * if none is specified, return -EINVAL.
332a89d89d3SWenchao Xia  *
333a89d89d3SWenchao Xia  * Returns: 0 on success, -errno on failure. If @bs is not inserted, return
334a89d89d3SWenchao Xia  * -ENOMEDIUM. If @snapshot_id and @name are both NULL, return -EINVAL. If @bs
335a89d89d3SWenchao Xia  * does not support internal snapshot deletion, return -ENOTSUP. If @bs does
336a89d89d3SWenchao Xia  * not support parameter @snapshot_id or @name, or one of them is not correctly
337a89d89d3SWenchao Xia  * specified, return -EINVAL. If @bs can't find one matching @id and @name,
338a89d89d3SWenchao Xia  * return -ENOENT. If @errp != NULL, it will always be filled with error
339a89d89d3SWenchao Xia  * message on failure.
340a89d89d3SWenchao Xia  */
341a89d89d3SWenchao Xia int bdrv_snapshot_delete(BlockDriverState *bs,
342a89d89d3SWenchao Xia                          const char *snapshot_id,
343a89d89d3SWenchao Xia                          const char *name,
344a89d89d3SWenchao Xia                          Error **errp)
345de08c606SWenchao Xia {
346de08c606SWenchao Xia     BlockDriver *drv = bs->drv;
347c8af8757SMax Reitz     BlockDriverState *fallback_bs = bdrv_snapshot_fallback(bs);
34827a7649aSPaolo Bonzini     int ret;
34927a7649aSPaolo Bonzini 
3506b573efeSEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
3516b573efeSEmanuele Giuseppe Esposito 
352de08c606SWenchao Xia     if (!drv) {
353c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs));
354de08c606SWenchao Xia         return -ENOMEDIUM;
355de08c606SWenchao Xia     }
356a89d89d3SWenchao Xia     if (!snapshot_id && !name) {
357a89d89d3SWenchao Xia         error_setg(errp, "snapshot_id and name are both NULL");
358a89d89d3SWenchao Xia         return -EINVAL;
359a89d89d3SWenchao Xia     }
3603432a192SZhang Haoyu 
3613432a192SZhang Haoyu     /* drain all pending i/o before deleting snapshot */
36227a7649aSPaolo Bonzini     bdrv_drained_begin(bs);
3633432a192SZhang Haoyu 
364de08c606SWenchao Xia     if (drv->bdrv_snapshot_delete) {
36527a7649aSPaolo Bonzini         ret = drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp);
366c8af8757SMax Reitz     } else if (fallback_bs) {
367c8af8757SMax Reitz         ret = bdrv_snapshot_delete(fallback_bs, snapshot_id, name, errp);
36827a7649aSPaolo Bonzini     } else {
36981e5f78aSAlberto Garcia         error_setg(errp, "Block format '%s' used by device '%s' "
37081e5f78aSAlberto Garcia                    "does not support internal snapshot deletion",
37181e5f78aSAlberto Garcia                    drv->format_name, bdrv_get_device_name(bs));
37227a7649aSPaolo Bonzini         ret = -ENOTSUP;
37327a7649aSPaolo Bonzini     }
37427a7649aSPaolo Bonzini 
37527a7649aSPaolo Bonzini     bdrv_drained_end(bs);
37627a7649aSPaolo Bonzini     return ret;
377de08c606SWenchao Xia }
378de08c606SWenchao Xia 
379de08c606SWenchao Xia int bdrv_snapshot_list(BlockDriverState *bs,
380de08c606SWenchao Xia                        QEMUSnapshotInfo **psn_info)
381de08c606SWenchao Xia {
382de08c606SWenchao Xia     BlockDriver *drv = bs->drv;
383c8af8757SMax Reitz     BlockDriverState *fallback_bs = bdrv_snapshot_fallback(bs);
3846b573efeSEmanuele Giuseppe Esposito 
3856b573efeSEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
386de08c606SWenchao Xia     if (!drv) {
387de08c606SWenchao Xia         return -ENOMEDIUM;
388de08c606SWenchao Xia     }
389de08c606SWenchao Xia     if (drv->bdrv_snapshot_list) {
390de08c606SWenchao Xia         return drv->bdrv_snapshot_list(bs, psn_info);
391de08c606SWenchao Xia     }
392c8af8757SMax Reitz     if (fallback_bs) {
393c8af8757SMax Reitz         return bdrv_snapshot_list(fallback_bs, psn_info);
394de08c606SWenchao Xia     }
395de08c606SWenchao Xia     return -ENOTSUP;
396de08c606SWenchao Xia }
397de08c606SWenchao Xia 
3987b4c4781SWenchao Xia /**
3997b4c4781SWenchao Xia  * Temporarily load an internal snapshot by @snapshot_id and @name.
4007b4c4781SWenchao Xia  * @bs: block device used in the operation
4017b4c4781SWenchao Xia  * @snapshot_id: unique snapshot ID, or NULL
4027b4c4781SWenchao Xia  * @name: snapshot name, or NULL
4037b4c4781SWenchao Xia  * @errp: location to store error
4047b4c4781SWenchao Xia  *
4057b4c4781SWenchao Xia  * If both @snapshot_id and @name are specified, load the first one with
4067b4c4781SWenchao Xia  * id @snapshot_id and name @name.
4077b4c4781SWenchao Xia  * If only @snapshot_id is specified, load the first one with id
4087b4c4781SWenchao Xia  * @snapshot_id.
4097b4c4781SWenchao Xia  * If only @name is specified, load the first one with name @name.
4107b4c4781SWenchao Xia  * if none is specified, return -EINVAL.
4117b4c4781SWenchao Xia  *
4127b4c4781SWenchao Xia  * Returns: 0 on success, -errno on fail. If @bs is not inserted, return
4137b4c4781SWenchao Xia  * -ENOMEDIUM. If @bs is not readonly, return -EINVAL. If @bs did not support
4147b4c4781SWenchao Xia  * internal snapshot, return -ENOTSUP. If qemu can't find a matching @id and
4157b4c4781SWenchao Xia  * @name, return -ENOENT. If @errp != NULL, it will always be filled on
4167b4c4781SWenchao Xia  * failure.
4177b4c4781SWenchao Xia  */
418de08c606SWenchao Xia int bdrv_snapshot_load_tmp(BlockDriverState *bs,
4197b4c4781SWenchao Xia                            const char *snapshot_id,
4207b4c4781SWenchao Xia                            const char *name,
4217b4c4781SWenchao Xia                            Error **errp)
422de08c606SWenchao Xia {
423de08c606SWenchao Xia     BlockDriver *drv = bs->drv;
4247b4c4781SWenchao Xia 
4256b573efeSEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
4266b573efeSEmanuele Giuseppe Esposito 
427de08c606SWenchao Xia     if (!drv) {
428c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs));
429de08c606SWenchao Xia         return -ENOMEDIUM;
430de08c606SWenchao Xia     }
4317b4c4781SWenchao Xia     if (!snapshot_id && !name) {
4327b4c4781SWenchao Xia         error_setg(errp, "snapshot_id and name are both NULL");
4337b4c4781SWenchao Xia         return -EINVAL;
4347b4c4781SWenchao Xia     }
435307261b2SVladimir Sementsov-Ogievskiy     if (!bdrv_is_read_only(bs)) {
4367b4c4781SWenchao Xia         error_setg(errp, "Device is not readonly");
437de08c606SWenchao Xia         return -EINVAL;
438de08c606SWenchao Xia     }
439de08c606SWenchao Xia     if (drv->bdrv_snapshot_load_tmp) {
4407b4c4781SWenchao Xia         return drv->bdrv_snapshot_load_tmp(bs, snapshot_id, name, errp);
441de08c606SWenchao Xia     }
44281e5f78aSAlberto Garcia     error_setg(errp, "Block format '%s' used by device '%s' "
44381e5f78aSAlberto Garcia                "does not support temporarily loading internal snapshots",
44481e5f78aSAlberto Garcia                drv->format_name, bdrv_get_device_name(bs));
445de08c606SWenchao Xia     return -ENOTSUP;
446de08c606SWenchao Xia }
4477b4c4781SWenchao Xia 
4487b4c4781SWenchao Xia int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,
4497b4c4781SWenchao Xia                                          const char *id_or_name,
4507b4c4781SWenchao Xia                                          Error **errp)
4517b4c4781SWenchao Xia {
4527b4c4781SWenchao Xia     int ret;
4537b4c4781SWenchao Xia     Error *local_err = NULL;
4547b4c4781SWenchao Xia 
4556b573efeSEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
4566b573efeSEmanuele Giuseppe Esposito 
4577b4c4781SWenchao Xia     ret = bdrv_snapshot_load_tmp(bs, id_or_name, NULL, &local_err);
4587b4c4781SWenchao Xia     if (ret == -ENOENT || ret == -EINVAL) {
4597b4c4781SWenchao Xia         error_free(local_err);
4607b4c4781SWenchao Xia         local_err = NULL;
4617b4c4781SWenchao Xia         ret = bdrv_snapshot_load_tmp(bs, NULL, id_or_name, &local_err);
4627b4c4781SWenchao Xia     }
4637b4c4781SWenchao Xia 
4647b4c4781SWenchao Xia     error_propagate(errp, local_err);
4657b4c4781SWenchao Xia 
4667b4c4781SWenchao Xia     return ret;
4677b4c4781SWenchao Xia }
468e9ff957aSDenis V. Lunev 
469cf3a74c9SDaniel P. Berrangé 
470cf3a74c9SDaniel P. Berrangé static int bdrv_all_get_snapshot_devices(bool has_devices, strList *devices,
471cf3a74c9SDaniel P. Berrangé                                          GList **all_bdrvs,
472cf3a74c9SDaniel P. Berrangé                                          Error **errp)
473cf3a74c9SDaniel P. Berrangé {
474cf3a74c9SDaniel P. Berrangé     g_autoptr(GList) bdrvs = NULL;
475cf3a74c9SDaniel P. Berrangé 
476cf3a74c9SDaniel P. Berrangé     if (has_devices) {
477cf3a74c9SDaniel P. Berrangé         if (!devices) {
478cf3a74c9SDaniel P. Berrangé             error_setg(errp, "At least one device is required for snapshot");
479cf3a74c9SDaniel P. Berrangé             return -1;
480cf3a74c9SDaniel P. Berrangé         }
481cf3a74c9SDaniel P. Berrangé 
482cf3a74c9SDaniel P. Berrangé         while (devices) {
483cf3a74c9SDaniel P. Berrangé             BlockDriverState *bs = bdrv_find_node(devices->value);
484cf3a74c9SDaniel P. Berrangé             if (!bs) {
485cf3a74c9SDaniel P. Berrangé                 error_setg(errp, "No block device node '%s'", devices->value);
486cf3a74c9SDaniel P. Berrangé                 return -1;
487cf3a74c9SDaniel P. Berrangé             }
488cf3a74c9SDaniel P. Berrangé             bdrvs = g_list_append(bdrvs, bs);
489cf3a74c9SDaniel P. Berrangé             devices = devices->next;
490cf3a74c9SDaniel P. Berrangé         }
491cf3a74c9SDaniel P. Berrangé     } else {
492cf3a74c9SDaniel P. Berrangé         BlockDriverState *bs;
493cf3a74c9SDaniel P. Berrangé         BdrvNextIterator it;
494cf3a74c9SDaniel P. Berrangé         for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
495cf3a74c9SDaniel P. Berrangé             bdrvs = g_list_append(bdrvs, bs);
496cf3a74c9SDaniel P. Berrangé         }
497cf3a74c9SDaniel P. Berrangé     }
498cf3a74c9SDaniel P. Berrangé 
499cf3a74c9SDaniel P. Berrangé     *all_bdrvs = g_steal_pointer(&bdrvs);
500cf3a74c9SDaniel P. Berrangé     return 0;
501cf3a74c9SDaniel P. Berrangé }
502cf3a74c9SDaniel P. Berrangé 
503cf3a74c9SDaniel P. Berrangé 
50405f4acedSKevin Wolf static bool bdrv_all_snapshots_includes_bs(BlockDriverState *bs)
50505f4acedSKevin Wolf {
50605f4acedSKevin Wolf     if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
50705f4acedSKevin Wolf         return false;
50805f4acedSKevin Wolf     }
50905f4acedSKevin Wolf 
51005f4acedSKevin Wolf     /* Include all nodes that are either in use by a BlockBackend, or that
51105f4acedSKevin Wolf      * aren't attached to any node, but owned by the monitor. */
51205f4acedSKevin Wolf     return bdrv_has_blk(bs) || QLIST_EMPTY(&bs->parents);
51305f4acedSKevin Wolf }
514e9ff957aSDenis V. Lunev 
515e9ff957aSDenis V. Lunev /* Group operations. All block drivers are involved.
516e9ff957aSDenis V. Lunev  * These functions will properly handle dataplane (take aio_context_acquire
517e9ff957aSDenis V. Lunev  * when appropriate for appropriate block drivers) */
518e9ff957aSDenis V. Lunev 
519cf3a74c9SDaniel P. Berrangé bool bdrv_all_can_snapshot(bool has_devices, strList *devices,
520cf3a74c9SDaniel P. Berrangé                            Error **errp)
521e9ff957aSDenis V. Lunev {
522cf3a74c9SDaniel P. Berrangé     g_autoptr(GList) bdrvs = NULL;
523cf3a74c9SDaniel P. Berrangé     GList *iterbdrvs;
524e9ff957aSDenis V. Lunev 
5256b573efeSEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
5266b573efeSEmanuele Giuseppe Esposito 
527cf3a74c9SDaniel P. Berrangé     if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
528cf3a74c9SDaniel P. Berrangé         return false;
529cf3a74c9SDaniel P. Berrangé     }
530cf3a74c9SDaniel P. Berrangé 
531cf3a74c9SDaniel P. Berrangé     iterbdrvs = bdrvs;
532cf3a74c9SDaniel P. Berrangé     while (iterbdrvs) {
533cf3a74c9SDaniel P. Berrangé         BlockDriverState *bs = iterbdrvs->data;
534e9ff957aSDenis V. Lunev         AioContext *ctx = bdrv_get_aio_context(bs);
535e26f98e2SDaniel P. Berrangé         bool ok = true;
536e9ff957aSDenis V. Lunev 
537e9ff957aSDenis V. Lunev         aio_context_acquire(ctx);
538cf3a74c9SDaniel P. Berrangé         if (devices || bdrv_all_snapshots_includes_bs(bs)) {
539e9ff957aSDenis V. Lunev             ok = bdrv_can_snapshot(bs);
540e9ff957aSDenis V. Lunev         }
541e9ff957aSDenis V. Lunev         aio_context_release(ctx);
54288be7b4bSKevin Wolf         if (!ok) {
543e26f98e2SDaniel P. Berrangé             error_setg(errp, "Device '%s' is writable but does not support "
544e26f98e2SDaniel P. Berrangé                        "snapshots", bdrv_get_device_or_node_name(bs));
545e26f98e2SDaniel P. Berrangé             return false;
54688be7b4bSKevin Wolf         }
547cf3a74c9SDaniel P. Berrangé 
548cf3a74c9SDaniel P. Berrangé         iterbdrvs = iterbdrvs->next;
549e9ff957aSDenis V. Lunev     }
550e9ff957aSDenis V. Lunev 
551e26f98e2SDaniel P. Berrangé     return true;
552e9ff957aSDenis V. Lunev }
5539b00ea37SDenis V. Lunev 
554cf3a74c9SDaniel P. Berrangé int bdrv_all_delete_snapshot(const char *name,
555cf3a74c9SDaniel P. Berrangé                              bool has_devices, strList *devices,
556cf3a74c9SDaniel P. Berrangé                              Error **errp)
5579b00ea37SDenis V. Lunev {
558cf3a74c9SDaniel P. Berrangé     g_autoptr(GList) bdrvs = NULL;
559cf3a74c9SDaniel P. Berrangé     GList *iterbdrvs;
5609b00ea37SDenis V. Lunev 
5616b573efeSEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
5626b573efeSEmanuele Giuseppe Esposito 
563cf3a74c9SDaniel P. Berrangé     if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
564cf3a74c9SDaniel P. Berrangé         return -1;
565cf3a74c9SDaniel P. Berrangé     }
566cf3a74c9SDaniel P. Berrangé 
567cf3a74c9SDaniel P. Berrangé     iterbdrvs = bdrvs;
568cf3a74c9SDaniel P. Berrangé     while (iterbdrvs) {
569cf3a74c9SDaniel P. Berrangé         BlockDriverState *bs = iterbdrvs->data;
5709b00ea37SDenis V. Lunev         AioContext *ctx = bdrv_get_aio_context(bs);
571cf3a74c9SDaniel P. Berrangé         QEMUSnapshotInfo sn1, *snapshot = &sn1;
572e26f98e2SDaniel P. Berrangé         int ret = 0;
5739b00ea37SDenis V. Lunev 
5749b00ea37SDenis V. Lunev         aio_context_acquire(ctx);
575cf3a74c9SDaniel P. Berrangé         if ((devices || bdrv_all_snapshots_includes_bs(bs)) &&
57605f4acedSKevin Wolf             bdrv_snapshot_find(bs, snapshot, name) >= 0)
57705f4acedSKevin Wolf         {
5786ca08045SDaniel Henrique Barboza             ret = bdrv_snapshot_delete(bs, snapshot->id_str,
579e53a578aSVladimir Sementsov-Ogievskiy                                        snapshot->name, errp);
5809b00ea37SDenis V. Lunev         }
5819b00ea37SDenis V. Lunev         aio_context_release(ctx);
58288be7b4bSKevin Wolf         if (ret < 0) {
583e26f98e2SDaniel P. Berrangé             error_prepend(errp, "Could not delete snapshot '%s' on '%s': ",
584e26f98e2SDaniel P. Berrangé                           name, bdrv_get_device_or_node_name(bs));
585e26f98e2SDaniel P. Berrangé             return -1;
58688be7b4bSKevin Wolf         }
587cf3a74c9SDaniel P. Berrangé 
588cf3a74c9SDaniel P. Berrangé         iterbdrvs = iterbdrvs->next;
5899b00ea37SDenis V. Lunev     }
5909b00ea37SDenis V. Lunev 
591e26f98e2SDaniel P. Berrangé     return 0;
5929b00ea37SDenis V. Lunev }
5934c1cdbaaSDenis V. Lunev 
5944c1cdbaaSDenis V. Lunev 
595cf3a74c9SDaniel P. Berrangé int bdrv_all_goto_snapshot(const char *name,
596cf3a74c9SDaniel P. Berrangé                            bool has_devices, strList *devices,
597cf3a74c9SDaniel P. Berrangé                            Error **errp)
5984c1cdbaaSDenis V. Lunev {
599cf3a74c9SDaniel P. Berrangé     g_autoptr(GList) bdrvs = NULL;
600cf3a74c9SDaniel P. Berrangé     GList *iterbdrvs;
6014c1cdbaaSDenis V. Lunev 
6026b573efeSEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
6036b573efeSEmanuele Giuseppe Esposito 
604cf3a74c9SDaniel P. Berrangé     if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
605cf3a74c9SDaniel P. Berrangé         return -1;
606cf3a74c9SDaniel P. Berrangé     }
607cf3a74c9SDaniel P. Berrangé 
608cf3a74c9SDaniel P. Berrangé     iterbdrvs = bdrvs;
609cf3a74c9SDaniel P. Berrangé     while (iterbdrvs) {
610cf3a74c9SDaniel P. Berrangé         BlockDriverState *bs = iterbdrvs->data;
6114c1cdbaaSDenis V. Lunev         AioContext *ctx = bdrv_get_aio_context(bs);
612e26f98e2SDaniel P. Berrangé         int ret = 0;
6134c1cdbaaSDenis V. Lunev 
6144c1cdbaaSDenis V. Lunev         aio_context_acquire(ctx);
615cf3a74c9SDaniel P. Berrangé         if (devices || bdrv_all_snapshots_includes_bs(bs)) {
6162b624fe0SKevin Wolf             ret = bdrv_snapshot_goto(bs, name, errp);
6174c1cdbaaSDenis V. Lunev         }
6184c1cdbaaSDenis V. Lunev         aio_context_release(ctx);
6192b624fe0SKevin Wolf         if (ret < 0) {
620e26f98e2SDaniel P. Berrangé             error_prepend(errp, "Could not load snapshot '%s' on '%s': ",
621e26f98e2SDaniel P. Berrangé                           name, bdrv_get_device_or_node_name(bs));
622e26f98e2SDaniel P. Berrangé             return -1;
62388be7b4bSKevin Wolf         }
624cf3a74c9SDaniel P. Berrangé 
625cf3a74c9SDaniel P. Berrangé         iterbdrvs = iterbdrvs->next;
6264c1cdbaaSDenis V. Lunev     }
6274c1cdbaaSDenis V. Lunev 
628e26f98e2SDaniel P. Berrangé     return 0;
6294c1cdbaaSDenis V. Lunev }
630723ccda1SDenis V. Lunev 
6313d3e9b1fSDaniel P. Berrangé int bdrv_all_has_snapshot(const char *name,
632cf3a74c9SDaniel P. Berrangé                           bool has_devices, strList *devices,
633cf3a74c9SDaniel P. Berrangé                           Error **errp)
634723ccda1SDenis V. Lunev {
635cf3a74c9SDaniel P. Berrangé     g_autoptr(GList) bdrvs = NULL;
636cf3a74c9SDaniel P. Berrangé     GList *iterbdrvs;
637723ccda1SDenis V. Lunev 
6386b573efeSEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
6396b573efeSEmanuele Giuseppe Esposito 
640cf3a74c9SDaniel P. Berrangé     if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
641cf3a74c9SDaniel P. Berrangé         return -1;
642cf3a74c9SDaniel P. Berrangé     }
643cf3a74c9SDaniel P. Berrangé 
644cf3a74c9SDaniel P. Berrangé     iterbdrvs = bdrvs;
645cf3a74c9SDaniel P. Berrangé     while (iterbdrvs) {
646cf3a74c9SDaniel P. Berrangé         BlockDriverState *bs = iterbdrvs->data;
647723ccda1SDenis V. Lunev         AioContext *ctx = bdrv_get_aio_context(bs);
648cf3a74c9SDaniel P. Berrangé         QEMUSnapshotInfo sn;
649e26f98e2SDaniel P. Berrangé         int ret = 0;
650723ccda1SDenis V. Lunev 
651723ccda1SDenis V. Lunev         aio_context_acquire(ctx);
652cf3a74c9SDaniel P. Berrangé         if (devices || bdrv_all_snapshots_includes_bs(bs)) {
653e26f98e2SDaniel P. Berrangé             ret = bdrv_snapshot_find(bs, &sn, name);
654723ccda1SDenis V. Lunev         }
655723ccda1SDenis V. Lunev         aio_context_release(ctx);
656e26f98e2SDaniel P. Berrangé         if (ret < 0) {
6573d3e9b1fSDaniel P. Berrangé             if (ret == -ENOENT) {
6583d3e9b1fSDaniel P. Berrangé                 return 0;
6593d3e9b1fSDaniel P. Berrangé             } else {
6603d3e9b1fSDaniel P. Berrangé                 error_setg_errno(errp, errno,
6613d3e9b1fSDaniel P. Berrangé                                  "Could not check snapshot '%s' on '%s'",
662e26f98e2SDaniel P. Berrangé                                  name, bdrv_get_device_or_node_name(bs));
663e26f98e2SDaniel P. Berrangé                 return -1;
66488be7b4bSKevin Wolf             }
6653d3e9b1fSDaniel P. Berrangé         }
666cf3a74c9SDaniel P. Berrangé 
667cf3a74c9SDaniel P. Berrangé         iterbdrvs = iterbdrvs->next;
668723ccda1SDenis V. Lunev     }
669723ccda1SDenis V. Lunev 
6703d3e9b1fSDaniel P. Berrangé     return 1;
671723ccda1SDenis V. Lunev }
672a9085f9bSDenis V. Lunev 
673a9085f9bSDenis V. Lunev int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn,
674a9085f9bSDenis V. Lunev                              BlockDriverState *vm_state_bs,
675a9085f9bSDenis V. Lunev                              uint64_t vm_state_size,
676cf3a74c9SDaniel P. Berrangé                              bool has_devices, strList *devices,
677e26f98e2SDaniel P. Berrangé                              Error **errp)
678a9085f9bSDenis V. Lunev {
679cf3a74c9SDaniel P. Berrangé     g_autoptr(GList) bdrvs = NULL;
680cf3a74c9SDaniel P. Berrangé     GList *iterbdrvs;
6816b573efeSEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
682a9085f9bSDenis V. Lunev 
683cf3a74c9SDaniel P. Berrangé     if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
684cf3a74c9SDaniel P. Berrangé         return -1;
685cf3a74c9SDaniel P. Berrangé     }
686cf3a74c9SDaniel P. Berrangé 
687cf3a74c9SDaniel P. Berrangé     iterbdrvs = bdrvs;
688cf3a74c9SDaniel P. Berrangé     while (iterbdrvs) {
689cf3a74c9SDaniel P. Berrangé         BlockDriverState *bs = iterbdrvs->data;
690a9085f9bSDenis V. Lunev         AioContext *ctx = bdrv_get_aio_context(bs);
691e26f98e2SDaniel P. Berrangé         int ret = 0;
692a9085f9bSDenis V. Lunev 
693a9085f9bSDenis V. Lunev         aio_context_acquire(ctx);
694a9085f9bSDenis V. Lunev         if (bs == vm_state_bs) {
695a9085f9bSDenis V. Lunev             sn->vm_state_size = vm_state_size;
696e26f98e2SDaniel P. Berrangé             ret = bdrv_snapshot_create(bs, sn);
697cf3a74c9SDaniel P. Berrangé         } else if (devices || bdrv_all_snapshots_includes_bs(bs)) {
698a9085f9bSDenis V. Lunev             sn->vm_state_size = 0;
699e26f98e2SDaniel P. Berrangé             ret = bdrv_snapshot_create(bs, sn);
700a9085f9bSDenis V. Lunev         }
701a9085f9bSDenis V. Lunev         aio_context_release(ctx);
702e26f98e2SDaniel P. Berrangé         if (ret < 0) {
703e26f98e2SDaniel P. Berrangé             error_setg(errp, "Could not create snapshot '%s' on '%s'",
704e26f98e2SDaniel P. Berrangé                        sn->name, bdrv_get_device_or_node_name(bs));
705e26f98e2SDaniel P. Berrangé             return -1;
70688be7b4bSKevin Wolf         }
707cf3a74c9SDaniel P. Berrangé 
708cf3a74c9SDaniel P. Berrangé         iterbdrvs = iterbdrvs->next;
709a9085f9bSDenis V. Lunev     }
710a9085f9bSDenis V. Lunev 
711e26f98e2SDaniel P. Berrangé     return 0;
712a9085f9bSDenis V. Lunev }
7137cb14481SDenis V. Lunev 
714c22d644cSDaniel P. Berrangé 
715c22d644cSDaniel P. Berrangé BlockDriverState *bdrv_all_find_vmstate_bs(const char *vmstate_bs,
716c22d644cSDaniel P. Berrangé                                            bool has_devices, strList *devices,
717cf3a74c9SDaniel P. Berrangé                                            Error **errp)
7187cb14481SDenis V. Lunev {
719cf3a74c9SDaniel P. Berrangé     g_autoptr(GList) bdrvs = NULL;
720cf3a74c9SDaniel P. Berrangé     GList *iterbdrvs;
7217cb14481SDenis V. Lunev 
7226b573efeSEmanuele Giuseppe Esposito     GLOBAL_STATE_CODE();
7236b573efeSEmanuele Giuseppe Esposito 
724cf3a74c9SDaniel P. Berrangé     if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
725cf3a74c9SDaniel P. Berrangé         return NULL;
726cf3a74c9SDaniel P. Berrangé     }
727cf3a74c9SDaniel P. Berrangé 
728cf3a74c9SDaniel P. Berrangé     iterbdrvs = bdrvs;
729cf3a74c9SDaniel P. Berrangé     while (iterbdrvs) {
730cf3a74c9SDaniel P. Berrangé         BlockDriverState *bs = iterbdrvs->data;
7317cb14481SDenis V. Lunev         AioContext *ctx = bdrv_get_aio_context(bs);
732cf3a74c9SDaniel P. Berrangé         bool found = false;
7337cb14481SDenis V. Lunev 
7347cb14481SDenis V. Lunev         aio_context_acquire(ctx);
735cf3a74c9SDaniel P. Berrangé         found = (devices || bdrv_all_snapshots_includes_bs(bs)) &&
736cf3a74c9SDaniel P. Berrangé             bdrv_can_snapshot(bs);
7377cb14481SDenis V. Lunev         aio_context_release(ctx);
73888be7b4bSKevin Wolf 
739c22d644cSDaniel P. Berrangé         if (vmstate_bs) {
740c22d644cSDaniel P. Berrangé             if (g_str_equal(vmstate_bs,
741c22d644cSDaniel P. Berrangé                             bdrv_get_node_name(bs))) {
74288be7b4bSKevin Wolf                 if (found) {
7437cb14481SDenis V. Lunev                     return bs;
744c22d644cSDaniel P. Berrangé                 } else {
745c22d644cSDaniel P. Berrangé                     error_setg(errp,
746c22d644cSDaniel P. Berrangé                                "vmstate block device '%s' does not support snapshots",
747c22d644cSDaniel P. Berrangé                                vmstate_bs);
748c22d644cSDaniel P. Berrangé                     return NULL;
749c22d644cSDaniel P. Berrangé                 }
750c22d644cSDaniel P. Berrangé             }
751c22d644cSDaniel P. Berrangé         } else if (found) {
752c22d644cSDaniel P. Berrangé             return bs;
7537cb14481SDenis V. Lunev         }
754cf3a74c9SDaniel P. Berrangé 
755cf3a74c9SDaniel P. Berrangé         iterbdrvs = iterbdrvs->next;
756cf3a74c9SDaniel P. Berrangé     }
757cf3a74c9SDaniel P. Berrangé 
758c22d644cSDaniel P. Berrangé     if (vmstate_bs) {
759c22d644cSDaniel P. Berrangé         error_setg(errp,
760c22d644cSDaniel P. Berrangé                    "vmstate block device '%s' does not exist", vmstate_bs);
761c22d644cSDaniel P. Berrangé     } else {
762c22d644cSDaniel P. Berrangé         error_setg(errp,
763c22d644cSDaniel P. Berrangé                    "no block device can store vmstate for snapshot");
764c22d644cSDaniel P. Berrangé     }
765cf3a74c9SDaniel P. Berrangé     return NULL;
766cf3a74c9SDaniel P. Berrangé }
767