1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include "block/snapshot.h"
26#include "block/block_int.h"
27
28QemuOptsList internal_snapshot_opts = {
29 .name = "snapshot",
30 .head = QTAILQ_HEAD_INITIALIZER(internal_snapshot_opts.head),
31 .desc = {
32 {
33 .name = SNAPSHOT_OPT_ID,
34 .type = QEMU_OPT_STRING,
35 .help = "snapshot id"
36 },{
37 .name = SNAPSHOT_OPT_NAME,
38 .type = QEMU_OPT_STRING,
39 .help = "snapshot name"
40 },{
41
42 }
43 },
44};
45
46int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
47 const char *name)
48{
49 QEMUSnapshotInfo *sn_tab, *sn;
50 int nb_sns, i, ret;
51
52 ret = -ENOENT;
53 nb_sns = bdrv_snapshot_list(bs, &sn_tab);
54 if (nb_sns < 0) {
55 return ret;
56 }
57 for (i = 0; i < nb_sns; i++) {
58 sn = &sn_tab[i];
59 if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {
60 *sn_info = *sn;
61 ret = 0;
62 break;
63 }
64 }
65 g_free(sn_tab);
66 return ret;
67}
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89bool bdrv_snapshot_find_by_id_and_name(BlockDriverState *bs,
90 const char *id,
91 const char *name,
92 QEMUSnapshotInfo *sn_info,
93 Error **errp)
94{
95 QEMUSnapshotInfo *sn_tab, *sn;
96 int nb_sns, i;
97 bool ret = false;
98
99 assert(id || name);
100
101 nb_sns = bdrv_snapshot_list(bs, &sn_tab);
102 if (nb_sns < 0) {
103 error_setg_errno(errp, -nb_sns, "Failed to get a snapshot list");
104 return false;
105 } else if (nb_sns == 0) {
106 return false;
107 }
108
109 if (id && name) {
110 for (i = 0; i < nb_sns; i++) {
111 sn = &sn_tab[i];
112 if (!strcmp(sn->id_str, id) && !strcmp(sn->name, name)) {
113 *sn_info = *sn;
114 ret = true;
115 break;
116 }
117 }
118 } else if (id) {
119 for (i = 0; i < nb_sns; i++) {
120 sn = &sn_tab[i];
121 if (!strcmp(sn->id_str, id)) {
122 *sn_info = *sn;
123 ret = true;
124 break;
125 }
126 }
127 } else if (name) {
128 for (i = 0; i < nb_sns; i++) {
129 sn = &sn_tab[i];
130 if (!strcmp(sn->name, name)) {
131 *sn_info = *sn;
132 ret = true;
133 break;
134 }
135 }
136 }
137
138 g_free(sn_tab);
139 return ret;
140}
141
142int bdrv_can_snapshot(BlockDriverState *bs)
143{
144 BlockDriver *drv = bs->drv;
145 if (!drv || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
146 return 0;
147 }
148
149 if (!drv->bdrv_snapshot_create) {
150 if (bs->file != NULL) {
151 return bdrv_can_snapshot(bs->file);
152 }
153 return 0;
154 }
155
156 return 1;
157}
158
159int bdrv_snapshot_create(BlockDriverState *bs,
160 QEMUSnapshotInfo *sn_info)
161{
162 BlockDriver *drv = bs->drv;
163 if (!drv) {
164 return -ENOMEDIUM;
165 }
166 if (drv->bdrv_snapshot_create) {
167 return drv->bdrv_snapshot_create(bs, sn_info);
168 }
169 if (bs->file) {
170 return bdrv_snapshot_create(bs->file, sn_info);
171 }
172 return -ENOTSUP;
173}
174
175int bdrv_snapshot_goto(BlockDriverState *bs,
176 const char *snapshot_id)
177{
178 BlockDriver *drv = bs->drv;
179 int ret, open_ret;
180
181 if (!drv) {
182 return -ENOMEDIUM;
183 }
184 if (drv->bdrv_snapshot_goto) {
185 return drv->bdrv_snapshot_goto(bs, snapshot_id);
186 }
187
188 if (bs->file) {
189 drv->bdrv_close(bs);
190 ret = bdrv_snapshot_goto(bs->file, snapshot_id);
191 open_ret = drv->bdrv_open(bs, NULL, bs->open_flags, NULL);
192 if (open_ret < 0) {
193 bdrv_unref(bs->file);
194 bs->drv = NULL;
195 return open_ret;
196 }
197 return ret;
198 }
199
200 return -ENOTSUP;
201}
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225int bdrv_snapshot_delete(BlockDriverState *bs,
226 const char *snapshot_id,
227 const char *name,
228 Error **errp)
229{
230 BlockDriver *drv = bs->drv;
231 if (!drv) {
232 error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs));
233 return -ENOMEDIUM;
234 }
235 if (!snapshot_id && !name) {
236 error_setg(errp, "snapshot_id and name are both NULL");
237 return -EINVAL;
238 }
239
240
241 bdrv_drain_all();
242
243 if (drv->bdrv_snapshot_delete) {
244 return drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp);
245 }
246 if (bs->file) {
247 return bdrv_snapshot_delete(bs->file, snapshot_id, name, errp);
248 }
249 error_set(errp, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
250 drv->format_name, bdrv_get_device_name(bs),
251 "internal snapshot deletion");
252 return -ENOTSUP;
253}
254
255void bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs,
256 const char *id_or_name,
257 Error **errp)
258{
259 int ret;
260 Error *local_err = NULL;
261
262 ret = bdrv_snapshot_delete(bs, id_or_name, NULL, &local_err);
263 if (ret == -ENOENT || ret == -EINVAL) {
264 error_free(local_err);
265 local_err = NULL;
266 ret = bdrv_snapshot_delete(bs, NULL, id_or_name, &local_err);
267 }
268
269 if (ret < 0) {
270 error_propagate(errp, local_err);
271 }
272}
273
274int bdrv_snapshot_list(BlockDriverState *bs,
275 QEMUSnapshotInfo **psn_info)
276{
277 BlockDriver *drv = bs->drv;
278 if (!drv) {
279 return -ENOMEDIUM;
280 }
281 if (drv->bdrv_snapshot_list) {
282 return drv->bdrv_snapshot_list(bs, psn_info);
283 }
284 if (bs->file) {
285 return bdrv_snapshot_list(bs->file, psn_info);
286 }
287 return -ENOTSUP;
288}
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310int bdrv_snapshot_load_tmp(BlockDriverState *bs,
311 const char *snapshot_id,
312 const char *name,
313 Error **errp)
314{
315 BlockDriver *drv = bs->drv;
316
317 if (!drv) {
318 error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs));
319 return -ENOMEDIUM;
320 }
321 if (!snapshot_id && !name) {
322 error_setg(errp, "snapshot_id and name are both NULL");
323 return -EINVAL;
324 }
325 if (!bs->read_only) {
326 error_setg(errp, "Device is not readonly");
327 return -EINVAL;
328 }
329 if (drv->bdrv_snapshot_load_tmp) {
330 return drv->bdrv_snapshot_load_tmp(bs, snapshot_id, name, errp);
331 }
332 error_set(errp, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
333 drv->format_name, bdrv_get_device_name(bs),
334 "temporarily load internal snapshot");
335 return -ENOTSUP;
336}
337
338int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,
339 const char *id_or_name,
340 Error **errp)
341{
342 int ret;
343 Error *local_err = NULL;
344
345 ret = bdrv_snapshot_load_tmp(bs, id_or_name, NULL, &local_err);
346 if (ret == -ENOENT || ret == -EINVAL) {
347 error_free(local_err);
348 local_err = NULL;
349 ret = bdrv_snapshot_load_tmp(bs, NULL, id_or_name, &local_err);
350 }
351
352 if (local_err) {
353 error_propagate(errp, local_err);
354 }
355
356 return ret;
357}
358