1 /*
2 * qemu_block.c: helper functions for QEMU block subsystem
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see
16 * <http://www.gnu.org/licenses/>.
17 */
18
19 #include <config.h>
20
21 #include "qemu_block.h"
22 #include "qemu_command.h"
23 #include "qemu_domain.h"
24 #include "qemu_alias.h"
25 #include "qemu_security.h"
26
27 #include "storage_source.h"
28 #include "viralloc.h"
29 #include "virstoragefile.h"
30 #include "virstring.h"
31 #include "virlog.h"
32
33 #define VIR_FROM_THIS VIR_FROM_QEMU
34
35 VIR_LOG_INIT("qemu.qemu_block");
36
37 /* qemu declares the buffer for node names as a 32 byte array */
38 static const size_t qemuBlockNodeNameBufSize = 32;
39
40 static int
qemuBlockNodeNameValidate(const char * nn)41 qemuBlockNodeNameValidate(const char *nn)
42 {
43 if (!nn)
44 return 0;
45
46 if (strlen(nn) >= qemuBlockNodeNameBufSize) {
47 virReportError(VIR_ERR_INTERNAL_ERROR,
48 _("node-name '%s' too long for qemu"), nn);
49 return -1;
50 }
51
52 return 0;
53 }
54
55
56 static int
qemuBlockNamedNodesArrayToHash(size_t pos G_GNUC_UNUSED,virJSONValue * item,void * opaque)57 qemuBlockNamedNodesArrayToHash(size_t pos G_GNUC_UNUSED,
58 virJSONValue *item,
59 void *opaque)
60 {
61 GHashTable *table = opaque;
62 const char *name;
63
64 if (!(name = virJSONValueObjectGetString(item, "node-name")))
65 return 1;
66
67 if (virHashAddEntry(table, name, item) < 0)
68 return -1;
69
70 return 0;
71 }
72
73
74 static void
qemuBlockNodeNameBackingChainDataFree(qemuBlockNodeNameBackingChainData * data)75 qemuBlockNodeNameBackingChainDataFree(qemuBlockNodeNameBackingChainData *data)
76 {
77 if (!data)
78 return;
79
80 g_free(data->nodeformat);
81 g_free(data->nodestorage);
82
83 g_free(data->qemufilename);
84
85 g_free(data->drvformat);
86 g_free(data->drvstorage);
87
88 qemuBlockNodeNameBackingChainDataFree(data->backing);
89
90 g_free(data);
91 }
92
93 G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuBlockNodeNameBackingChainData,
94 qemuBlockNodeNameBackingChainDataFree);
95
96
97 static void
qemuBlockNodeNameBackingChainDataHashEntryFree(void * opaque)98 qemuBlockNodeNameBackingChainDataHashEntryFree(void *opaque)
99 {
100 qemuBlockNodeNameBackingChainDataFree(opaque);
101 }
102
103
104 /* list of driver names of layers that qemu automatically adds into the
105 * backing chain */
106 static const char *qemuBlockDriversBlockjob[] = {
107 "mirror_top", "commit_top", NULL };
108
109 static bool
qemuBlockDriverMatch(const char * drvname,const char ** drivers)110 qemuBlockDriverMatch(const char *drvname,
111 const char **drivers)
112 {
113 while (*drivers) {
114 if (STREQ(drvname, *drivers))
115 return true;
116
117 drivers++;
118 }
119
120 return false;
121 }
122
123
124 struct qemuBlockNodeNameGetBackingChainData {
125 GHashTable *nodenamestable;
126 GHashTable *disks;
127 };
128
129
130 static int
qemuBlockNodeNameGetBackingChainBacking(virJSONValue * next,GHashTable * nodenamestable,qemuBlockNodeNameBackingChainData ** nodenamedata)131 qemuBlockNodeNameGetBackingChainBacking(virJSONValue *next,
132 GHashTable *nodenamestable,
133 qemuBlockNodeNameBackingChainData **nodenamedata)
134 {
135 g_autoptr(qemuBlockNodeNameBackingChainData) data = NULL;
136 qemuBlockNodeNameBackingChainData *backingdata = NULL;
137 virJSONValue *backing = virJSONValueObjectGetObject(next, "backing");
138 virJSONValue *parent = virJSONValueObjectGetObject(next, "parent");
139 virJSONValue *parentnodedata;
140 virJSONValue *nodedata;
141 const char *nodename = virJSONValueObjectGetString(next, "node-name");
142 const char *drvname = NULL;
143 const char *drvparent = NULL;
144 const char *parentnodename = NULL;
145 const char *filename = NULL;
146
147 if (!nodename)
148 return 0;
149
150 if ((nodedata = virHashLookup(nodenamestable, nodename)) &&
151 (drvname = virJSONValueObjectGetString(nodedata, "drv"))) {
152
153 /* qemu 2.9 reports layers in the backing chain which don't correspond
154 * to files. skip them */
155 if (qemuBlockDriverMatch(drvname, qemuBlockDriversBlockjob)) {
156 if (backing) {
157 return qemuBlockNodeNameGetBackingChainBacking(backing,
158 nodenamestable,
159 nodenamedata);
160 } else {
161 return 0;
162 }
163 }
164 }
165
166 if (parent &&
167 (parentnodename = virJSONValueObjectGetString(parent, "node-name"))) {
168 if ((parentnodedata = virHashLookup(nodenamestable, parentnodename))) {
169 filename = virJSONValueObjectGetString(parentnodedata, "file");
170 drvparent = virJSONValueObjectGetString(parentnodedata, "drv");
171 }
172 }
173
174 data = g_new0(qemuBlockNodeNameBackingChainData, 1);
175
176 data->nodeformat = g_strdup(nodename);
177 data->nodestorage = g_strdup(parentnodename);
178 data->qemufilename = g_strdup(filename);
179 data->drvformat = g_strdup(drvname);
180 data->drvstorage = g_strdup(drvparent);
181
182 if (backing &&
183 qemuBlockNodeNameGetBackingChainBacking(backing, nodenamestable,
184 &backingdata) < 0)
185 return -1;
186
187 data->backing = g_steal_pointer(&backingdata);
188 *nodenamedata = g_steal_pointer(&data);
189
190 return 0;
191 }
192
193
194 static int
qemuBlockNodeNameGetBackingChainDisk(size_t pos G_GNUC_UNUSED,virJSONValue * item,void * opaque)195 qemuBlockNodeNameGetBackingChainDisk(size_t pos G_GNUC_UNUSED,
196 virJSONValue *item,
197 void *opaque)
198 {
199 struct qemuBlockNodeNameGetBackingChainData *data = opaque;
200 const char *device = virJSONValueObjectGetString(item, "device");
201 g_autoptr(qemuBlockNodeNameBackingChainData) devicedata = NULL;
202
203 if (qemuBlockNodeNameGetBackingChainBacking(item, data->nodenamestable,
204 &devicedata) < 0)
205 return -1;
206
207 if (devicedata &&
208 virHashAddEntry(data->disks, device, devicedata) < 0)
209 return -1;
210
211 devicedata = NULL;
212 return 1; /* we don't really want to steal @item */
213 }
214
215
216 /**
217 * qemuBlockNodeNameGetBackingChain:
218 * @namednodes: JSON array of data returned from 'query-named-block-nodes'
219 * @blockstats: JSON array of data returned from 'query-blockstats'
220 *
221 * Tries to reconstruct the backing chain from @json to allow detection of
222 * node names that were auto-assigned by qemu. This is a best-effort operation
223 * and may not be successful. The returned hash table contains the entries as
224 * qemuBlockNodeNameBackingChainData *accessible by the node name. The fields
225 * then can be used to recover the full backing chain.
226 *
227 * Returns a hash table on success and NULL on failure.
228 */
229 GHashTable *
qemuBlockNodeNameGetBackingChain(virJSONValue * namednodes,virJSONValue * blockstats)230 qemuBlockNodeNameGetBackingChain(virJSONValue *namednodes,
231 virJSONValue *blockstats)
232 {
233 g_autoptr(GHashTable) namednodestable = virHashNew(virJSONValueHashFree);
234 g_autoptr(GHashTable) disks = virHashNew(qemuBlockNodeNameBackingChainDataHashEntryFree);
235 struct qemuBlockNodeNameGetBackingChainData data = { .nodenamestable = namednodestable,
236 .disks = disks };
237
238 if (virJSONValueArrayForeachSteal(namednodes,
239 qemuBlockNamedNodesArrayToHash,
240 namednodestable) < 0)
241 return NULL;
242
243 if (virJSONValueArrayForeachSteal(blockstats,
244 qemuBlockNodeNameGetBackingChainDisk,
245 &data) < 0)
246 return NULL;
247
248 return g_steal_pointer(&disks);
249 }
250
251
252 static void
qemuBlockDiskClearDetectedNodes(virDomainDiskDef * disk)253 qemuBlockDiskClearDetectedNodes(virDomainDiskDef *disk)
254 {
255 virStorageSource *next = disk->src;
256
257 while (virStorageSourceIsBacking(next)) {
258 VIR_FREE(next->nodeformat);
259 VIR_FREE(next->nodestorage);
260
261 next = next->backingStore;
262 }
263 }
264
265
266 static int
qemuBlockDiskDetectNodes(virDomainDiskDef * disk,GHashTable * disktable)267 qemuBlockDiskDetectNodes(virDomainDiskDef *disk,
268 GHashTable *disktable)
269 {
270 qemuBlockNodeNameBackingChainData *entry = NULL;
271 virStorageSource *src = disk->src;
272 g_autofree char *alias = NULL;
273
274 /* don't attempt the detection if the top level already has node names */
275 if (src->nodeformat || src->nodestorage)
276 return 0;
277
278 if (!(alias = qemuAliasDiskDriveFromDisk(disk)))
279 return -1;
280
281 if (!(entry = virHashLookup(disktable, alias)))
282 return 0;
283
284 while (virStorageSourceIsBacking(src) && entry) {
285 if (src->nodeformat || src->nodestorage) {
286 if (STRNEQ_NULLABLE(src->nodeformat, entry->nodeformat) ||
287 STRNEQ_NULLABLE(src->nodestorage, entry->nodestorage))
288 goto error;
289
290 break;
291 } else {
292 src->nodeformat = g_strdup(entry->nodeformat);
293 src->nodestorage = g_strdup(entry->nodestorage);
294 }
295
296 entry = entry->backing;
297 src = src->backingStore;
298 }
299
300 return 0;
301
302 error:
303 qemuBlockDiskClearDetectedNodes(disk);
304 return -1;
305 }
306
307
308 int
qemuBlockNodeNamesDetect(virQEMUDriver * driver,virDomainObj * vm,qemuDomainAsyncJob asyncJob)309 qemuBlockNodeNamesDetect(virQEMUDriver *driver,
310 virDomainObj *vm,
311 qemuDomainAsyncJob asyncJob)
312 {
313 qemuDomainObjPrivate *priv = vm->privateData;
314 g_autoptr(GHashTable) disktable = NULL;
315 g_autoptr(virJSONValue) data = NULL;
316 g_autoptr(virJSONValue) blockstats = NULL;
317 virDomainDiskDef *disk;
318 size_t i;
319
320 if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_QUERY_NAMED_BLOCK_NODES))
321 return 0;
322
323 if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
324 return -1;
325
326 data = qemuMonitorQueryNamedBlockNodes(qemuDomainGetMonitor(vm));
327 blockstats = qemuMonitorQueryBlockstats(qemuDomainGetMonitor(vm));
328
329 if (qemuDomainObjExitMonitor(driver, vm) < 0 || !data || !blockstats)
330 return -1;
331
332 if (!(disktable = qemuBlockNodeNameGetBackingChain(data, blockstats)))
333 return -1;
334
335 for (i = 0; i < vm->def->ndisks; i++) {
336 disk = vm->def->disks[i];
337
338 if (qemuBlockDiskDetectNodes(disk, disktable) < 0)
339 return -1;
340 }
341
342 return 0;
343 }
344
345
346 /**
347 * qemuBlockGetNodeData:
348 * @data: JSON object returned from query-named-block-nodes
349 *
350 * Returns a hash table organized by the node name of the JSON value objects of
351 * data for given qemu block nodes.
352 *
353 * Returns a filled GHashTable *on success NULL on error.
354 */
355 GHashTable *
qemuBlockGetNodeData(virJSONValue * data)356 qemuBlockGetNodeData(virJSONValue *data)
357 {
358 g_autoptr(GHashTable) nodedata = virHashNew(virJSONValueHashFree);
359
360 if (virJSONValueArrayForeachSteal(data,
361 qemuBlockNamedNodesArrayToHash, nodedata) < 0)
362 return NULL;
363
364 return g_steal_pointer(&nodedata);
365 }
366
367
368 /**
369 * qemuBlockStorageSourceSupportsConcurrentAccess:
370 * @src: disk storage source
371 *
372 * Returns true if the given storage format supports concurrent access from two
373 * separate processes.
374 */
375 bool
qemuBlockStorageSourceSupportsConcurrentAccess(virStorageSource * src)376 qemuBlockStorageSourceSupportsConcurrentAccess(virStorageSource *src)
377 {
378 /* no need to check in backing chain since only RAW storage supports this */
379 return src->format == VIR_STORAGE_FILE_RAW;
380 }
381
382
383 /**
384 * qemuBlockStorageSourceGetURI:
385 * @src: disk storage source
386 *
387 * Formats a URI from a virStorageSource.
388 */
389 virURI *
qemuBlockStorageSourceGetURI(virStorageSource * src)390 qemuBlockStorageSourceGetURI(virStorageSource *src)
391 {
392 g_autoptr(virURI) uri = NULL;
393
394 if (src->nhosts != 1) {
395 virReportError(VIR_ERR_INTERNAL_ERROR,
396 _("protocol '%s' accepts only one host"),
397 virStorageNetProtocolTypeToString(src->protocol));
398 return NULL;
399 }
400
401 uri = g_new0(virURI, 1);
402
403 if (src->hosts->transport == VIR_STORAGE_NET_HOST_TRANS_TCP) {
404 uri->port = src->hosts->port;
405
406 uri->scheme = g_strdup(virStorageNetProtocolTypeToString(src->protocol));
407 } else {
408 uri->scheme = g_strdup_printf("%s+%s",
409 virStorageNetProtocolTypeToString(src->protocol),
410 virStorageNetHostTransportTypeToString(src->hosts->transport));
411 }
412
413 if (src->path) {
414 if (src->volume) {
415 uri->path = g_strdup_printf("/%s/%s", src->volume, src->path);
416 } else {
417 uri->path = g_strdup_printf("%s%s",
418 g_path_is_absolute(src->path) ? "" : "/",
419 src->path);
420 }
421 }
422
423 uri->query = g_strdup(src->query);
424
425 uri->server = g_strdup(src->hosts->name);
426
427 return g_steal_pointer(&uri);
428 }
429
430
431 /**
432 * qemuBlockStorageSourceBuildJSONSocketAddress
433 * @host: the virStorageNetHostDef * definition to build
434 * @legacy: use old field names/values
435 *
436 * Formats @hosts into a json object conforming to the 'SocketAddress' type
437 * in qemu.
438 *
439 * For compatibility with old approach used in the gluster driver of old qemus
440 * use the old spelling for TCP transport and, the path field of the unix socket.
441 *
442 * Returns a virJSONValue * for a single server.
443 */
444 static virJSONValue *
qemuBlockStorageSourceBuildJSONSocketAddress(virStorageNetHostDef * host,bool legacy)445 qemuBlockStorageSourceBuildJSONSocketAddress(virStorageNetHostDef *host,
446 bool legacy)
447 {
448 g_autoptr(virJSONValue) server = NULL;
449 const char *transport;
450 const char *field;
451 g_autofree char *port = NULL;
452
453 switch ((virStorageNetHostTransport) host->transport) {
454 case VIR_STORAGE_NET_HOST_TRANS_TCP:
455 if (legacy)
456 transport = "tcp";
457 else
458 transport = "inet";
459
460 port = g_strdup_printf("%u", host->port);
461
462 if (virJSONValueObjectAdd(&server,
463 "s:type", transport,
464 "s:host", host->name,
465 "s:port", port,
466 NULL) < 0)
467 return NULL;
468 break;
469
470 case VIR_STORAGE_NET_HOST_TRANS_UNIX:
471 if (legacy)
472 field = "s:socket";
473 else
474 field = "s:path";
475
476 if (virJSONValueObjectAdd(&server,
477 "s:type", "unix",
478 field, host->socket,
479 NULL) < 0)
480 return NULL;
481 break;
482
483 case VIR_STORAGE_NET_HOST_TRANS_RDMA:
484 case VIR_STORAGE_NET_HOST_TRANS_LAST:
485 virReportError(VIR_ERR_INTERNAL_ERROR,
486 _("transport protocol '%s' is not yet supported"),
487 virStorageNetHostTransportTypeToString(host->transport));
488 return NULL;
489 }
490
491 return g_steal_pointer(&server);
492 }
493
494
495 /**
496 * qemuBlockStorageSourceBuildHostsJSONSocketAddress:
497 * @src: disk storage source
498 * @legacy: use 'tcp' instead of 'inet' for compatibility reasons
499 *
500 * Formats src->hosts into a json object conforming to the 'SocketAddress' type
501 * in qemu.
502 */
503 static virJSONValue *
qemuBlockStorageSourceBuildHostsJSONSocketAddress(virStorageSource * src,bool legacy)504 qemuBlockStorageSourceBuildHostsJSONSocketAddress(virStorageSource *src,
505 bool legacy)
506 {
507 g_autoptr(virJSONValue) servers = NULL;
508 g_autoptr(virJSONValue) server = NULL;
509 virStorageNetHostDef *host;
510 size_t i;
511
512 servers = virJSONValueNewArray();
513
514 for (i = 0; i < src->nhosts; i++) {
515 host = src->hosts + i;
516
517 if (!(server = qemuBlockStorageSourceBuildJSONSocketAddress(host, legacy)))
518 return NULL;
519
520 if (virJSONValueArrayAppend(servers, &server) < 0)
521 return NULL;
522 }
523
524 return g_steal_pointer(&servers);
525 }
526
527
528 /**
529 * qemuBlockStorageSourceBuildJSONInetSocketAddress
530 * @host: the virStorageNetHostDef * definition to build
531 *
532 * Formats @hosts into a json object conforming to the 'InetSocketAddress' type
533 * in qemu.
534 *
535 * Returns a virJSONValue *for a single server.
536 */
537 static virJSONValue *
qemuBlockStorageSourceBuildJSONInetSocketAddress(virStorageNetHostDef * host)538 qemuBlockStorageSourceBuildJSONInetSocketAddress(virStorageNetHostDef *host)
539 {
540 virJSONValue *ret = NULL;
541 g_autofree char *port = NULL;
542
543 if (host->transport != VIR_STORAGE_NET_HOST_TRANS_TCP) {
544 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
545 _("only TCP protocol can be converted to InetSocketAddress"));
546 return NULL;
547 }
548
549 port = g_strdup_printf("%u", host->port);
550
551 ignore_value(virJSONValueObjectAdd(&ret,
552 "s:host", host->name,
553 "s:port", port,
554 NULL));
555
556 return ret;
557 }
558
559
560 /**
561 * qemuBlockStorageSourceBuildJSONNFSServer(virStorageNetHostDef *host)
562 * @host: the virStorageNetHostDef * definition to build
563 *
564 * Formats @hosts into a json object conforming to the 'NFSServer' type
565 * in qemu.
566 *
567 * Returns a virJSONValue *for a single server.
568 */
569 static virJSONValue *
qemuBlockStorageSourceBuildJSONNFSServer(virStorageNetHostDef * host)570 qemuBlockStorageSourceBuildJSONNFSServer(virStorageNetHostDef *host)
571 {
572 virJSONValue *ret = NULL;
573
574 ignore_value(virJSONValueObjectAdd(&ret,
575 "s:host", host->name,
576 "s:type", "inet",
577 NULL));
578
579 return ret;
580 }
581
582
583 /**
584 * qemuBlockStorageSourceBuildHostsJSONInetSocketAddress:
585 * @src: disk storage source
586 *
587 * Formats src->hosts into a json object conforming to the 'InetSocketAddress'
588 * type in qemu.
589 */
590 static virJSONValue *
qemuBlockStorageSourceBuildHostsJSONInetSocketAddress(virStorageSource * src)591 qemuBlockStorageSourceBuildHostsJSONInetSocketAddress(virStorageSource *src)
592 {
593 g_autoptr(virJSONValue) servers = NULL;
594 g_autoptr(virJSONValue) server = NULL;
595 virStorageNetHostDef *host;
596 size_t i;
597
598 servers = virJSONValueNewArray();
599
600 for (i = 0; i < src->nhosts; i++) {
601 host = src->hosts + i;
602
603 if (!(server = qemuBlockStorageSourceBuildJSONInetSocketAddress(host)))
604 return NULL;
605
606 if (virJSONValueArrayAppend(servers, &server) < 0)
607 return NULL;
608 }
609
610 return g_steal_pointer(&servers);
611 }
612
613
614 static virJSONValue *
qemuBlockStorageSourceGetGlusterProps(virStorageSource * src,bool legacy,bool onlytarget)615 qemuBlockStorageSourceGetGlusterProps(virStorageSource *src,
616 bool legacy,
617 bool onlytarget)
618 {
619 g_autoptr(virJSONValue) servers = NULL;
620 g_autoptr(virJSONValue) props = NULL;
621
622 if (!(servers = qemuBlockStorageSourceBuildHostsJSONSocketAddress(src, legacy)))
623 return NULL;
624
625 /* { driver:"gluster",
626 * volume:"testvol",
627 * path:"/a.img",
628 * server :[{type:"tcp", host:"1.2.3.4", port:24007},
629 * {type:"unix", socket:"/tmp/glusterd.socket"}, ...]}
630 */
631 if (virJSONValueObjectAdd(&props,
632 "s:volume", src->volume,
633 "s:path", src->path,
634 "a:server", &servers, NULL) < 0)
635 return NULL;
636
637 if (!onlytarget &&
638 src->debug &&
639 virJSONValueObjectAdd(&props, "u:debug", src->debugLevel, NULL) < 0)
640 return NULL;
641
642 return g_steal_pointer(&props);
643 }
644
645
646 static virJSONValue *
qemuBlockStorageSourceGetVxHSProps(virStorageSource * src,bool onlytarget)647 qemuBlockStorageSourceGetVxHSProps(virStorageSource *src,
648 bool onlytarget)
649 {
650 g_autoptr(virJSONValue) server = NULL;
651 const char *tlsAlias = src->tlsAlias;
652 virJSONValue *ret = NULL;
653
654 if (src->nhosts != 1) {
655 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
656 _("VxHS protocol accepts only one host"));
657 return NULL;
658 }
659
660 if (!(server = qemuBlockStorageSourceBuildJSONInetSocketAddress(&src->hosts[0])))
661 return NULL;
662
663 if (onlytarget)
664 tlsAlias = NULL;
665
666 /* VxHS disk specification example:
667 * { driver:"vxhs",
668 * tls-creds:"objvirtio-disk0_tls0",
669 * vdisk-id:"eb90327c-8302-4725-4e85ed4dc251",
670 * server:{type:"tcp", host:"1.2.3.4", port:9999}}
671 */
672 ignore_value(virJSONValueObjectAdd(&ret,
673 "S:tls-creds", tlsAlias,
674 "s:vdisk-id", src->path,
675 "a:server", &server, NULL));
676
677 return ret;
678 }
679
680
681 static virJSONValue *
qemuBlockStorageSourceGetNFSProps(virStorageSource * src)682 qemuBlockStorageSourceGetNFSProps(virStorageSource *src)
683 {
684 g_autoptr(virJSONValue) server = NULL;
685 virJSONValue *ret = NULL;
686
687 if (!(server = qemuBlockStorageSourceBuildJSONNFSServer(&src->hosts[0])))
688 return NULL;
689
690 /* NFS disk specification example:
691 * { driver:"nfs",
692 * user: "0",
693 * group: "0",
694 * path: "/foo/bar/baz",
695 * server: {type:"tcp", host:"1.2.3.4"}}
696 */
697 if (virJSONValueObjectAdd(&ret,
698 "a:server", &server,
699 "S:path", src->path, NULL) < 0)
700 return NULL;
701
702 if (src->nfs_uid != -1 &&
703 virJSONValueObjectAdd(&ret, "i:user", src->nfs_uid, NULL) < 0)
704 return NULL;
705
706 if (src->nfs_gid != -1 &&
707 virJSONValueObjectAdd(&ret, "i:group", src->nfs_gid, NULL) < 0)
708 return NULL;
709
710 return ret;
711 }
712
713
714 static virJSONValue *
qemuBlockStorageSourceGetCURLProps(virStorageSource * src,bool onlytarget)715 qemuBlockStorageSourceGetCURLProps(virStorageSource *src,
716 bool onlytarget)
717 {
718 qemuDomainStorageSourcePrivate *srcPriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(src);
719 const char *passwordalias = NULL;
720 const char *cookiealias = NULL;
721 const char *username = NULL;
722 virJSONValue *ret = NULL;
723 g_autoptr(virURI) uri = NULL;
724 g_autofree char *uristr = NULL;
725 g_autofree char *cookiestr = NULL;
726
727 /**
728 * Common options:
729 * url, readahead, timeout, username, password-secret, proxy-username,
730 * proxy-password-secret
731 *
732 * Options for http transport:
733 * cookie, cookie-secret
734 *
735 * Options for secure transport (ftps, https):
736 * sslverify
737 */
738
739
740 if (!(uri = qemuBlockStorageSourceGetURI(src)))
741 return NULL;
742
743 if (!(uristr = virURIFormat(uri)))
744 return NULL;
745
746 if (!onlytarget) {
747 if (src->auth) {
748 username = src->auth->username;
749 passwordalias = srcPriv->secinfo->alias;
750 }
751
752 if (srcPriv &&
753 srcPriv->httpcookie)
754 cookiealias = srcPriv->httpcookie->alias;
755 } else {
756 /* format target string along with cookies */
757 cookiestr = qemuBlockStorageSourceGetCookieString(src);
758 }
759
760 ignore_value(virJSONValueObjectAdd(&ret,
761 "s:url", uristr,
762 "S:username", username,
763 "S:password-secret", passwordalias,
764 "T:sslverify", src->sslverify,
765 "S:cookie", cookiestr,
766 "S:cookie-secret", cookiealias,
767 "P:timeout", src->timeout,
768 "P:readahead", src->readahead,
769 NULL));
770
771 return ret;
772 }
773
774
775 static virJSONValue *
qemuBlockStorageSourceGetISCSIProps(virStorageSource * src,bool onlytarget)776 qemuBlockStorageSourceGetISCSIProps(virStorageSource *src,
777 bool onlytarget)
778 {
779 qemuDomainStorageSourcePrivate *srcPriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(src);
780 g_autofree char *target = NULL;
781 char *lunStr = NULL;
782 char *username = NULL;
783 char *objalias = NULL;
784 g_autofree char *portal = NULL;
785 unsigned int lun = 0;
786 virJSONValue *ret = NULL;
787
788 /* { driver:"iscsi",
789 * transport:"tcp", ("iser" also possible)
790 * portal:"example.com",
791 * target:"iqn.2017-04.com.example:iscsi-disks",
792 * lun:1,
793 * user:"username",
794 * password-secret:"secret-alias",
795 * initiator-name:"iqn.2017-04.com.example:client"
796 * }
797 */
798
799 target = g_strdup(src->path);
800
801 /* Separate the target and lun */
802 if ((lunStr = strchr(target, '/'))) {
803 *(lunStr++) = '\0';
804 if (virStrToLong_ui(lunStr, NULL, 10, &lun) < 0) {
805 virReportError(VIR_ERR_INTERNAL_ERROR,
806 _("cannot parse target for lunStr '%s'"),
807 target);
808 return NULL;
809 }
810 }
811
812 /* combine host and port into portal */
813 if (virSocketAddrNumericFamily(src->hosts[0].name) == AF_INET6) {
814 portal = g_strdup_printf("[%s]:%u", src->hosts[0].name,
815 src->hosts[0].port);
816 } else {
817 portal = g_strdup_printf("%s:%u", src->hosts[0].name, src->hosts[0].port);
818 }
819
820 if (!onlytarget && src->auth) {
821 username = src->auth->username;
822 objalias = srcPriv->secinfo->alias;
823 }
824
825 ignore_value(virJSONValueObjectAdd(&ret,
826 "s:portal", portal,
827 "s:target", target,
828 "u:lun", lun,
829 "s:transport", "tcp",
830 "S:user", username,
831 "S:password-secret", objalias,
832 "S:initiator-name", src->initiator.iqn,
833 NULL));
834 return ret;
835 }
836
837
838 static virJSONValue *
qemuBlockStorageSourceGetNBDProps(virStorageSource * src,bool onlytarget)839 qemuBlockStorageSourceGetNBDProps(virStorageSource *src,
840 bool onlytarget)
841 {
842 g_autoptr(virJSONValue) serverprops = NULL;
843 const char *tlsAlias = src->tlsAlias;
844 virJSONValue *ret = NULL;
845
846 if (src->nhosts != 1) {
847 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
848 _("nbd protocol accepts only one host"));
849 return NULL;
850 }
851
852 serverprops = qemuBlockStorageSourceBuildJSONSocketAddress(&src->hosts[0],
853 false);
854 if (!serverprops)
855 return NULL;
856
857 if (onlytarget)
858 tlsAlias = NULL;
859
860 if (virJSONValueObjectAdd(&ret,
861 "a:server", &serverprops,
862 "S:export", src->path,
863 "S:tls-creds", tlsAlias,
864 NULL) < 0)
865 return NULL;
866
867 return ret;
868 }
869
870
871 static virJSONValue *
qemuBlockStorageSourceGetRBDProps(virStorageSource * src,bool onlytarget)872 qemuBlockStorageSourceGetRBDProps(virStorageSource *src,
873 bool onlytarget)
874 {
875 qemuDomainStorageSourcePrivate *srcPriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(src);
876 g_autoptr(virJSONValue) servers = NULL;
877 virJSONValue *ret = NULL;
878 g_autoptr(virJSONValue) encrypt = NULL;
879 const char *encformat;
880 const char *username = NULL;
881 g_autoptr(virJSONValue) authmodes = NULL;
882 g_autoptr(virJSONValue) mode = NULL;
883 const char *keysecret = NULL;
884
885 if (src->nhosts > 0 &&
886 !(servers = qemuBlockStorageSourceBuildHostsJSONInetSocketAddress(src)))
887 return NULL;
888
889 if (!onlytarget && src->auth) {
890 username = srcPriv->secinfo->username;
891 keysecret = srcPriv->secinfo->alias;
892 /* the auth modes are modelled after our old command line generator */
893 authmodes = virJSONValueNewArray();
894
895 if (!(mode = virJSONValueNewString("cephx")) ||
896 virJSONValueArrayAppend(authmodes, &mode) < 0)
897 return NULL;
898
899 if (!(mode = virJSONValueNewString("none")) ||
900 virJSONValueArrayAppend(authmodes, &mode) < 0)
901 return NULL;
902 }
903
904 if (src->encryption &&
905 src->encryption->engine == VIR_STORAGE_ENCRYPTION_ENGINE_LIBRBD) {
906 switch ((virStorageEncryptionFormatType) src->encryption->format) {
907 case VIR_STORAGE_ENCRYPTION_FORMAT_LUKS:
908 encformat = "luks";
909 break;
910
911 case VIR_STORAGE_ENCRYPTION_FORMAT_LUKS2:
912 encformat = "luks2";
913 break;
914
915 case VIR_STORAGE_ENCRYPTION_FORMAT_QCOW:
916 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
917 _("librbd encryption engine only supports luks/luks2 formats"));
918 return NULL;
919
920 case VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT:
921 case VIR_STORAGE_ENCRYPTION_FORMAT_LAST:
922 default:
923 virReportEnumRangeError(virStorageEncryptionFormatType,
924 src->encryption->format);
925 return NULL;
926 }
927
928 if (virJSONValueObjectAdd(&encrypt,
929 "s:format", encformat,
930 "s:key-secret", srcPriv->encinfo->alias,
931 NULL) < 0)
932 return NULL;
933 }
934
935 if (virJSONValueObjectAdd(&ret,
936 "s:pool", src->volume,
937 "s:image", src->path,
938 "S:snapshot", src->snapshot,
939 "S:conf", src->configFile,
940 "A:server", &servers,
941 "A:encrypt", &encrypt,
942 "S:user", username,
943 "A:auth-client-required", &authmodes,
944 "S:key-secret", keysecret,
945 NULL) < 0)
946 return NULL;
947
948 return ret;
949 }
950
951
952 static virJSONValue *
qemuBlockStorageSourceGetSheepdogProps(virStorageSource * src)953 qemuBlockStorageSourceGetSheepdogProps(virStorageSource *src)
954 {
955 g_autoptr(virJSONValue) serverprops = NULL;
956 virJSONValue *ret = NULL;
957
958 if (src->nhosts != 1) {
959 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
960 _("sheepdog protocol accepts only one host"));
961 return NULL;
962 }
963
964 serverprops = qemuBlockStorageSourceBuildJSONSocketAddress(&src->hosts[0],
965 false);
966 if (!serverprops)
967 return NULL;
968
969 /* libvirt does not support the 'snap-id' and 'tag' properties */
970 if (virJSONValueObjectAdd(&ret,
971 "a:server", &serverprops,
972 "s:vdi", src->path,
973 NULL) < 0)
974 return NULL;
975
976 return ret;
977 }
978
979
980 static virJSONValue *
qemuBlockStorageSourceGetSshProps(virStorageSource * src)981 qemuBlockStorageSourceGetSshProps(virStorageSource *src)
982 {
983 g_autoptr(virJSONValue) serverprops = NULL;
984 virJSONValue *ret = NULL;
985 const char *username = NULL;
986 g_autoptr(virJSONValue) host_key_check = NULL;
987
988 if (src->nhosts != 1) {
989 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
990 _("ssh protocol accepts only one host"));
991 return NULL;
992 }
993
994 serverprops = qemuBlockStorageSourceBuildJSONInetSocketAddress(&src->hosts[0]);
995 if (!serverprops)
996 return NULL;
997
998 if (src->auth)
999 username = src->auth->username;
1000 else if (src->ssh_user)
1001 username = src->ssh_user;
1002
1003 if (src->ssh_host_key_check_disabled &&
1004 virJSONValueObjectAdd(&host_key_check,
1005 "s:mode", "none",
1006 NULL) < 0)
1007 return NULL;
1008
1009 if (virJSONValueObjectAdd(&ret,
1010 "s:path", src->path,
1011 "a:server", &serverprops,
1012 "S:user", username,
1013 "A:host-key-check", &host_key_check,
1014 NULL) < 0)
1015 return NULL;
1016
1017 return ret;
1018 }
1019
1020
1021 static virJSONValue *
qemuBlockStorageSourceGetFileProps(virStorageSource * src,bool onlytarget)1022 qemuBlockStorageSourceGetFileProps(virStorageSource *src,
1023 bool onlytarget)
1024 {
1025 const char *iomode = NULL;
1026 const char *prManagerAlias = NULL;
1027 virJSONValue *ret = NULL;
1028
1029 if (!onlytarget) {
1030 if (src->pr)
1031 prManagerAlias = src->pr->mgralias;
1032
1033 if (src->iomode != VIR_DOMAIN_DISK_IO_DEFAULT)
1034 iomode = virDomainDiskIoTypeToString(src->iomode);
1035 }
1036
1037 ignore_value(virJSONValueObjectAdd(&ret,
1038 "s:filename", src->path,
1039 "S:aio", iomode,
1040 "S:pr-manager", prManagerAlias,
1041 NULL) < 0);
1042 return ret;
1043 }
1044
1045
1046 static virJSONValue *
qemuBlockStorageSourceGetVvfatProps(virStorageSource * src,bool onlytarget)1047 qemuBlockStorageSourceGetVvfatProps(virStorageSource *src,
1048 bool onlytarget)
1049 {
1050 g_autoptr(virJSONValue) ret = NULL;
1051
1052 /* libvirt currently does not handle the following attributes:
1053 * '*fat-type': 'int'
1054 * '*label': 'str'
1055 */
1056 if (virJSONValueObjectAdd(&ret,
1057 "s:driver", "vvfat",
1058 "s:dir", src->path,
1059 "b:floppy", src->floppyimg, NULL) < 0)
1060 return NULL;
1061
1062 if (!onlytarget &&
1063 virJSONValueObjectAdd(&ret, "b:rw", !src->readonly, NULL) < 0)
1064 return NULL;
1065
1066 return g_steal_pointer(&ret);
1067 }
1068
1069
1070 static virJSONValue *
qemuBlockStorageSourceGetNVMeProps(virStorageSource * src)1071 qemuBlockStorageSourceGetNVMeProps(virStorageSource *src)
1072 {
1073 const virStorageSourceNVMeDef *nvme = src->nvme;
1074 g_autofree char *pciAddr = NULL;
1075 virJSONValue *ret = NULL;
1076
1077 if (!(pciAddr = virPCIDeviceAddressAsString(&nvme->pciAddr)))
1078 return NULL;
1079
1080 ignore_value(virJSONValueObjectAdd(&ret,
1081 "s:driver", "nvme",
1082 "s:device", pciAddr,
1083 "U:namespace", nvme->namespc,
1084 NULL));
1085 return ret;
1086 }
1087
1088
1089 static int
qemuBlockStorageSourceGetBlockdevGetCacheProps(virStorageSource * src,virJSONValue * props)1090 qemuBlockStorageSourceGetBlockdevGetCacheProps(virStorageSource *src,
1091 virJSONValue *props)
1092 {
1093 g_autoptr(virJSONValue) cacheobj = NULL;
1094 bool direct = false;
1095 bool noflush = false;
1096
1097 if (src->cachemode == VIR_DOMAIN_DISK_CACHE_DEFAULT)
1098 return 0;
1099
1100 if (qemuDomainDiskCachemodeFlags(src->cachemode, NULL, &direct, &noflush) < 0)
1101 return -1;
1102
1103 if (virJSONValueObjectAdd(&cacheobj,
1104 "b:direct", direct,
1105 "b:no-flush", noflush,
1106 NULL) < 0)
1107 return -1;
1108
1109 if (virJSONValueObjectAppend(props, "cache", &cacheobj) < 0)
1110 return -1;
1111
1112 return 0;
1113 }
1114
1115
1116 /**
1117 * qemuBlockStorageSourceGetBackendProps:
1118 * @src: disk source
1119 * @flags: bitwise-or of qemuBlockStorageSourceBackendPropsFlags
1120 *
1121 * Flags:
1122 * QEMU_BLOCK_STORAGE_SOURCE_BACKEND_PROPS_LEGACY:
1123 * use legacy formatting of attributes (for -drive / old qemus)
1124 * QEMU_BLOCK_STORAGE_SOURCE_BACKEND_PROPS_TARGET_ONLY:
1125 * omit any data which does not identify the image itself
1126 * QEMU_BLOCK_STORAGE_SOURCE_BACKEND_PROPS_AUTO_READONLY:
1127 * use the auto-read-only feature of qemu
1128 * QEMU_BLOCK_STORAGE_SOURCE_BACKEND_PROPS_SKIP_UNMAP:
1129 * don't enable 'discard:unmap' option for passing through discards
1130 * (note that this is disabled also for _LEGACY and _TARGET_ONLY options)
1131 *
1132 * Creates a JSON object describing the underlying storage or protocol of a
1133 * storage source. Returns NULL on error and reports an appropriate error message.
1134 */
1135 virJSONValue *
qemuBlockStorageSourceGetBackendProps(virStorageSource * src,unsigned int flags)1136 qemuBlockStorageSourceGetBackendProps(virStorageSource *src,
1137 unsigned int flags)
1138 {
1139 int actualType = virStorageSourceGetActualType(src);
1140 g_autoptr(virJSONValue) fileprops = NULL;
1141 const char *driver = NULL;
1142 virTristateBool aro = VIR_TRISTATE_BOOL_ABSENT;
1143 virTristateBool ro = VIR_TRISTATE_BOOL_ABSENT;
1144 bool onlytarget = flags & QEMU_BLOCK_STORAGE_SOURCE_BACKEND_PROPS_TARGET_ONLY;
1145 bool legacy = flags & QEMU_BLOCK_STORAGE_SOURCE_BACKEND_PROPS_LEGACY;
1146
1147 if (flags & QEMU_BLOCK_STORAGE_SOURCE_BACKEND_PROPS_AUTO_READONLY) {
1148 aro = VIR_TRISTATE_BOOL_YES;
1149 } else {
1150 if (src->readonly)
1151 ro = VIR_TRISTATE_BOOL_YES;
1152 else
1153 ro = VIR_TRISTATE_BOOL_NO;
1154 }
1155
1156 switch ((virStorageType)actualType) {
1157 case VIR_STORAGE_TYPE_BLOCK:
1158 case VIR_STORAGE_TYPE_FILE:
1159 if (virStorageSourceIsBlockLocal(src)) {
1160 if (src->hostcdrom)
1161 driver = "host_cdrom";
1162 else
1163 driver = "host_device";
1164 } else {
1165 driver = "file";
1166 }
1167
1168 if (!(fileprops = qemuBlockStorageSourceGetFileProps(src, onlytarget)))
1169 return NULL;
1170 break;
1171
1172 case VIR_STORAGE_TYPE_DIR:
1173 /* qemu handles directories by exposing them as a device with emulated
1174 * FAT filesystem */
1175 if (!(fileprops = qemuBlockStorageSourceGetVvfatProps(src, onlytarget)))
1176 return NULL;
1177 break;
1178
1179 case VIR_STORAGE_TYPE_NVME:
1180 if (!(fileprops = qemuBlockStorageSourceGetNVMeProps(src)))
1181 return NULL;
1182 break;
1183
1184 case VIR_STORAGE_TYPE_VHOST_USER:
1185 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1186 _("unable to create blockdev props for vhostuser disk type"));
1187 return NULL;
1188
1189 case VIR_STORAGE_TYPE_VOLUME:
1190 virReportError(VIR_ERR_INTERNAL_ERROR,
1191 _("storage source pool '%s' volume '%s' is not translated"),
1192 src->srcpool->pool, src->srcpool->volume);
1193 return NULL;
1194
1195 case VIR_STORAGE_TYPE_NONE:
1196 case VIR_STORAGE_TYPE_LAST:
1197 virReportEnumRangeError(virStorageType, actualType);
1198 return NULL;
1199
1200 case VIR_STORAGE_TYPE_NETWORK:
1201 switch ((virStorageNetProtocol) src->protocol) {
1202 case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
1203 driver = "gluster";
1204 if (!(fileprops = qemuBlockStorageSourceGetGlusterProps(src, legacy, onlytarget)))
1205 return NULL;
1206 break;
1207
1208 case VIR_STORAGE_NET_PROTOCOL_VXHS:
1209 driver = "vxhs";
1210 if (!(fileprops = qemuBlockStorageSourceGetVxHSProps(src, onlytarget)))
1211 return NULL;
1212 break;
1213
1214 case VIR_STORAGE_NET_PROTOCOL_HTTP:
1215 case VIR_STORAGE_NET_PROTOCOL_HTTPS:
1216 case VIR_STORAGE_NET_PROTOCOL_FTP:
1217 case VIR_STORAGE_NET_PROTOCOL_FTPS:
1218 case VIR_STORAGE_NET_PROTOCOL_TFTP:
1219 driver = virStorageNetProtocolTypeToString(src->protocol);
1220 if (!(fileprops = qemuBlockStorageSourceGetCURLProps(src, onlytarget)))
1221 return NULL;
1222 break;
1223
1224 case VIR_STORAGE_NET_PROTOCOL_ISCSI:
1225 driver = "iscsi";
1226 if (!(fileprops = qemuBlockStorageSourceGetISCSIProps(src, onlytarget)))
1227 return NULL;
1228 break;
1229
1230 case VIR_STORAGE_NET_PROTOCOL_NBD:
1231 driver = "nbd";
1232 if (!(fileprops = qemuBlockStorageSourceGetNBDProps(src, onlytarget)))
1233 return NULL;
1234 break;
1235
1236 case VIR_STORAGE_NET_PROTOCOL_RBD:
1237 driver = "rbd";
1238 if (!(fileprops = qemuBlockStorageSourceGetRBDProps(src, onlytarget)))
1239 return NULL;
1240 break;
1241
1242 case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
1243 driver = "sheepdog";
1244 if (!(fileprops = qemuBlockStorageSourceGetSheepdogProps(src)))
1245 return NULL;
1246 break;
1247
1248 case VIR_STORAGE_NET_PROTOCOL_SSH:
1249 driver = "ssh";
1250 if (!(fileprops = qemuBlockStorageSourceGetSshProps(src)))
1251 return NULL;
1252 break;
1253
1254 case VIR_STORAGE_NET_PROTOCOL_NFS:
1255 driver = "nfs";
1256 if (!(fileprops = qemuBlockStorageSourceGetNFSProps(src)))
1257 return NULL;
1258 break;
1259
1260 case VIR_STORAGE_NET_PROTOCOL_NONE:
1261 case VIR_STORAGE_NET_PROTOCOL_LAST:
1262 virReportEnumRangeError(virStorageNetProtocol, src->protocol);
1263 return NULL;
1264 }
1265 break;
1266 }
1267
1268 if (driver && virJSONValueObjectPrependString(fileprops, "driver", driver) < 0)
1269 return NULL;
1270
1271 if (!onlytarget) {
1272 if (qemuBlockNodeNameValidate(src->nodestorage) < 0 ||
1273 virJSONValueObjectAdd(&fileprops, "S:node-name", src->nodestorage, NULL) < 0)
1274 return NULL;
1275
1276 if (!legacy) {
1277 if (qemuBlockStorageSourceGetBlockdevGetCacheProps(src, fileprops) < 0)
1278 return NULL;
1279
1280 if (virJSONValueObjectAdd(&fileprops,
1281 "T:read-only", ro,
1282 "T:auto-read-only", aro,
1283 NULL) < 0)
1284 return NULL;
1285
1286 if (!(flags & QEMU_BLOCK_STORAGE_SOURCE_BACKEND_PROPS_SKIP_UNMAP) &&
1287 virJSONValueObjectAdd(&fileprops,
1288 "s:discard", "unmap",
1289 NULL) < 0)
1290 return NULL;
1291 }
1292 }
1293
1294 return g_steal_pointer(&fileprops);
1295 }
1296
1297
1298 static int
qemuBlockStorageSourceGetFormatLUKSProps(virStorageSource * src,virJSONValue * props)1299 qemuBlockStorageSourceGetFormatLUKSProps(virStorageSource *src,
1300 virJSONValue *props)
1301 {
1302 qemuDomainStorageSourcePrivate *srcPriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(src);
1303
1304 if (!srcPriv || !srcPriv->encinfo || !srcPriv->encinfo->alias) {
1305 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1306 _("missing secret info for 'luks' driver"));
1307 return -1;
1308 }
1309
1310 if (virJSONValueObjectAdd(&props,
1311 "s:driver", "luks",
1312 "s:key-secret", srcPriv->encinfo->alias,
1313 NULL) < 0)
1314 return -1;
1315
1316 return 0;
1317 }
1318
1319
1320 static int
qemuBlockStorageSourceGetFormatRawProps(virStorageSource * src,virJSONValue * props)1321 qemuBlockStorageSourceGetFormatRawProps(virStorageSource *src,
1322 virJSONValue *props)
1323 {
1324 if (virJSONValueObjectAdd(&props, "s:driver", "raw", NULL) < 0)
1325 return -1;
1326
1327 /* Currently only storage slices are supported. We'll have to calculate
1328 * the union of the slices here if we don't want to be adding needless
1329 * 'raw' nodes. */
1330 if (src->sliceStorage &&
1331 virJSONValueObjectAdd(&props,
1332 "U:offset", src->sliceStorage->offset,
1333 "U:size", src->sliceStorage->size,
1334 NULL) < 0)
1335 return -1;
1336
1337 return 0;
1338 }
1339
1340
1341 static int
qemuBlockStorageSourceGetCryptoProps(virStorageSource * src,virJSONValue ** encprops)1342 qemuBlockStorageSourceGetCryptoProps(virStorageSource *src,
1343 virJSONValue **encprops)
1344 {
1345 qemuDomainStorageSourcePrivate *srcpriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(src);
1346 const char *encformat = NULL;
1347
1348 *encprops = NULL;
1349
1350 if (!src->encryption ||
1351 src->encryption->engine != VIR_STORAGE_ENCRYPTION_ENGINE_QEMU ||
1352 !srcpriv ||
1353 !srcpriv->encinfo)
1354 return 0;
1355
1356 switch ((virStorageEncryptionFormatType) src->encryption->format) {
1357 case VIR_STORAGE_ENCRYPTION_FORMAT_QCOW:
1358 encformat = "aes";
1359 break;
1360
1361 case VIR_STORAGE_ENCRYPTION_FORMAT_LUKS:
1362 encformat = "luks";
1363 break;
1364
1365 case VIR_STORAGE_ENCRYPTION_FORMAT_LUKS2:
1366 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1367 _("luks2 is currently not supported by the qemu encryption engine"));
1368 return -1;
1369
1370 case VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT:
1371 case VIR_STORAGE_ENCRYPTION_FORMAT_LAST:
1372 default:
1373 virReportEnumRangeError(virStorageEncryptionFormatType,
1374 src->encryption->format);
1375 return -1;
1376 }
1377
1378 return virJSONValueObjectAdd(encprops,
1379 "s:format", encformat,
1380 "s:key-secret", srcpriv->encinfo->alias,
1381 NULL);
1382 }
1383
1384
1385 static int
qemuBlockStorageSourceGetFormatQcowGenericProps(virStorageSource * src,const char * format,virJSONValue * props)1386 qemuBlockStorageSourceGetFormatQcowGenericProps(virStorageSource *src,
1387 const char *format,
1388 virJSONValue *props)
1389 {
1390 g_autoptr(virJSONValue) encprops = NULL;
1391
1392 if (qemuBlockStorageSourceGetCryptoProps(src, &encprops) < 0)
1393 return -1;
1394
1395 if (virJSONValueObjectAdd(&props,
1396 "s:driver", format,
1397 "A:encrypt", &encprops, NULL) < 0)
1398 return -1;
1399
1400 return 0;
1401 }
1402
1403
1404 static int
qemuBlockStorageSourceGetFormatQcow2Props(virStorageSource * src,virJSONValue * props)1405 qemuBlockStorageSourceGetFormatQcow2Props(virStorageSource *src,
1406 virJSONValue *props)
1407 {
1408 /* currently unhandled qcow2 props:
1409 *
1410 * 'lazy-refcounts'
1411 * 'pass-discard-request'
1412 * 'pass-discard-snapshot'
1413 * 'pass-discard-other'
1414 * 'overlap-check'
1415 * 'l2-cache-size'
1416 * 'l2-cache-entry-size'
1417 * 'refcount-cache-size'
1418 * 'cache-clean-interval'
1419 */
1420
1421 if (qemuBlockStorageSourceGetFormatQcowGenericProps(src, "qcow2", props) < 0)
1422 return -1;
1423
1424 /* 'cache-size' controls the maximum size of L2 and refcount caches.
1425 * see: qemu.git/docs/qcow2-cache.txt
1426 * https://git.qemu.org/?p=qemu.git;a=blob;f=docs/qcow2-cache.txt
1427 */
1428 if (src->metadataCacheMaxSize > 0) {
1429 if (virJSONValueObjectAdd(&props,
1430 "U:cache-size", src->metadataCacheMaxSize,
1431 NULL) < 0)
1432 return -1;
1433 }
1434
1435 return 0;
1436 }
1437
1438
1439 static virJSONValue *
qemuBlockStorageSourceGetBlockdevFormatCommonProps(virStorageSource * src)1440 qemuBlockStorageSourceGetBlockdevFormatCommonProps(virStorageSource *src)
1441 {
1442 const char *detectZeroes = NULL;
1443 const char *discard = NULL;
1444 int detectZeroesMode = virDomainDiskGetDetectZeroesMode(src->discard,
1445 src->detect_zeroes);
1446 g_autoptr(virJSONValue) props = NULL;
1447
1448 if (qemuBlockNodeNameValidate(src->nodeformat) < 0)
1449 return NULL;
1450
1451 if (src->discard)
1452 discard = virDomainDiskDiscardTypeToString(src->discard);
1453
1454 if (detectZeroesMode)
1455 detectZeroes = virDomainDiskDetectZeroesTypeToString(detectZeroesMode);
1456
1457 /* currently unhandled global properties:
1458 * '*force-share': 'bool'
1459 */
1460
1461 if (virJSONValueObjectAdd(&props,
1462 "s:node-name", src->nodeformat,
1463 "b:read-only", src->readonly,
1464 "S:discard", discard,
1465 "S:detect-zeroes", detectZeroes,
1466 NULL) < 0)
1467 return NULL;
1468
1469 if (qemuBlockStorageSourceGetBlockdevGetCacheProps(src, props) < 0)
1470 return NULL;
1471
1472 return g_steal_pointer(&props);
1473 }
1474
1475
1476 static virJSONValue *
qemuBlockStorageSourceGetBlockdevFormatProps(virStorageSource * src)1477 qemuBlockStorageSourceGetBlockdevFormatProps(virStorageSource *src)
1478 {
1479 const char *driver = NULL;
1480 g_autoptr(virJSONValue) props = NULL;
1481
1482 if (!(props = qemuBlockStorageSourceGetBlockdevFormatCommonProps(src)))
1483 return NULL;
1484
1485 switch ((virStorageFileFormat) src->format) {
1486 case VIR_STORAGE_FILE_FAT:
1487 /* The fat layer is emulated by the storage access layer, so we need to
1488 * put a raw layer on top */
1489 case VIR_STORAGE_FILE_RAW:
1490 if (src->encryption &&
1491 src->encryption->engine == VIR_STORAGE_ENCRYPTION_ENGINE_QEMU &&
1492 src->encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) {
1493 if (qemuBlockStorageSourceGetFormatLUKSProps(src, props) < 0)
1494 return NULL;
1495 } else {
1496 if (qemuBlockStorageSourceGetFormatRawProps(src, props) < 0)
1497 return NULL;
1498 }
1499 break;
1500
1501 case VIR_STORAGE_FILE_QCOW2:
1502 if (qemuBlockStorageSourceGetFormatQcow2Props(src, props) < 0)
1503 return NULL;
1504 break;
1505
1506 case VIR_STORAGE_FILE_QCOW:
1507 if (qemuBlockStorageSourceGetFormatQcowGenericProps(src, "qcow", props) < 0)
1508 return NULL;
1509 break;
1510
1511 /* formats without any special parameters */
1512 case VIR_STORAGE_FILE_PLOOP:
1513 driver = "parallels";
1514 break;
1515
1516 case VIR_STORAGE_FILE_VHD:
1517 driver = "vhdx";
1518 break;
1519
1520 case VIR_STORAGE_FILE_BOCHS:
1521 case VIR_STORAGE_FILE_CLOOP:
1522 case VIR_STORAGE_FILE_DMG:
1523 case VIR_STORAGE_FILE_VDI:
1524 case VIR_STORAGE_FILE_VPC:
1525 case VIR_STORAGE_FILE_QED:
1526 case VIR_STORAGE_FILE_VMDK:
1527 driver = virStorageFileFormatTypeToString(src->format);
1528 break;
1529
1530 case VIR_STORAGE_FILE_AUTO_SAFE:
1531 case VIR_STORAGE_FILE_AUTO:
1532 case VIR_STORAGE_FILE_NONE:
1533 case VIR_STORAGE_FILE_COW:
1534 case VIR_STORAGE_FILE_ISO:
1535 case VIR_STORAGE_FILE_DIR:
1536 virReportError(VIR_ERR_INTERNAL_ERROR,
1537 _("mishandled storage format '%s'"),
1538 virStorageFileFormatTypeToString(src->format));
1539 return NULL;
1540
1541 case VIR_STORAGE_FILE_LAST:
1542 default:
1543 virReportEnumRangeError(virStorageFileFormat, src->format);
1544 return NULL;
1545 }
1546
1547 if (driver &&
1548 virJSONValueObjectAdd(&props, "s:driver", driver, NULL) < 0)
1549 return NULL;
1550
1551 return g_steal_pointer(&props);
1552 }
1553
1554
1555 /**
1556 * qemuBlockStorageSourceGetBlockdevProps:
1557 *
1558 * @src: storage source to format
1559 * @backingStore: a storage source to use as backing of @src
1560 *
1561 * Formats @src into a JSON object which can be used with blockdev-add or
1562 * -blockdev. The formatted object contains both the storage and format layer
1563 * in nested form including link to the backing chain layer if necessary.
1564 */
1565 virJSONValue *
qemuBlockStorageSourceGetBlockdevProps(virStorageSource * src,virStorageSource * backingStore)1566 qemuBlockStorageSourceGetBlockdevProps(virStorageSource *src,
1567 virStorageSource *backingStore)
1568 {
1569 g_autoptr(virJSONValue) props = NULL;
1570 const char *storagenode = src->nodestorage;
1571
1572 if (qemuBlockStorageSourceNeedsStorageSliceLayer(src))
1573 storagenode = src->sliceStorage->nodename;
1574
1575 if (!(props = qemuBlockStorageSourceGetBlockdevFormatProps(src)))
1576 return NULL;
1577
1578 if (virJSONValueObjectAppendString(props, "file", storagenode) < 0)
1579 return NULL;
1580
1581 if (backingStore) {
1582 if (src->format >= VIR_STORAGE_FILE_BACKING) {
1583 if (virStorageSourceIsBacking(backingStore)) {
1584 if (virJSONValueObjectAppendString(props, "backing",
1585 backingStore->nodeformat) < 0)
1586 return NULL;
1587 } else {
1588 /* chain is terminated, indicate that no detection should happen
1589 * in qemu */
1590 if (virJSONValueObjectAppendNull(props, "backing") < 0)
1591 return NULL;
1592 }
1593 } else {
1594 if (virStorageSourceIsBacking(backingStore)) {
1595 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1596 _("storage format '%s' does not support backing store"),
1597 virStorageFileFormatTypeToString(src->format));
1598 return NULL;
1599 }
1600 }
1601 }
1602
1603 return g_steal_pointer(&props);
1604 }
1605
1606
1607 static virJSONValue *
qemuBlockStorageSourceGetBlockdevStorageSliceProps(virStorageSource * src)1608 qemuBlockStorageSourceGetBlockdevStorageSliceProps(virStorageSource *src)
1609 {
1610 g_autoptr(virJSONValue) props = NULL;
1611
1612 if (qemuBlockNodeNameValidate(src->sliceStorage->nodename) < 0)
1613 return NULL;
1614
1615 if (virJSONValueObjectAdd(&props,
1616 "s:driver", "raw",
1617 "s:node-name", src->sliceStorage->nodename,
1618 "U:offset", src->sliceStorage->offset,
1619 "U:size", src->sliceStorage->size,
1620 "s:file", src->nodestorage,
1621 "b:auto-read-only", true,
1622 "s:discard", "unmap",
1623 NULL) < 0)
1624 return NULL;
1625
1626 if (qemuBlockStorageSourceGetBlockdevGetCacheProps(src, props) < 0)
1627 return NULL;
1628
1629 return g_steal_pointer(&props);
1630 }
1631
1632
1633 void
qemuBlockStorageSourceAttachDataFree(qemuBlockStorageSourceAttachData * data)1634 qemuBlockStorageSourceAttachDataFree(qemuBlockStorageSourceAttachData *data)
1635 {
1636 if (!data)
1637 return;
1638
1639 virJSONValueFree(data->storageProps);
1640 virJSONValueFree(data->storageSliceProps);
1641 virJSONValueFree(data->formatProps);
1642 virJSONValueFree(data->prmgrProps);
1643 virJSONValueFree(data->authsecretProps);
1644 virJSONValueFree(data->httpcookiesecretProps);
1645 virJSONValueFree(data->encryptsecretProps);
1646 virJSONValueFree(data->tlsProps);
1647 virJSONValueFree(data->tlsKeySecretProps);
1648 g_free(data->tlsAlias);
1649 g_free(data->tlsKeySecretAlias);
1650 g_free(data->authsecretAlias);
1651 g_free(data->encryptsecretAlias);
1652 g_free(data->httpcookiesecretAlias);
1653 g_free(data->driveCmd);
1654 g_free(data->driveAlias);
1655 g_free(data->chardevAlias);
1656 g_free(data->chardevCmd);
1657 g_free(data);
1658 }
1659
1660
1661 /**
1662 * qemuBlockStorageSourceAttachPrepareBlockdev:
1663 * @src: storage source to prepare data from
1664 * @backingStore: storage source to use as backing of @src
1665 * @autoreadonly: use 'auto-read-only' feature of qemu
1666 *
1667 * Creates a qemuBlockStorageSourceAttachData structure containing data to attach
1668 * @src to a VM using the blockdev-add approach. Note that this function only
1669 * creates the data for the storage source itself, any other related
1670 * authentication/encryption/... objects need to be prepared separately.
1671 *
1672 * The changes are then applied using qemuBlockStorageSourceAttachApply.
1673 *
1674 * Returns the filled data structure on success or NULL on error and a libvirt
1675 * error is reported
1676 */
1677 qemuBlockStorageSourceAttachData *
qemuBlockStorageSourceAttachPrepareBlockdev(virStorageSource * src,virStorageSource * backingStore,bool autoreadonly)1678 qemuBlockStorageSourceAttachPrepareBlockdev(virStorageSource *src,
1679 virStorageSource *backingStore,
1680 bool autoreadonly)
1681 {
1682 g_autoptr(qemuBlockStorageSourceAttachData) data = NULL;
1683 unsigned int backendpropsflags = 0;
1684
1685 if (autoreadonly)
1686 backendpropsflags |= QEMU_BLOCK_STORAGE_SOURCE_BACKEND_PROPS_AUTO_READONLY;
1687
1688 data = g_new0(qemuBlockStorageSourceAttachData, 1);
1689
1690 if (!(data->formatProps = qemuBlockStorageSourceGetBlockdevProps(src,
1691 backingStore)) ||
1692 !(data->storageProps = qemuBlockStorageSourceGetBackendProps(src,
1693 backendpropsflags)))
1694 return NULL;
1695
1696 data->storageNodeName = src->nodestorage;
1697 data->formatNodeName = src->nodeformat;
1698
1699 if (qemuBlockStorageSourceNeedsStorageSliceLayer(src)) {
1700 if (!(data->storageSliceProps = qemuBlockStorageSourceGetBlockdevStorageSliceProps(src)))
1701 return NULL;
1702
1703 data->storageSliceNodeName = src->sliceStorage->nodename;
1704 }
1705
1706 return g_steal_pointer(&data);
1707 }
1708
1709
1710 static int
qemuBlockStorageSourceAttachApplyStorageDeps(qemuMonitor * mon,qemuBlockStorageSourceAttachData * data)1711 qemuBlockStorageSourceAttachApplyStorageDeps(qemuMonitor *mon,
1712 qemuBlockStorageSourceAttachData *data)
1713 {
1714 if (data->prmgrProps &&
1715 qemuMonitorAddObject(mon, &data->prmgrProps, &data->prmgrAlias) < 0)
1716 return -1;
1717
1718 if (data->authsecretProps &&
1719 qemuMonitorAddObject(mon, &data->authsecretProps,
1720 &data->authsecretAlias) < 0)
1721 return -1;
1722
1723 if (data->httpcookiesecretProps &&
1724 qemuMonitorAddObject(mon, &data->httpcookiesecretProps,
1725 &data->httpcookiesecretAlias) < 0)
1726 return -1;
1727
1728 if (data->tlsKeySecretProps &&
1729 qemuMonitorAddObject(mon, &data->tlsKeySecretProps,
1730 &data->tlsKeySecretAlias) < 0)
1731 return -1;
1732
1733 if (data->tlsProps &&
1734 qemuMonitorAddObject(mon, &data->tlsProps, &data->tlsAlias) < 0)
1735 return -1;
1736
1737 return 0;
1738 }
1739
1740
1741 static int
qemuBlockStorageSourceAttachApplyStorage(qemuMonitor * mon,qemuBlockStorageSourceAttachData * data)1742 qemuBlockStorageSourceAttachApplyStorage(qemuMonitor *mon,
1743 qemuBlockStorageSourceAttachData *data)
1744 {
1745 if (data->storageProps) {
1746 if (qemuMonitorBlockdevAdd(mon, &data->storageProps) < 0)
1747 return -1;
1748
1749 data->storageAttached = true;
1750 }
1751
1752 return 0;
1753 }
1754
1755
1756 static int
qemuBlockStorageSourceAttachApplyFormatDeps(qemuMonitor * mon,qemuBlockStorageSourceAttachData * data)1757 qemuBlockStorageSourceAttachApplyFormatDeps(qemuMonitor *mon,
1758 qemuBlockStorageSourceAttachData *data)
1759 {
1760 if (data->encryptsecretProps &&
1761 qemuMonitorAddObject(mon, &data->encryptsecretProps,
1762 &data->encryptsecretAlias) < 0)
1763 return -1;
1764
1765 return 0;
1766 }
1767
1768
1769 static int
qemuBlockStorageSourceAttachApplyFormat(qemuMonitor * mon,qemuBlockStorageSourceAttachData * data)1770 qemuBlockStorageSourceAttachApplyFormat(qemuMonitor *mon,
1771 qemuBlockStorageSourceAttachData *data)
1772 {
1773 if (data->formatProps) {
1774 if (qemuMonitorBlockdevAdd(mon, &data->formatProps) < 0)
1775 return -1;
1776
1777 data->formatAttached = true;
1778 }
1779
1780 return 0;
1781 }
1782
1783
1784 static int
qemuBlockStorageSourceAttachApplyStorageSlice(qemuMonitor * mon,qemuBlockStorageSourceAttachData * data)1785 qemuBlockStorageSourceAttachApplyStorageSlice(qemuMonitor *mon,
1786 qemuBlockStorageSourceAttachData *data)
1787 {
1788 if (data->storageSliceProps) {
1789 if (qemuMonitorBlockdevAdd(mon, &data->storageSliceProps) < 0)
1790 return -1;
1791
1792 data->storageSliceAttached = true;
1793 }
1794
1795 return 0;
1796 }
1797
1798
1799 /**
1800 * qemuBlockStorageSourceAttachApply:
1801 * @mon: monitor object
1802 * @data: structure holding data of block device to apply
1803 *
1804 * Attaches a virStorageSource definition converted to
1805 * qemuBlockStorageSourceAttachData to a running VM. This function expects being
1806 * called after the monitor was entered.
1807 *
1808 * Returns 0 on success and -1 on error with a libvirt error reported. If an
1809 * error occurred, changes which were already applied need to be rolled back by
1810 * calling qemuBlockStorageSourceAttachRollback.
1811 */
1812 int
qemuBlockStorageSourceAttachApply(qemuMonitor * mon,qemuBlockStorageSourceAttachData * data)1813 qemuBlockStorageSourceAttachApply(qemuMonitor *mon,
1814 qemuBlockStorageSourceAttachData *data)
1815 {
1816 if (qemuBlockStorageSourceAttachApplyStorageDeps(mon, data) < 0 ||
1817 qemuBlockStorageSourceAttachApplyStorage(mon, data) < 0 ||
1818 qemuBlockStorageSourceAttachApplyStorageSlice(mon, data) < 0 ||
1819 qemuBlockStorageSourceAttachApplyFormatDeps(mon, data) < 0 ||
1820 qemuBlockStorageSourceAttachApplyFormat(mon, data) < 0)
1821 return -1;
1822
1823 if (data->driveCmd) {
1824 if (qemuMonitorAddDrive(mon, data->driveCmd) < 0)
1825 return -1;
1826
1827 data->driveAdded = true;
1828 }
1829
1830 if (data->chardevDef) {
1831 if (qemuMonitorAttachCharDev(mon, data->chardevAlias, data->chardevDef) < 0)
1832 return -1;
1833
1834 data->chardevAdded = true;
1835 }
1836
1837 return 0;
1838 }
1839
1840
1841 /**
1842 * qemuBlockStorageSourceAttachRollback:
1843 * @mon: monitor object
1844 * @data: structure holding data of block device to roll back
1845 *
1846 * Attempts a best effort rollback of changes which were made to a running VM by
1847 * qemuBlockStorageSourceAttachApply. Preserves any existing errors.
1848 *
1849 * This function expects being called after the monitor was entered.
1850 */
1851 void
qemuBlockStorageSourceAttachRollback(qemuMonitor * mon,qemuBlockStorageSourceAttachData * data)1852 qemuBlockStorageSourceAttachRollback(qemuMonitor *mon,
1853 qemuBlockStorageSourceAttachData *data)
1854 {
1855 virErrorPtr orig_err;
1856
1857 virErrorPreserveLast(&orig_err);
1858
1859 if (data->chardevAdded) {
1860 if (qemuMonitorDetachCharDev(mon, data->chardevAlias) < 0) {
1861 VIR_WARN("Unable to remove chardev %s after failed 'device_add'",
1862 data->chardevAlias);
1863 }
1864 }
1865
1866 if (data->driveAdded) {
1867 if (qemuMonitorDriveDel(mon, data->driveAlias) < 0)
1868 VIR_WARN("Unable to remove drive %s (%s) after failed 'device_add'",
1869 data->driveAlias, data->driveCmd);
1870 }
1871
1872 if (data->formatAttached)
1873 ignore_value(qemuMonitorBlockdevDel(mon, data->formatNodeName));
1874
1875 if (data->storageSliceAttached)
1876 ignore_value(qemuMonitorBlockdevDel(mon, data->storageSliceNodeName));
1877
1878 if (data->storageAttached)
1879 ignore_value(qemuMonitorBlockdevDel(mon, data->storageNodeName));
1880
1881 if (data->prmgrAlias)
1882 ignore_value(qemuMonitorDelObject(mon, data->prmgrAlias, false));
1883
1884 if (data->authsecretAlias)
1885 ignore_value(qemuMonitorDelObject(mon, data->authsecretAlias, false));
1886
1887 if (data->encryptsecretAlias)
1888 ignore_value(qemuMonitorDelObject(mon, data->encryptsecretAlias, false));
1889
1890 if (data->httpcookiesecretAlias)
1891 ignore_value(qemuMonitorDelObject(mon, data->httpcookiesecretAlias, false));
1892
1893 if (data->tlsAlias)
1894 ignore_value(qemuMonitorDelObject(mon, data->tlsAlias, false));
1895
1896 if (data->tlsKeySecretAlias)
1897 ignore_value(qemuMonitorDelObject(mon, data->tlsKeySecretAlias, false));
1898
1899 virErrorRestore(&orig_err);
1900 }
1901
1902
1903 /**
1904 * qemuBlockStorageSourceDetachPrepare:
1905 * @src: disk source structure
1906 * @driveAlias: Alias of the -drive backend, the pointer is always consumed
1907 *
1908 * Prepare qemuBlockStorageSourceAttachData *for detaching a single source
1909 * from a VM. If @driveAlias is NULL -blockdev is assumed.
1910 */
1911 qemuBlockStorageSourceAttachData *
qemuBlockStorageSourceDetachPrepare(virStorageSource * src,char * driveAlias)1912 qemuBlockStorageSourceDetachPrepare(virStorageSource *src,
1913 char *driveAlias)
1914 {
1915 qemuDomainStorageSourcePrivate *srcpriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(src);
1916 g_autoptr(qemuBlockStorageSourceAttachData) data = NULL;
1917
1918 data = g_new0(qemuBlockStorageSourceAttachData, 1);
1919
1920 if (driveAlias) {
1921 data->driveAlias = g_steal_pointer(&driveAlias);
1922 data->driveAdded = true;
1923 } else {
1924 data->formatNodeName = src->nodeformat;
1925 data->formatAttached = true;
1926 data->storageNodeName = src->nodestorage;
1927 data->storageAttached = true;
1928
1929 /* 'raw' format doesn't need the extra 'raw' layer when slicing, thus
1930 * the nodename is NULL */
1931 if (src->sliceStorage &&
1932 src->sliceStorage->nodename) {
1933 data->storageSliceNodeName = src->sliceStorage->nodename;
1934 data->storageSliceAttached = true;
1935 }
1936 }
1937
1938 if (src->pr &&
1939 !virStoragePRDefIsManaged(src->pr))
1940 data->prmgrAlias = g_strdup(src->pr->mgralias);
1941
1942 data->tlsAlias = g_strdup(src->tlsAlias);
1943
1944 if (srcpriv) {
1945 if (srcpriv->secinfo)
1946 data->authsecretAlias = g_strdup(srcpriv->secinfo->alias);
1947
1948 if (srcpriv->encinfo)
1949 data->encryptsecretAlias = g_strdup(srcpriv->encinfo->alias);
1950
1951 if (srcpriv->httpcookie)
1952 data->httpcookiesecretAlias = g_strdup(srcpriv->httpcookie->alias);
1953
1954 if (srcpriv->tlsKeySecret)
1955 data->tlsKeySecretAlias = g_strdup(srcpriv->tlsKeySecret->alias);
1956 }
1957
1958 return g_steal_pointer(&data);
1959 }
1960
1961
1962 void
qemuBlockStorageSourceChainDataFree(qemuBlockStorageSourceChainData * data)1963 qemuBlockStorageSourceChainDataFree(qemuBlockStorageSourceChainData *data)
1964 {
1965 size_t i;
1966
1967 if (!data)
1968 return;
1969
1970 for (i = 0; i < data->nsrcdata; i++)
1971 qemuBlockStorageSourceAttachDataFree(data->srcdata[i]);
1972
1973 virJSONValueFree(data->copyOnReadProps);
1974 g_free(data->copyOnReadNodename);
1975
1976 g_free(data->srcdata);
1977 g_free(data);
1978 }
1979
1980
1981 /**
1982 * qemuBlockStorageSourceChainDetachPrepareBlockdev
1983 * @src: storage source chain to remove
1984 *
1985 * Prepares qemuBlockStorageSourceChainData *for detaching @src and its
1986 * backingStore if -blockdev was used.
1987 */
1988 qemuBlockStorageSourceChainData *
qemuBlockStorageSourceChainDetachPrepareBlockdev(virStorageSource * src)1989 qemuBlockStorageSourceChainDetachPrepareBlockdev(virStorageSource *src)
1990 {
1991 g_autoptr(qemuBlockStorageSourceAttachData) backend = NULL;
1992 g_autoptr(qemuBlockStorageSourceChainData) data = NULL;
1993 virStorageSource *n;
1994
1995 data = g_new0(qemuBlockStorageSourceChainData, 1);
1996
1997 for (n = src; virStorageSourceIsBacking(n); n = n->backingStore) {
1998 if (!(backend = qemuBlockStorageSourceDetachPrepare(n, NULL)))
1999 return NULL;
2000
2001 VIR_APPEND_ELEMENT(data->srcdata, data->nsrcdata, backend);
2002 }
2003
2004 return g_steal_pointer(&data);
2005 }
2006
2007
2008 /**
2009 * qemuBlockStorageSourceChainDetachPrepareLegacy
2010 * @src: storage source chain to remove
2011 * @driveAlias: Alias of the 'drive' backend (always consumed)
2012 *
2013 * Prepares qemuBlockStorageSourceChainData *for detaching @src and its
2014 * backingStore if -drive was used.
2015 */
2016 qemuBlockStorageSourceChainData *
qemuBlockStorageSourceChainDetachPrepareDrive(virStorageSource * src,char * driveAlias)2017 qemuBlockStorageSourceChainDetachPrepareDrive(virStorageSource *src,
2018 char *driveAlias)
2019 {
2020 g_autoptr(qemuBlockStorageSourceAttachData) backend = NULL;
2021 g_autoptr(qemuBlockStorageSourceChainData) data = NULL;
2022
2023 data = g_new0(qemuBlockStorageSourceChainData, 1);
2024
2025 if (!(backend = qemuBlockStorageSourceDetachPrepare(src, driveAlias)))
2026 return NULL;
2027
2028 VIR_APPEND_ELEMENT(data->srcdata, data->nsrcdata, backend);
2029
2030 return g_steal_pointer(&data);
2031 }
2032
2033
2034 /**
2035 * qemuBlockStorageSourceChainDetachPrepareChardev
2036 * @src: storage source chain to remove
2037 *
2038 * Prepares qemuBlockStorageSourceChainData *for detaching @src and its
2039 * backingStore if -chardev was used.
2040 */
2041 qemuBlockStorageSourceChainData *
qemuBlockStorageSourceChainDetachPrepareChardev(char * chardevAlias)2042 qemuBlockStorageSourceChainDetachPrepareChardev(char *chardevAlias)
2043 {
2044 g_autoptr(qemuBlockStorageSourceAttachData) backend = NULL;
2045 g_autoptr(qemuBlockStorageSourceChainData) data = NULL;
2046
2047 data = g_new0(qemuBlockStorageSourceChainData, 1);
2048 backend = g_new0(qemuBlockStorageSourceAttachData, 1);
2049
2050 backend->chardevAlias = chardevAlias;
2051 backend->chardevAdded = true;
2052
2053 VIR_APPEND_ELEMENT(data->srcdata, data->nsrcdata, backend);
2054
2055 return g_steal_pointer(&data);
2056 }
2057
2058
2059 /**
2060 * qemuBlockStorageSourceChainAttach:
2061 * @mon: monitor object
2062 * @data: storage source chain data
2063 *
2064 * Attach a storage source including its backing chain and supporting objects.
2065 * Caller must enter @mon prior calling this function. In case of error this
2066 * function returns -1. @data is updated so that qemuBlockStorageSourceChainDetach
2067 * can be used to roll-back the changes.
2068 */
2069 int
qemuBlockStorageSourceChainAttach(qemuMonitor * mon,qemuBlockStorageSourceChainData * data)2070 qemuBlockStorageSourceChainAttach(qemuMonitor *mon,
2071 qemuBlockStorageSourceChainData *data)
2072 {
2073 size_t i;
2074
2075 for (i = data->nsrcdata; i > 0; i--) {
2076 if (qemuBlockStorageSourceAttachApply(mon, data->srcdata[i - 1]) < 0)
2077 return -1;
2078 }
2079
2080 if (data->copyOnReadProps) {
2081 if (qemuMonitorBlockdevAdd(mon, &data->copyOnReadProps) < 0)
2082 return -1;
2083 }
2084
2085 return 0;
2086 }
2087
2088
2089 /**
2090 * qemuBlockStorageSourceChainDetach:
2091 * @mon: monitor object
2092 * @data: storage source chain data
2093 *
2094 * Detach a unused storage source including all its backing chain and related
2095 * objects described by @data.
2096 */
2097 void
qemuBlockStorageSourceChainDetach(qemuMonitor * mon,qemuBlockStorageSourceChainData * data)2098 qemuBlockStorageSourceChainDetach(qemuMonitor *mon,
2099 qemuBlockStorageSourceChainData *data)
2100 {
2101 size_t i;
2102
2103 if (data->copyOnReadAttached)
2104 ignore_value(qemuMonitorBlockdevDel(mon, data->copyOnReadNodename));
2105
2106
2107 for (i = 0; i < data->nsrcdata; i++)
2108 qemuBlockStorageSourceAttachRollback(mon, data->srcdata[i]);
2109 }
2110
2111
2112 /**
2113 * qemuBlockStorageSourceDetachOneBlockdev:
2114 * @driver: qemu driver object
2115 * @vm: domain object
2116 * @asyncJob: currently running async job
2117 * @src: storage source to detach
2118 *
2119 * Detaches one virStorageSource using blockdev-del. Note that this does not
2120 * detach any authentication/encryption objects. This function enters the
2121 * monitor internally.
2122 */
2123 int
qemuBlockStorageSourceDetachOneBlockdev(virQEMUDriver * driver,virDomainObj * vm,qemuDomainAsyncJob asyncJob,virStorageSource * src)2124 qemuBlockStorageSourceDetachOneBlockdev(virQEMUDriver *driver,
2125 virDomainObj *vm,
2126 qemuDomainAsyncJob asyncJob,
2127 virStorageSource *src)
2128 {
2129 int ret;
2130
2131 if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
2132 return -1;
2133
2134 ret = qemuMonitorBlockdevDel(qemuDomainGetMonitor(vm), src->nodeformat);
2135
2136 if (ret == 0)
2137 ret = qemuMonitorBlockdevDel(qemuDomainGetMonitor(vm), src->nodestorage);
2138
2139 if (qemuDomainObjExitMonitor(driver, vm) < 0)
2140 return -1;
2141
2142 return ret;
2143 }
2144
2145
2146 int
qemuBlockSnapshotAddLegacy(virJSONValue * actions,virDomainDiskDef * disk,virStorageSource * newsrc,bool reuse)2147 qemuBlockSnapshotAddLegacy(virJSONValue *actions,
2148 virDomainDiskDef *disk,
2149 virStorageSource *newsrc,
2150 bool reuse)
2151 {
2152 const char *format = virStorageFileFormatTypeToString(newsrc->format);
2153 g_autofree char *device = NULL;
2154 g_autofree char *source = NULL;
2155
2156 if (!(device = qemuAliasDiskDriveFromDisk(disk)))
2157 return -1;
2158
2159 if (qemuGetDriveSourceString(newsrc, NULL, &source) < 0)
2160 return -1;
2161
2162 return qemuMonitorTransactionSnapshotLegacy(actions, device, source, format, reuse);
2163 }
2164
2165
2166 int
qemuBlockSnapshotAddBlockdev(virJSONValue * actions,virDomainDiskDef * disk,virStorageSource * newsrc)2167 qemuBlockSnapshotAddBlockdev(virJSONValue *actions,
2168 virDomainDiskDef *disk,
2169 virStorageSource *newsrc)
2170 {
2171 return qemuMonitorTransactionSnapshotBlockdev(actions,
2172 disk->src->nodeformat,
2173 newsrc->nodeformat);
2174 }
2175
2176
2177 /**
2178 * qemuBlockStorageGetCopyOnReadProps:
2179 * @disk: disk with copy-on-read enabled
2180 *
2181 * Creates blockdev properties for a disk copy-on-read layer.
2182 */
2183 virJSONValue *
qemuBlockStorageGetCopyOnReadProps(virDomainDiskDef * disk)2184 qemuBlockStorageGetCopyOnReadProps(virDomainDiskDef *disk)
2185 {
2186 qemuDomainDiskPrivate *priv = QEMU_DOMAIN_DISK_PRIVATE(disk);
2187 virJSONValue *ret = NULL;
2188
2189 ignore_value(virJSONValueObjectAdd(&ret,
2190 "s:driver", "copy-on-read",
2191 "s:node-name", priv->nodeCopyOnRead,
2192 "s:file", disk->src->nodeformat,
2193 "s:discard", "unmap",
2194 NULL));
2195
2196 return ret;
2197 }
2198
2199
2200 /**
2201 * qemuBlockGetBackingStoreString:
2202 * @src: storage source to get the string for
2203 * @pretty: pretty-print the JSON (if applicable, used by tests)
2204 *
2205 * Formats a string used in the backing store field of a disk image which
2206 * supports backing store. Non-local storage may result in use of the json:
2207 * pseudo protocol for any complex configuration.
2208 */
2209 char *
qemuBlockGetBackingStoreString(virStorageSource * src,bool pretty)2210 qemuBlockGetBackingStoreString(virStorageSource *src,
2211 bool pretty)
2212 {
2213 int actualType = virStorageSourceGetActualType(src);
2214 g_autoptr(virJSONValue) backingProps = NULL;
2215 g_autoptr(virJSONValue) sliceProps = NULL;
2216 virJSONValue *props = NULL;
2217 g_autoptr(virURI) uri = NULL;
2218 g_autofree char *backingJSON = NULL;
2219
2220 if (!src->sliceStorage) {
2221 if (virStorageSourceIsLocalStorage(src)) {
2222 if (src->type == VIR_STORAGE_TYPE_DIR &&
2223 src->format == VIR_STORAGE_FILE_FAT)
2224 return g_strdup_printf("fat:%s", src->path);
2225
2226 return g_strdup(src->path);
2227 }
2228
2229 /* generate simplified URIs for the easy cases */
2230 if (actualType == VIR_STORAGE_TYPE_NETWORK &&
2231 src->nhosts == 1 &&
2232 src->hosts->transport == VIR_STORAGE_NET_HOST_TRANS_TCP &&
2233 src->timeout == 0 &&
2234 src->ncookies == 0 &&
2235 src->sslverify == VIR_TRISTATE_BOOL_ABSENT &&
2236 src->timeout == 0 &&
2237 src->readahead == 0) {
2238
2239 switch ((virStorageNetProtocol) src->protocol) {
2240 case VIR_STORAGE_NET_PROTOCOL_NBD:
2241 case VIR_STORAGE_NET_PROTOCOL_HTTP:
2242 case VIR_STORAGE_NET_PROTOCOL_HTTPS:
2243 case VIR_STORAGE_NET_PROTOCOL_FTP:
2244 case VIR_STORAGE_NET_PROTOCOL_FTPS:
2245 case VIR_STORAGE_NET_PROTOCOL_TFTP:
2246 case VIR_STORAGE_NET_PROTOCOL_ISCSI:
2247 case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
2248 if (!(uri = qemuBlockStorageSourceGetURI(src)))
2249 return NULL;
2250
2251 return virURIFormat(uri);
2252
2253 case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
2254 case VIR_STORAGE_NET_PROTOCOL_RBD:
2255 case VIR_STORAGE_NET_PROTOCOL_VXHS:
2256 case VIR_STORAGE_NET_PROTOCOL_NFS:
2257 case VIR_STORAGE_NET_PROTOCOL_SSH:
2258 case VIR_STORAGE_NET_PROTOCOL_LAST:
2259 case VIR_STORAGE_NET_PROTOCOL_NONE:
2260 break;
2261 }
2262 }
2263 }
2264
2265 /* use json: pseudo protocol otherwise */
2266 if (!(backingProps = qemuBlockStorageSourceGetBackendProps(src,
2267 QEMU_BLOCK_STORAGE_SOURCE_BACKEND_PROPS_TARGET_ONLY)))
2268 return NULL;
2269
2270 props = backingProps;
2271
2272 if (src->sliceStorage) {
2273 if (virJSONValueObjectAdd(&sliceProps,
2274 "s:driver", "raw",
2275 "U:offset", src->sliceStorage->offset,
2276 "U:size", src->sliceStorage->size,
2277 "a:file", &backingProps,
2278 NULL) < 0)
2279 return NULL;
2280
2281 props = sliceProps;
2282 }
2283
2284 if (!(backingJSON = virJSONValueToString(props, pretty)))
2285 return NULL;
2286
2287 return g_strdup_printf("json:{\"file\":%s}", backingJSON);
2288 }
2289
2290
2291 static int
qemuBlockStorageSourceCreateAddBacking(virStorageSource * backing,virJSONValue * props,bool format)2292 qemuBlockStorageSourceCreateAddBacking(virStorageSource *backing,
2293 virJSONValue *props,
2294 bool format)
2295 {
2296 g_autofree char *backingFileStr = NULL;
2297 const char *backingFormatStr = NULL;
2298
2299 if (!virStorageSourceIsBacking(backing))
2300 return 0;
2301
2302 if (format) {
2303 if (backing->format == VIR_STORAGE_FILE_RAW &&
2304 backing->encryption &&
2305 backing->encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS)
2306 backingFormatStr = "luks";
2307 else
2308 backingFormatStr = virStorageFileFormatTypeToString(backing->format);
2309 }
2310
2311 if (!(backingFileStr = qemuBlockGetBackingStoreString(backing, false)))
2312 return -1;
2313
2314 if (virJSONValueObjectAdd(&props,
2315 "S:backing-file", backingFileStr,
2316 "S:backing-fmt", backingFormatStr,
2317 NULL) < 0)
2318 return -1;
2319
2320 return 0;
2321 }
2322
2323
2324 static int
qemuBlockStorageSourceCreateGetFormatPropsGeneric(virStorageSource * src,const char * driver,virJSONValue ** retprops,virStorageSource * backing)2325 qemuBlockStorageSourceCreateGetFormatPropsGeneric(virStorageSource *src,
2326 const char *driver,
2327 virJSONValue **retprops,
2328 virStorageSource *backing)
2329 {
2330 g_autoptr(virJSONValue) props = NULL;
2331
2332 if (virJSONValueObjectAdd(&props,
2333 "s:driver", driver,
2334 "s:file", src->nodestorage,
2335 "U:size", src->capacity,
2336 NULL) < 0)
2337 return -1;
2338
2339 if (backing &&
2340 qemuBlockStorageSourceCreateAddBacking(backing, props, false) < 0)
2341 return -1;
2342
2343 *retprops = g_steal_pointer(&props);
2344 return 0;
2345 }
2346
2347
2348 static int
qemuBlockStorageSourceCreateGetEncryptionLUKS(virStorageSource * src,virJSONValue ** luksProps)2349 qemuBlockStorageSourceCreateGetEncryptionLUKS(virStorageSource *src,
2350 virJSONValue **luksProps)
2351 {
2352 qemuDomainStorageSourcePrivate *srcpriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(src);
2353 g_autoptr(virJSONValue) props = NULL;
2354 g_autofree char *cipheralg = NULL;
2355 const char *keysecret = NULL;
2356
2357 if (srcpriv &&
2358 srcpriv->encinfo)
2359 keysecret = srcpriv->encinfo->alias;
2360
2361 if (virJSONValueObjectAdd(&props,
2362 "s:key-secret", keysecret,
2363 NULL) < 0)
2364 return -1;
2365
2366 if (src->encryption) {
2367 if (src->encryption->encinfo.cipher_name) {
2368 cipheralg = g_strdup_printf("%s-%u",
2369 src->encryption->encinfo.cipher_name,
2370 src->encryption->encinfo.cipher_size);
2371 }
2372
2373 if (virJSONValueObjectAdd(&props,
2374 "S:cipher-alg", cipheralg,
2375 "S:cipher-mode", src->encryption->encinfo.cipher_mode,
2376 "S:hash-alg", src->encryption->encinfo.cipher_hash,
2377 "S:ivgen-alg", src->encryption->encinfo.ivgen_name,
2378 "S:ivgen-hash-alg", src->encryption->encinfo.ivgen_hash,
2379 NULL) < 0)
2380 return -1;
2381 }
2382
2383 *luksProps = g_steal_pointer(&props);
2384 return 0;
2385 }
2386
2387
2388 static int
qemuBlockStorageSourceCreateGetFormatPropsLUKS(virStorageSource * src,virJSONValue ** props)2389 qemuBlockStorageSourceCreateGetFormatPropsLUKS(virStorageSource *src,
2390 virJSONValue **props)
2391 {
2392 g_autoptr(virJSONValue) luksprops = NULL;
2393
2394 if (qemuBlockStorageSourceCreateGetEncryptionLUKS(src, &luksprops) < 0)
2395 return -1;
2396
2397 if (virJSONValueObjectAdd(&luksprops,
2398 "s:driver", "luks",
2399 "s:file", src->nodestorage,
2400 "U:size", src->capacity,
2401 NULL) < 0)
2402 return -1;
2403
2404 *props = g_steal_pointer(&luksprops);
2405 return 0;
2406 }
2407
2408
2409 static int
qemuBlockStorageSourceCreateAddEncryptionQcow(virStorageSource * src,virJSONValue * props)2410 qemuBlockStorageSourceCreateAddEncryptionQcow(virStorageSource *src,
2411 virJSONValue *props)
2412 {
2413 g_autoptr(virJSONValue) encryptProps = NULL;
2414
2415 if (!src->encryption)
2416 return 0;
2417
2418 if (src->encryption->format != VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) {
2419 virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
2420 _("creation of qcow/qcow2 files supports only 'luks' encryption"));
2421 return -1;
2422 }
2423
2424 if (qemuBlockStorageSourceCreateGetEncryptionLUKS(src, &encryptProps) < 0)
2425 return -1;
2426
2427 if (virJSONValueObjectAdd(&encryptProps, "s:format", "luks", NULL) < 0)
2428 return -1;
2429
2430 if (virJSONValueObjectAdd(&props, "a:encrypt", &encryptProps, NULL) < 0)
2431 return -1;
2432
2433 return 0;
2434 }
2435
2436
2437 static int
qemuBlockStorageSourceCreateGetFormatPropsQcow2(virStorageSource * src,virStorageSource * backing,virJSONValue ** props)2438 qemuBlockStorageSourceCreateGetFormatPropsQcow2(virStorageSource *src,
2439 virStorageSource *backing,
2440 virJSONValue **props)
2441 {
2442 g_autoptr(virJSONValue) qcow2props = NULL;
2443 const char *qcow2version = NULL;
2444
2445 if (STREQ_NULLABLE(src->compat, "0.10"))
2446 qcow2version = "v2";
2447 else if (STREQ_NULLABLE(src->compat, "1.1"))
2448 qcow2version = "v3";
2449
2450 if (virJSONValueObjectAdd(&qcow2props,
2451 "s:driver", "qcow2",
2452 "s:file", src->nodestorage,
2453 "U:size", src->capacity,
2454 "S:version", qcow2version,
2455 "P:cluster-size", src->clusterSize,
2456 NULL) < 0)
2457 return -1;
2458
2459 if (qemuBlockStorageSourceCreateAddBacking(backing, qcow2props, true) < 0 ||
2460 qemuBlockStorageSourceCreateAddEncryptionQcow(src, qcow2props) < 0)
2461 return -1;
2462
2463 *props = g_steal_pointer(&qcow2props);
2464 return 0;
2465 }
2466
2467
2468 static int
qemuBlockStorageSourceCreateGetFormatPropsQcow(virStorageSource * src,virStorageSource * backing,virJSONValue ** props)2469 qemuBlockStorageSourceCreateGetFormatPropsQcow(virStorageSource *src,
2470 virStorageSource *backing,
2471 virJSONValue **props)
2472 {
2473 g_autoptr(virJSONValue) qcowprops = NULL;
2474
2475 if (virJSONValueObjectAdd(&qcowprops,
2476 "s:driver", "qcow",
2477 "s:file", src->nodestorage,
2478 "U:size", src->capacity,
2479 NULL) < 0)
2480 return -1;
2481
2482 if (qemuBlockStorageSourceCreateAddBacking(backing, qcowprops, false) < 0 ||
2483 qemuBlockStorageSourceCreateAddEncryptionQcow(src, qcowprops) < 0)
2484 return -1;
2485
2486 *props = g_steal_pointer(&qcowprops);
2487 return 0;
2488 }
2489
2490
2491 static int
qemuBlockStorageSourceCreateGetFormatPropsQed(virStorageSource * src,virStorageSource * backing,virJSONValue ** props)2492 qemuBlockStorageSourceCreateGetFormatPropsQed(virStorageSource *src,
2493 virStorageSource *backing,
2494 virJSONValue **props)
2495 {
2496 g_autoptr(virJSONValue) qedprops = NULL;
2497
2498 if (virJSONValueObjectAdd(&qedprops,
2499 "s:driver", "qed",
2500 "s:file", src->nodestorage,
2501 "U:size", src->capacity,
2502 NULL) < 0)
2503 return -1;
2504
2505 if (qemuBlockStorageSourceCreateAddBacking(backing, qedprops, true) < 0)
2506 return -1;
2507
2508 *props = g_steal_pointer(&qedprops);
2509 return 0;
2510 }
2511
2512
2513 /**
2514 * qemuBlockStorageSourceCreateGetFormatProps:
2515 * @src: storage source to format
2516 * @backing: storage source describing backing image of @src (if necessary)
2517 * @props: filled with props to be used with 'blockdev-create' to format @src
2518 *
2519 * @src must be properly initialized to contain node-names of the protocol layer
2520 * which should be formatted. @props may be NULL with success returned in which
2521 * case creation of given storage format is not supported. Note that creation
2522 * of 'raw' storage is also returns NULL as there is nothing to do.
2523 */
2524 int
qemuBlockStorageSourceCreateGetFormatProps(virStorageSource * src,virStorageSource * backing,virJSONValue ** props)2525 qemuBlockStorageSourceCreateGetFormatProps(virStorageSource *src,
2526 virStorageSource *backing,
2527 virJSONValue **props)
2528 {
2529 switch ((virStorageFileFormat) src->format) {
2530 case VIR_STORAGE_FILE_RAW:
2531 if (!src->encryption ||
2532 src->encryption->format != VIR_STORAGE_ENCRYPTION_FORMAT_LUKS)
2533 return 0;
2534
2535 return qemuBlockStorageSourceCreateGetFormatPropsLUKS(src, props);
2536
2537 case VIR_STORAGE_FILE_QCOW2:
2538 return qemuBlockStorageSourceCreateGetFormatPropsQcow2(src, backing, props);
2539
2540 case VIR_STORAGE_FILE_QCOW:
2541 return qemuBlockStorageSourceCreateGetFormatPropsQcow(src, backing, props);
2542
2543 case VIR_STORAGE_FILE_QED:
2544 return qemuBlockStorageSourceCreateGetFormatPropsQed(src, backing, props);
2545
2546 case VIR_STORAGE_FILE_VPC:
2547 return qemuBlockStorageSourceCreateGetFormatPropsGeneric(src, "vpc",
2548 props, NULL);
2549
2550 case VIR_STORAGE_FILE_PLOOP:
2551 return qemuBlockStorageSourceCreateGetFormatPropsGeneric(src, "parallels",
2552 props, NULL);
2553
2554 case VIR_STORAGE_FILE_VDI:
2555 return qemuBlockStorageSourceCreateGetFormatPropsGeneric(src, "vdi",
2556 props, NULL);
2557
2558 case VIR_STORAGE_FILE_VHD:
2559 return qemuBlockStorageSourceCreateGetFormatPropsGeneric(src, "vhdx",
2560 props, NULL);
2561
2562 case VIR_STORAGE_FILE_VMDK:
2563 return qemuBlockStorageSourceCreateGetFormatPropsGeneric(src, "vmdk",
2564 props, backing);
2565
2566 /* unsupported by qemu / impossible */
2567 case VIR_STORAGE_FILE_FAT:
2568 case VIR_STORAGE_FILE_BOCHS:
2569 case VIR_STORAGE_FILE_CLOOP:
2570 case VIR_STORAGE_FILE_DMG:
2571 case VIR_STORAGE_FILE_COW:
2572 case VIR_STORAGE_FILE_ISO:
2573 case VIR_STORAGE_FILE_DIR:
2574 return 0;
2575
2576 case VIR_STORAGE_FILE_AUTO_SAFE:
2577 case VIR_STORAGE_FILE_AUTO:
2578 case VIR_STORAGE_FILE_NONE:
2579 virReportError(VIR_ERR_INTERNAL_ERROR,
2580 _("mishandled storage format '%s'"),
2581 virStorageFileFormatTypeToString(src->format));
2582 return -1;
2583
2584 case VIR_STORAGE_FILE_LAST:
2585 default:
2586 break;
2587 }
2588
2589 virReportEnumRangeError(virStorageFileFormat, src->format);
2590 return -1;
2591 }
2592
2593
2594 /**
2595 * qemuBlockStorageSourceCreateGetStorageProps:
2596 * @src: storage source to create
2597 * @props: filled with props to be used with 'blockdev-create' to create @src
2598 *
2599 * This function should be used only if @src->type is VIR_STORAGE_TYPE_NETWORK.
2600 * Note that @props may be NULL if qemu does not support creation storage
2601 * on given protocol. @src->physical is used as size for the storage.
2602 */
2603 int
qemuBlockStorageSourceCreateGetStorageProps(virStorageSource * src,virJSONValue ** props)2604 qemuBlockStorageSourceCreateGetStorageProps(virStorageSource *src,
2605 virJSONValue **props)
2606 {
2607 int actualType = virStorageSourceGetActualType(src);
2608 g_autoptr(virJSONValue) location = NULL;
2609 const char *driver = NULL;
2610 const char *filename = NULL;
2611
2612 switch ((virStorageType) actualType) {
2613 case VIR_STORAGE_TYPE_FILE:
2614 driver = "file";
2615 filename = src->path;
2616 break;
2617
2618 case VIR_STORAGE_TYPE_NETWORK:
2619 switch ((virStorageNetProtocol) src->protocol) {
2620 case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
2621 driver = "gluster";
2622 if (!(location = qemuBlockStorageSourceGetGlusterProps(src, false, false)))
2623 return -1;
2624 break;
2625
2626 case VIR_STORAGE_NET_PROTOCOL_RBD:
2627 driver = "rbd";
2628 if (!(location = qemuBlockStorageSourceGetRBDProps(src, false)))
2629 return -1;
2630 break;
2631
2632 case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
2633 driver = "sheepdog";
2634 if (!(location = qemuBlockStorageSourceGetSheepdogProps(src)))
2635 return -1;
2636 break;
2637
2638 case VIR_STORAGE_NET_PROTOCOL_SSH:
2639 driver = "ssh";
2640 if (!(location = qemuBlockStorageSourceGetSshProps(src)))
2641 return -1;
2642 break;
2643
2644 case VIR_STORAGE_NET_PROTOCOL_NFS:
2645 driver = "nfs";
2646 if (!(location = qemuBlockStorageSourceGetNFSProps(src)))
2647 return -1;
2648 break;
2649
2650 /* unsupported/impossible */
2651 case VIR_STORAGE_NET_PROTOCOL_NBD:
2652 case VIR_STORAGE_NET_PROTOCOL_ISCSI:
2653 case VIR_STORAGE_NET_PROTOCOL_VXHS:
2654 case VIR_STORAGE_NET_PROTOCOL_HTTP:
2655 case VIR_STORAGE_NET_PROTOCOL_HTTPS:
2656 case VIR_STORAGE_NET_PROTOCOL_FTP:
2657 case VIR_STORAGE_NET_PROTOCOL_FTPS:
2658 case VIR_STORAGE_NET_PROTOCOL_TFTP:
2659 case VIR_STORAGE_NET_PROTOCOL_NONE:
2660 case VIR_STORAGE_NET_PROTOCOL_LAST:
2661 return 0;
2662 }
2663 break;
2664
2665 case VIR_STORAGE_TYPE_BLOCK:
2666 case VIR_STORAGE_TYPE_DIR:
2667 case VIR_STORAGE_TYPE_VOLUME:
2668 case VIR_STORAGE_TYPE_NVME:
2669 case VIR_STORAGE_TYPE_VHOST_USER:
2670 return 0;
2671
2672 case VIR_STORAGE_TYPE_NONE:
2673 case VIR_STORAGE_TYPE_LAST:
2674 virReportEnumRangeError(virStorageType, actualType);
2675 return -1;
2676 }
2677
2678 if (virJSONValueObjectAdd(props,
2679 "s:driver", driver,
2680 "S:filename", filename,
2681 "A:location", &location,
2682 "U:size", src->physical,
2683 NULL) < 0)
2684 return -1;
2685
2686 return 0;
2687 }
2688
2689
2690 static int
qemuBlockStorageSourceCreateGeneric(virDomainObj * vm,virJSONValue * createProps,virStorageSource * src,virStorageSource * chain,bool storageCreate,qemuDomainAsyncJob asyncJob)2691 qemuBlockStorageSourceCreateGeneric(virDomainObj *vm,
2692 virJSONValue *createProps,
2693 virStorageSource *src,
2694 virStorageSource *chain,
2695 bool storageCreate,
2696 qemuDomainAsyncJob asyncJob)
2697 {
2698 g_autoptr(virJSONValue) props = createProps;
2699 qemuDomainObjPrivate *priv = vm->privateData;
2700 qemuBlockJobData *job = NULL;
2701 int ret = -1;
2702 int rc;
2703
2704 if (!(job = qemuBlockJobNewCreate(vm, src, chain, storageCreate)))
2705 return -1;
2706
2707 qemuBlockJobSyncBegin(job);
2708
2709 if (qemuDomainObjEnterMonitorAsync(priv->driver, vm, asyncJob) < 0)
2710 goto cleanup;
2711
2712 rc = qemuMonitorBlockdevCreate(priv->mon, job->name, props);
2713 props = NULL;
2714
2715 if (qemuDomainObjExitMonitor(priv->driver, vm) < 0 || rc < 0)
2716 goto cleanup;
2717
2718 qemuBlockJobStarted(job, vm);
2719
2720 qemuBlockJobUpdate(vm, job, asyncJob);
2721 while (qemuBlockJobIsRunning(job)) {
2722 if (virDomainObjWait(vm) < 0)
2723 goto cleanup;
2724 qemuBlockJobUpdate(vm, job, asyncJob);
2725 }
2726
2727 if (job->state == QEMU_BLOCKJOB_STATE_FAILED ||
2728 job->state == QEMU_BLOCKJOB_STATE_CANCELLED) {
2729 if (job->state == QEMU_BLOCKJOB_STATE_CANCELLED && !job->errmsg) {
2730 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
2731 _("blockdev-create job was cancelled"));
2732 } else {
2733 virReportError(VIR_ERR_OPERATION_FAILED,
2734 _("failed to format image: '%s'"), NULLSTR(job->errmsg));
2735 }
2736 goto cleanup;
2737 }
2738
2739 ret = 0;
2740
2741 cleanup:
2742 qemuBlockJobStartupFinalize(vm, job);
2743 return ret;
2744 }
2745
2746
2747 static int
qemuBlockStorageSourceCreateStorage(virDomainObj * vm,virStorageSource * src,virStorageSource * chain,qemuDomainAsyncJob asyncJob)2748 qemuBlockStorageSourceCreateStorage(virDomainObj *vm,
2749 virStorageSource *src,
2750 virStorageSource *chain,
2751 qemuDomainAsyncJob asyncJob)
2752 {
2753 int actualType = virStorageSourceGetActualType(src);
2754 g_autoptr(virJSONValue) createstorageprops = NULL;
2755 int ret;
2756
2757 /* We create local files directly to be able to apply security labels
2758 * properly. This is enough for formats which store the capacity of the image
2759 * in the metadata as they will grow. We must create a correctly sized
2760 * image for 'raw' and 'luks' though as the image size influences the
2761 * capacity.
2762 */
2763 if (actualType != VIR_STORAGE_TYPE_NETWORK &&
2764 !(actualType == VIR_STORAGE_TYPE_FILE && src->format == VIR_STORAGE_FILE_RAW))
2765 return 0;
2766
2767 if (qemuBlockStorageSourceCreateGetStorageProps(src, &createstorageprops) < 0)
2768 return -1;
2769
2770 if (!createstorageprops) {
2771 /* we can always try opening it to see whether it was existing */
2772 return 0;
2773 }
2774
2775 ret = qemuBlockStorageSourceCreateGeneric(vm, createstorageprops, src, chain,
2776 true, asyncJob);
2777 createstorageprops = NULL;
2778
2779 return ret;
2780 }
2781
2782
2783 static int
qemuBlockStorageSourceCreateFormat(virDomainObj * vm,virStorageSource * src,virStorageSource * backingStore,virStorageSource * chain,qemuDomainAsyncJob asyncJob)2784 qemuBlockStorageSourceCreateFormat(virDomainObj *vm,
2785 virStorageSource *src,
2786 virStorageSource *backingStore,
2787 virStorageSource *chain,
2788 qemuDomainAsyncJob asyncJob)
2789 {
2790 g_autoptr(virJSONValue) createformatprops = NULL;
2791 int ret;
2792
2793 if (src->format == VIR_STORAGE_FILE_RAW &&
2794 !src->encryption)
2795 return 0;
2796
2797 if (qemuBlockStorageSourceCreateGetFormatProps(src, backingStore,
2798 &createformatprops) < 0)
2799 return -1;
2800
2801 if (!createformatprops) {
2802 virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
2803 _("can't create storage format '%s'"),
2804 virStorageFileFormatTypeToString(src->format));
2805 return -1;
2806 }
2807
2808 ret = qemuBlockStorageSourceCreateGeneric(vm, createformatprops, src, chain,
2809 false, asyncJob);
2810 createformatprops = NULL;
2811
2812 return ret;
2813 }
2814
2815
2816 /**
2817 * qemuBlockStorageSourceCreate:
2818 * @vm: domain object
2819 * @src: storage source definition to create
2820 * @backingStore: backingStore of the new image (used only in image metadata)
2821 * @chain: backing chain to unplug in case of a long-running job failure
2822 * @data: qemuBlockStorageSourceAttachData for @src so that it can be attached
2823 * @asyncJob: qemu asynchronous job type
2824 *
2825 * Creates and formats a storage volume according to @src and attaches it to @vm.
2826 * @data must provide attachment data as if @src was existing. @src is attached
2827 * after successful return of this function. If libvirtd is restarted during
2828 * the create job @chain is unplugged, otherwise it's left for the caller.
2829 * If @backingStore is provided, the new image will refer to it as its backing
2830 * store.
2831 */
2832 int
qemuBlockStorageSourceCreate(virDomainObj * vm,virStorageSource * src,virStorageSource * backingStore,virStorageSource * chain,qemuBlockStorageSourceAttachData * data,qemuDomainAsyncJob asyncJob)2833 qemuBlockStorageSourceCreate(virDomainObj *vm,
2834 virStorageSource *src,
2835 virStorageSource *backingStore,
2836 virStorageSource *chain,
2837 qemuBlockStorageSourceAttachData *data,
2838 qemuDomainAsyncJob asyncJob)
2839 {
2840 qemuDomainObjPrivate *priv = vm->privateData;
2841 int ret = -1;
2842 int rc;
2843
2844 if (src->sliceStorage) {
2845 virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
2846 _("creation of images with slice type='storage' is not supported"));
2847 return -1;
2848 }
2849
2850 /* grant write access to read-only images during formatting */
2851 if (src->readonly &&
2852 qemuDomainStorageSourceAccessAllow(priv->driver, vm, src, false,
2853 false, true) < 0)
2854 return -1;
2855
2856 if (qemuDomainObjEnterMonitorAsync(priv->driver, vm, asyncJob) < 0)
2857 goto cleanup;
2858
2859 rc = qemuBlockStorageSourceAttachApplyStorageDeps(priv->mon, data);
2860
2861 if (qemuDomainObjExitMonitor(priv->driver, vm) < 0 || rc < 0)
2862 goto cleanup;
2863
2864 if (qemuBlockStorageSourceCreateStorage(vm, src, chain, asyncJob) < 0)
2865 goto cleanup;
2866
2867 if (qemuDomainObjEnterMonitorAsync(priv->driver, vm, asyncJob) < 0)
2868 goto cleanup;
2869
2870 rc = qemuBlockStorageSourceAttachApplyStorage(priv->mon, data);
2871
2872 if (rc == 0)
2873 rc = qemuBlockStorageSourceAttachApplyFormatDeps(priv->mon, data);
2874
2875 if (qemuDomainObjExitMonitor(priv->driver, vm) < 0 || rc < 0)
2876 goto cleanup;
2877
2878 if (qemuBlockStorageSourceCreateFormat(vm, src, backingStore, chain,
2879 asyncJob) < 0)
2880 goto cleanup;
2881
2882 /* revoke write access to read-only images during formatting */
2883 if (src->readonly &&
2884 qemuDomainStorageSourceAccessAllow(priv->driver, vm, src, true,
2885 false, true) < 0)
2886 goto cleanup;
2887
2888 if (qemuDomainObjEnterMonitorAsync(priv->driver, vm, asyncJob) < 0)
2889 goto cleanup;
2890
2891 rc = qemuBlockStorageSourceAttachApplyFormat(priv->mon, data);
2892
2893 if (qemuDomainObjExitMonitor(priv->driver, vm) < 0 || rc < 0)
2894 goto cleanup;
2895
2896 ret = 0;
2897
2898 cleanup:
2899 if (ret < 0 &&
2900 virDomainObjIsActive(vm) &&
2901 qemuDomainObjEnterMonitorAsync(priv->driver, vm, asyncJob) == 0) {
2902
2903 qemuBlockStorageSourceAttachRollback(priv->mon, data);
2904 ignore_value(qemuDomainObjExitMonitor(priv->driver, vm));
2905 }
2906
2907 return ret;
2908 }
2909
2910
2911 /**
2912 * qemuBlockStorageSourceCreateDetectSize:
2913 * @blockNamedNodeData: hash table filled with qemuBlockNamedNodeData
2914 * @src: storage source to update size/capacity on
2915 * @templ: storage source template
2916 *
2917 * When creating a storage source via blockdev-create we need to know the size
2918 * and capacity of the original volume (e.g. when creating a snapshot or copy).
2919 * This function updates @src's 'capacity' and 'physical' attributes according
2920 * to the detected sizes from @templ.
2921 */
2922 int
qemuBlockStorageSourceCreateDetectSize(GHashTable * blockNamedNodeData,virStorageSource * src,virStorageSource * templ)2923 qemuBlockStorageSourceCreateDetectSize(GHashTable *blockNamedNodeData,
2924 virStorageSource *src,
2925 virStorageSource *templ)
2926 {
2927 qemuBlockNamedNodeData *entry;
2928
2929 if (!(entry = virHashLookup(blockNamedNodeData, templ->nodeformat))) {
2930 virReportError(VIR_ERR_INTERNAL_ERROR,
2931 _("failed to update capacity data for block node '%s'"),
2932 templ->nodeformat);
2933 return -1;
2934 }
2935
2936 /* propagate cluster size if the images are compatible */
2937 if (templ->format == VIR_STORAGE_FILE_QCOW2 &&
2938 src->format == VIR_STORAGE_FILE_QCOW2 &&
2939 src->clusterSize == 0)
2940 src->clusterSize = entry->clusterSize;
2941
2942 if (src->format == VIR_STORAGE_FILE_RAW) {
2943 src->physical = entry->capacity;
2944 } else {
2945 src->physical = entry->physical;
2946 }
2947
2948 src->capacity = entry->capacity;
2949
2950 return 0;
2951 }
2952
2953
2954 int
qemuBlockRemoveImageMetadata(virQEMUDriver * driver,virDomainObj * vm,const char * diskTarget,virStorageSource * src)2955 qemuBlockRemoveImageMetadata(virQEMUDriver *driver,
2956 virDomainObj *vm,
2957 const char *diskTarget,
2958 virStorageSource *src)
2959 {
2960 virStorageSource *n;
2961 int ret = 0;
2962
2963 for (n = src; virStorageSourceIsBacking(n); n = n->backingStore) {
2964 if (qemuSecurityMoveImageMetadata(driver, vm, n, NULL) < 0) {
2965 VIR_WARN("Unable to remove disk metadata on "
2966 "vm %s from %s (disk target %s)",
2967 vm->def->name,
2968 NULLSTR(n->path),
2969 diskTarget);
2970 ret = -1;
2971 }
2972 }
2973
2974 return ret;
2975 }
2976
2977
2978 /**
2979 * qemuBlockNamedNodeDataGetBitmapByName:
2980 * @blockNamedNodeData: hash table returned by qemuMonitorBlockGetNamedNodeData
2981 * @src: disk source to find the bitmap for
2982 * @bitmap: name of the bitmap to find
2983 *
2984 * Looks up a bitmap named @bitmap of the @src image.
2985 */
2986 qemuBlockNamedNodeDataBitmap *
qemuBlockNamedNodeDataGetBitmapByName(GHashTable * blockNamedNodeData,virStorageSource * src,const char * bitmap)2987 qemuBlockNamedNodeDataGetBitmapByName(GHashTable *blockNamedNodeData,
2988 virStorageSource *src,
2989 const char *bitmap)
2990 {
2991 qemuBlockNamedNodeData *nodedata;
2992 size_t i;
2993
2994 if (!(nodedata = virHashLookup(blockNamedNodeData, src->nodeformat)))
2995 return NULL;
2996
2997 for (i = 0; i < nodedata->nbitmaps; i++) {
2998 qemuBlockNamedNodeDataBitmap *bitmapdata = nodedata->bitmaps[i];
2999
3000 if (STRNEQ(bitmapdata->name, bitmap))
3001 continue;
3002
3003 return bitmapdata;
3004 }
3005
3006 return NULL;
3007 }
3008
3009
3010 GHashTable *
qemuBlockGetNamedNodeData(virDomainObj * vm,qemuDomainAsyncJob asyncJob)3011 qemuBlockGetNamedNodeData(virDomainObj *vm,
3012 qemuDomainAsyncJob asyncJob)
3013 {
3014 qemuDomainObjPrivate *priv = vm->privateData;
3015 virQEMUDriver *driver = priv->driver;
3016 g_autoptr(GHashTable) blockNamedNodeData = NULL;
3017 bool supports_flat = virQEMUCapsGet(priv->qemuCaps,
3018 QEMU_CAPS_QMP_QUERY_NAMED_BLOCK_NODES_FLAT);
3019
3020 if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
3021 return NULL;
3022
3023 blockNamedNodeData = qemuMonitorBlockGetNamedNodeData(priv->mon, supports_flat);
3024
3025 if (qemuDomainObjExitMonitor(driver, vm) < 0 || !blockNamedNodeData)
3026 return NULL;
3027
3028 return g_steal_pointer(&blockNamedNodeData);
3029 }
3030
3031
3032 /**
3033 * qemuBlockGetBitmapMergeActionsGetBitmaps:
3034 *
3035 * Collect a list of bitmaps which need to be handled in
3036 * qemuBlockGetBitmapMergeActions. The list contains only valid bitmaps in the
3037 * sub-chain which is being processed.
3038 *
3039 * Note that the returned GSList contains bitmap names string pointers borrowed
3040 * from @blockNamedNodeData so they must not be freed.
3041 */
3042 static GSList *
qemuBlockGetBitmapMergeActionsGetBitmaps(virStorageSource * topsrc,const char * bitmapname,GHashTable * blockNamedNodeData)3043 qemuBlockGetBitmapMergeActionsGetBitmaps(virStorageSource *topsrc,
3044 const char *bitmapname,
3045 GHashTable *blockNamedNodeData)
3046 {
3047 g_autoptr(GSList) ret = NULL;
3048 qemuBlockNamedNodeData *entry;
3049 size_t i;
3050
3051 /* for now it doesn't make sense to consider bitmaps which are not present
3052 * in @topsrc as we can't recreate a bitmap for a layer if it's missing */
3053
3054 if (!(entry = virHashLookup(blockNamedNodeData, topsrc->nodeformat)))
3055 return NULL;
3056
3057 for (i = 0; i < entry->nbitmaps; i++) {
3058 qemuBlockNamedNodeDataBitmap *bitmap = entry->bitmaps[i];
3059
3060 if (bitmapname &&
3061 STRNEQ(bitmapname, bitmap->name))
3062 continue;
3063
3064 if (!qemuBlockBitmapChainIsValid(topsrc, bitmap->name, blockNamedNodeData))
3065 continue;
3066
3067 ret = g_slist_prepend(ret, bitmap->name);
3068 }
3069
3070 return g_steal_pointer(&ret);
3071 }
3072
3073
3074 /**
3075 * qemuBlockGetBitmapMergeActions:
3076 * @topsrc: top of the chain to merge bitmaps in
3077 * @basesrc: bottom of the chain to merge bitmaps in (NULL for full chain)
3078 * @target: destination storage source of the merge (may be part of original chain)
3079 * @bitmapname: name of bitmap to perform the merge (NULL for all bitmaps)
3080 * @dstbitmapname: name of destination bitmap of the merge (see below for caveats)
3081 * @writebitmapsrc: storage source corresponding to the node containing the write temporary bitmap
3082 * @actions: returns actions for a 'transaction' QMP command for executing the merge
3083 * @blockNamedNodeData: hash table filled with qemuBlockNamedNodeData
3084 *
3085 * Calculate handling of dirty block bitmaps between @topsrc and @basesrc. If
3086 * @basesrc is NULL the end of the chain is considered. @target is the destination
3087 * storage source definition of the merge and may or may not be part of the
3088 * merged chain.
3089 *
3090 * Specifically the merging algorithm ensures that each considered bitmap is
3091 * merged with the appropriate bitmaps so that it properly describes
3092 * the state of dirty blocks when looked at from @topsrc based on the depth
3093 * of the backing chain where the bitmap is placed.
3094 *
3095 * If @bitmapname is non-NULL only bitmaps with that name are handled, otherwise
3096 * all bitmaps are considered.
3097 *
3098 * If @dstbitmap is non-NULL everything is merged into a bitmap with that name,
3099 * otherwise each bitmap is merged into a bitmap with the same name into @target.
3100 * Additionally if @dstbitmap is non-NULL the target bitmap is created as 'inactive'
3101 * and 'transient' as a special case for the backup operation.
3102 *
3103 * If @writebitmapsrc is non-NULL, the 'libvirt-tmp-activewrite' bitmap from
3104 * given node is merged along with others. This bitmap corresponds to the writes
3105 * which occurred between an active layer job finished and the rest of the bitmap
3106 * merging.
3107 *
3108 * If the bitmap is not valid somehow (see qemuBlockBitmapChainIsValid) given
3109 * bitmap is silently skipped, so callers must ensure that given bitmap is valid
3110 * if they care about it.
3111 *
3112 * The resulting 'transaction' QMP command actions are filled in and returned via
3113 * @actions.
3114 *
3115 * Note that @actions may be NULL if no merging is required.
3116 */
3117 int
qemuBlockGetBitmapMergeActions(virStorageSource * topsrc,virStorageSource * basesrc,virStorageSource * target,const char * bitmapname,const char * dstbitmapname,virStorageSource * writebitmapsrc,virJSONValue ** actions,GHashTable * blockNamedNodeData)3118 qemuBlockGetBitmapMergeActions(virStorageSource *topsrc,
3119 virStorageSource *basesrc,
3120 virStorageSource *target,
3121 const char *bitmapname,
3122 const char *dstbitmapname,
3123 virStorageSource *writebitmapsrc,
3124 virJSONValue **actions,
3125 GHashTable *blockNamedNodeData)
3126 {
3127 g_autoptr(virJSONValue) act = virJSONValueNewArray();
3128 virStorageSource *n;
3129
3130 g_autoptr(GSList) bitmaps = NULL;
3131 GSList *next;
3132
3133 if (!(bitmaps = qemuBlockGetBitmapMergeActionsGetBitmaps(topsrc, bitmapname,
3134 blockNamedNodeData)))
3135 goto done;
3136
3137 for (next = bitmaps; next; next = next->next) {
3138 const char *curbitmap = next->data;
3139 const char *mergebitmapname = dstbitmapname;
3140 bool mergebitmappersistent = false;
3141 bool mergebitmapdisabled = true;
3142 g_autoptr(virJSONValue) merge = virJSONValueNewArray();
3143 unsigned long long granularity = 0;
3144 qemuBlockNamedNodeDataBitmap *bitmap;
3145
3146 /* explicitly named destinations mean that we want a temporary
3147 * disabled bitmap only, so undo the default for non-explicit cases */
3148 if (!mergebitmapname) {
3149 mergebitmapname = curbitmap;
3150 mergebitmappersistent = true;
3151 mergebitmapdisabled = false;
3152 }
3153
3154 for (n = topsrc; virStorageSourceIsBacking(n) && n != basesrc; n = n->backingStore) {
3155 if (!(bitmap = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData,
3156 n, curbitmap)))
3157 continue;
3158
3159 if (granularity == 0)
3160 granularity = bitmap->granularity;
3161
3162 if (qemuMonitorTransactionBitmapMergeSourceAddBitmap(merge,
3163 n->nodeformat,
3164 bitmap->name) < 0)
3165 return -1;
3166 }
3167
3168 if (dstbitmapname ||
3169 !(bitmap = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData,
3170 target, curbitmap))) {
3171
3172 if (qemuMonitorTransactionBitmapAdd(act,
3173 target->nodeformat,
3174 mergebitmapname,
3175 mergebitmappersistent,
3176 mergebitmapdisabled,
3177 granularity) < 0)
3178 return -1;
3179 }
3180
3181 if (writebitmapsrc &&
3182 qemuMonitorTransactionBitmapMergeSourceAddBitmap(merge,
3183 writebitmapsrc->nodeformat,
3184 "libvirt-tmp-activewrite") < 0)
3185 return -1;
3186
3187 if (qemuMonitorTransactionBitmapMerge(act, target->nodeformat,
3188 mergebitmapname, &merge) < 0)
3189 return -1;
3190 }
3191
3192 done:
3193 if (writebitmapsrc &&
3194 qemuMonitorTransactionBitmapRemove(act, writebitmapsrc->nodeformat,
3195 "libvirt-tmp-activewrite") < 0)
3196 return -1;
3197
3198 if (virJSONValueArraySize(act) > 0)
3199 *actions = g_steal_pointer(&act);
3200
3201 return 0;
3202 }
3203
3204
3205 /**
3206 * qemuBlockBitmapChainIsValid:
3207 *
3208 * Validates that the backing chain of @src contains bitmaps which libvirt will
3209 * consider as properly corresponding to a checkpoint named @bitmapname.
3210 *
3211 * The bitmaps need to:
3212 * 1) start from the top image @src
3213 * 2) must be present in consecutive layers
3214 * 3) all must be active, persistent and not inconsistent
3215 */
3216 bool
qemuBlockBitmapChainIsValid(virStorageSource * src,const char * bitmapname,GHashTable * blockNamedNodeData)3217 qemuBlockBitmapChainIsValid(virStorageSource *src,
3218 const char *bitmapname,
3219 GHashTable *blockNamedNodeData)
3220 {
3221 virStorageSource *n;
3222 bool found = false;
3223 bool chain_ended = false;
3224
3225 for (n = src; virStorageSourceIsBacking(n); n = n->backingStore) {
3226 qemuBlockNamedNodeDataBitmap *bitmap;
3227
3228 if (!(bitmap = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData,
3229 n, bitmapname))) {
3230 /* rule 1, must start from top */
3231 if (!found)
3232 return false;
3233
3234 chain_ended = true;
3235
3236 continue;
3237 }
3238
3239 /* rule 2, no-gaps */
3240 if (chain_ended)
3241 return false;
3242
3243 /* rule 3 */
3244 if (bitmap->inconsistent || !bitmap->persistent || !bitmap->recording)
3245 return false;
3246
3247 found = true;
3248 }
3249
3250 return found;
3251 }
3252
3253
3254 /**
3255 * qemuBlockBitmapsHandleBlockcopy:
3256 * @src: disk source
3257 * @mirror: mirror source
3258 * @blockNamedNodeData: hash table containing data about bitmaps
3259 * @shallow: whether shallow copy is requested
3260 * @actions: filled with arguments for a 'transaction' command
3261 *
3262 * Calculates which bitmaps to copy and merge during a virDomainBlockCopy job.
3263 * This is designed to be called when the job is already synchronised as it
3264 * may result in active bitmaps being created.
3265 *
3266 * Returns 0 on success and -1 on error. If @actions is NULL when 0 is returned
3267 * there are no actions to perform for the given job.
3268 */
3269 int
qemuBlockBitmapsHandleBlockcopy(virStorageSource * src,virStorageSource * mirror,GHashTable * blockNamedNodeData,bool shallow,virJSONValue ** actions)3270 qemuBlockBitmapsHandleBlockcopy(virStorageSource *src,
3271 virStorageSource *mirror,
3272 GHashTable *blockNamedNodeData,
3273 bool shallow,
3274 virJSONValue **actions)
3275 {
3276 virStorageSource *base = NULL;
3277
3278 if (shallow)
3279 base = src->backingStore;
3280
3281 if (qemuBlockGetBitmapMergeActions(src, base, mirror, NULL, NULL, mirror, actions,
3282 blockNamedNodeData) < 0)
3283 return -1;
3284
3285 return 0;
3286 }
3287
3288
3289 /**
3290 * @topsrc: virStorageSource representing 'top' of the job
3291 * @basesrc: virStorageSource representing 'base' of the job
3292 * @active: commit job is an active layer block-commit
3293 * @blockNamedNodeData: hash table containing data about bitmaps
3294 * @actions: filled with arguments for a 'transaction' command
3295 * @disabledBitmapsBase: bitmap names which were disabled
3296 *
3297 * Calculates the necessary bitmap merges/additions/enablements to properly
3298 * handle commit of images from 'top' into 'base'. The necessary operations
3299 * in the form of arguments of the 'transaction' command are filled into
3300 * 'actions' if there is anything to do. Otherwise NULL is returned.
3301 */
3302 int
qemuBlockBitmapsHandleCommitFinish(virStorageSource * topsrc,virStorageSource * basesrc,bool active,GHashTable * blockNamedNodeData,virJSONValue ** actions)3303 qemuBlockBitmapsHandleCommitFinish(virStorageSource *topsrc,
3304 virStorageSource *basesrc,
3305 bool active,
3306 GHashTable *blockNamedNodeData,
3307 virJSONValue **actions)
3308 {
3309 virStorageSource *writebitmapsrc = NULL;
3310
3311 if (active)
3312 writebitmapsrc = basesrc;
3313
3314 if (qemuBlockGetBitmapMergeActions(topsrc, basesrc, basesrc, NULL, NULL,
3315 writebitmapsrc, actions,
3316 blockNamedNodeData) < 0)
3317 return -1;
3318
3319 return 0;
3320 }
3321
3322
3323 int
qemuBlockReopenFormatMon(qemuMonitor * mon,virStorageSource * src)3324 qemuBlockReopenFormatMon(qemuMonitor *mon,
3325 virStorageSource *src)
3326 {
3327 g_autoptr(virJSONValue) reopenprops = NULL;
3328 g_autoptr(virJSONValue) srcprops = NULL;
3329 g_autoptr(virJSONValue) reopenoptions = virJSONValueNewArray();
3330
3331 if (!(srcprops = qemuBlockStorageSourceGetBlockdevProps(src, src->backingStore)))
3332 return -1;
3333
3334 if (virJSONValueArrayAppend(reopenoptions, &srcprops) < 0)
3335 return -1;
3336
3337 if (virJSONValueObjectAdd(&reopenprops,
3338 "a:options", &reopenoptions,
3339 NULL) < 0)
3340 return -1;
3341
3342 if (qemuMonitorBlockdevReopen(mon, &reopenprops) < 0)
3343 return -1;
3344
3345 return 0;
3346 }
3347
3348
3349 /**
3350 * qemuBlockReopenFormat:
3351 * @vm: domain object
3352 * @src: storage source to reopen
3353 * @asyncJob: qemu async job type
3354 *
3355 * Invokes the 'blockdev-reopen' command on the format layer of @src. This means
3356 * that @src must be already properly configured for the desired outcome. The
3357 * nodenames of @src are used to identify the specific image in qemu.
3358 */
3359 static int
qemuBlockReopenFormat(virDomainObj * vm,virStorageSource * src,qemuDomainAsyncJob asyncJob)3360 qemuBlockReopenFormat(virDomainObj *vm,
3361 virStorageSource *src,
3362 qemuDomainAsyncJob asyncJob)
3363 {
3364 qemuDomainObjPrivate *priv = vm->privateData;
3365 virQEMUDriver *driver = priv->driver;
3366 int rc;
3367
3368 /* If we are lacking the object here, qemu might have opened an image with
3369 * a node name unknown to us */
3370 if (!src->backingStore) {
3371 virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3372 _("can't reopen image with unknown presence of backing store"));
3373 return -1;
3374 }
3375
3376 if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
3377 return -1;
3378
3379 rc = qemuBlockReopenFormatMon(priv->mon, src);
3380
3381 if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
3382 return -1;
3383
3384 return 0;
3385 }
3386
3387
3388 /**
3389 * qemuBlockReopenReadWrite:
3390 * @vm: domain object
3391 * @src: storage source to reopen
3392 * @asyncJob: qemu async job type
3393 *
3394 * Wrapper that reopens @src read-write. We currently depend on qemu
3395 * reopening the storage with 'auto-read-only' enabled for us.
3396 * After successful reopen @src's 'readonly' flag is modified. Does nothing
3397 * if @src is already read-write.
3398 */
3399 int
qemuBlockReopenReadWrite(virDomainObj * vm,virStorageSource * src,qemuDomainAsyncJob asyncJob)3400 qemuBlockReopenReadWrite(virDomainObj *vm,
3401 virStorageSource *src,
3402 qemuDomainAsyncJob asyncJob)
3403 {
3404 if (!src->readonly)
3405 return 0;
3406
3407 src->readonly = false;
3408 if (qemuBlockReopenFormat(vm, src, asyncJob) < 0) {
3409 src->readonly = true;
3410 return -1;
3411 }
3412
3413 return 0;
3414 }
3415
3416
3417 /**
3418 * qemuBlockReopenReadOnly:
3419 * @vm: domain object
3420 * @src: storage source to reopen
3421 * @asyncJob: qemu async job type
3422 *
3423 * Wrapper that reopens @src read-only. We currently depend on qemu
3424 * reopening the storage with 'auto-read-only' enabled for us.
3425 * After successful reopen @src's 'readonly' flag is modified. Does nothing
3426 * if @src is already read-only.
3427 */
3428 int
qemuBlockReopenReadOnly(virDomainObj * vm,virStorageSource * src,qemuDomainAsyncJob asyncJob)3429 qemuBlockReopenReadOnly(virDomainObj *vm,
3430 virStorageSource *src,
3431 qemuDomainAsyncJob asyncJob)
3432 {
3433 if (src->readonly)
3434 return 0;
3435
3436 src->readonly = true;
3437 if (qemuBlockReopenFormat(vm, src, asyncJob) < 0) {
3438 src->readonly = false;
3439 return -1;
3440 }
3441
3442 return 0;
3443 }
3444
3445 /**
3446 * qemuBlockStorageSourceNeedSliceLayer:
3447 * @src: source to inspect
3448 *
3449 * Returns true if @src requires an extra 'raw' layer for handling of the storage
3450 * slice.
3451 */
3452 bool
qemuBlockStorageSourceNeedsStorageSliceLayer(const virStorageSource * src)3453 qemuBlockStorageSourceNeedsStorageSliceLayer(const virStorageSource *src)
3454 {
3455 if (!src->sliceStorage)
3456 return false;
3457
3458 if (src->format != VIR_STORAGE_FILE_RAW)
3459 return true;
3460
3461 if (src->encryption &&
3462 src->encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS)
3463 return true;
3464
3465 return false;
3466 }
3467
3468
3469 /**
3470 * qemuBlockStorageSourceGetCookieString:
3471 * @src: storage source
3472 *
3473 * Returns a properly formatted string representing cookies of @src in format
3474 * accepted by qemu.
3475 */
3476 char *
qemuBlockStorageSourceGetCookieString(virStorageSource * src)3477 qemuBlockStorageSourceGetCookieString(virStorageSource *src)
3478 {
3479 g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
3480 size_t i;
3481
3482 for (i = 0; i < src->ncookies; i++) {
3483 virStorageNetCookieDef *cookie = src->cookies[i];
3484
3485 virBufferAsprintf(&buf, "%s=%s; ", cookie->name, cookie->value);
3486 }
3487
3488 virBufferTrim(&buf, "; ");
3489
3490 return virBufferContentAndReset(&buf);
3491 }
3492
3493
3494 /**
3495 * qemuBlockUpdateRelativeBacking:
3496 * @vm: domain object
3497 * @src: starting point of the update
3498 * @topsrc: top level image in the backing chain (used to get security label)
3499 *
3500 * Reload data necessary for keeping backing store links starting from @src
3501 * relative.
3502 */
3503 int
qemuBlockUpdateRelativeBacking(virDomainObj * vm,virStorageSource * src,virStorageSource * topsrc)3504 qemuBlockUpdateRelativeBacking(virDomainObj *vm,
3505 virStorageSource *src,
3506 virStorageSource *topsrc)
3507 {
3508 qemuDomainObjPrivate *priv = vm->privateData;
3509 virQEMUDriver *driver = priv->driver;
3510 virStorageSource *n;
3511
3512 for (n = src; virStorageSourceHasBacking(n); n = n->backingStore) {
3513 int rc;
3514
3515 if (n->backingStore->relPath)
3516 break;
3517
3518 if (!virStorageSourceSupportsBackingChainTraversal(n))
3519 continue;
3520
3521 if (qemuDomainStorageFileInit(driver, vm, n, topsrc) < 0)
3522 return -1;
3523
3524 rc = virStorageSourceFetchRelativeBackingPath(n, &n->backingStore->relPath);
3525
3526 virStorageSourceDeinit(n);
3527
3528 if (rc < 0)
3529 return rc;
3530 }
3531
3532 return 0;
3533 }
3534
3535
3536 virJSONValue *
qemuBlockExportGetNBDProps(const char * nodename,const char * exportname,bool writable,const char ** bitmaps)3537 qemuBlockExportGetNBDProps(const char *nodename,
3538 const char *exportname,
3539 bool writable,
3540 const char **bitmaps)
3541 {
3542 g_autofree char *exportid = NULL;
3543 g_autoptr(virJSONValue) bitmapsarr = NULL;
3544 virJSONValue *ret = NULL;
3545
3546 exportid = g_strdup_printf("libvirt-nbd-%s", nodename);
3547
3548 if (bitmaps && *bitmaps) {
3549 bitmapsarr = virJSONValueNewArray();
3550
3551 while (*bitmaps) {
3552 if (virJSONValueArrayAppendString(bitmapsarr, *(bitmaps++)) < 0)
3553 return NULL;
3554 }
3555 }
3556
3557 if (virJSONValueObjectAdd(&ret,
3558 "s:type", "nbd",
3559 "s:id", exportid,
3560 "s:node-name", nodename,
3561 "b:writable", writable,
3562 "s:name", exportname,
3563 "A:bitmaps", &bitmapsarr,
3564 NULL) < 0)
3565 return NULL;
3566
3567 return ret;
3568 }
3569
3570
3571 /**
3572 * qemuBlockExportAddNBD:
3573 * @vm: domain object
3574 * @drivealias: (optional) alias of -drive to export in pre-blockdev configurations
3575 * @src: disk source to export
3576 * @exportname: name for the export
3577 * @writable: whether the NBD export allows writes
3578 * @bitmap: (optional) block dirty bitmap to export along
3579 *
3580 * This function automatically selects the proper invocation of exporting a
3581 * block backend via NBD in qemu. This includes use of nodename for blockdev
3582 * and proper configuration for the exportname for older qemus.
3583 *
3584 * This function must be called while in the monitor context.
3585 */
3586 int
qemuBlockExportAddNBD(virDomainObj * vm,const char * drivealias,virStorageSource * src,const char * exportname,bool writable,const char * bitmap)3587 qemuBlockExportAddNBD(virDomainObj *vm,
3588 const char *drivealias,
3589 virStorageSource *src,
3590 const char *exportname,
3591 bool writable,
3592 const char *bitmap)
3593 {
3594 qemuDomainObjPrivate *priv = vm->privateData;
3595 g_autoptr(virJSONValue) nbdprops = NULL;
3596 const char *bitmaps[2] = { bitmap, NULL };
3597
3598 /* older qemu versions didn't support configuring the exportname and
3599 * took the 'drivealias' as the export name */
3600 if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV))
3601 return qemuMonitorNBDServerAdd(priv->mon, drivealias, NULL, writable, NULL);
3602
3603 if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCK_EXPORT_ADD))
3604 return qemuMonitorNBDServerAdd(priv->mon, src->nodeformat,
3605 exportname, writable, bitmap);
3606
3607 if (!(nbdprops = qemuBlockExportGetNBDProps(src->nodeformat, exportname,
3608 writable, bitmaps)))
3609 return -1;
3610
3611 return qemuMonitorBlockExportAdd(priv->mon, &nbdprops);
3612 }
3613