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