xref: /qemu/block/snapshot.c (revision a95921f1)
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