It will be needed for the futur patches because we will redefine snapshots --- src/conf/domain_conf.c | 20 ++- src/vbox/vbox_tmpl.c | 427 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 427 insertions(+), 20 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f1623f1..c98ff63 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -16810,15 +16810,17 @@ virDomainDefFormatInternal(virDomainDefPtr def, if (virDomainChrDefFormat(buf, &console, flags) < 0) goto error; } - if (STREQ(def->os.type, "hvm") && - def->nconsoles == 0 && - def->nserials > 0) { - virDomainChrDef console; - memcpy(&console, def->serials[n], sizeof(console)); - console.deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE; - console.targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL; - if (virDomainChrDefFormat(buf, &console, flags) < 0) - goto error; + if (def->os.type) { + if (STREQ(def->os.type, "hvm") && + def->nconsoles == 0 && + def->nserials > 0) { + virDomainChrDef console; + memcpy(&console, def->serials[n], sizeof(console)); + console.deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE; + console.targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL; + if (virDomainChrDefFormat(buf, &console, flags) < 0) + goto error; + } } for (n = 0; n < def->nchannels; n++) diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c index 5e5ea85..ded179f 100644 --- a/src/vbox/vbox_tmpl.c +++ b/src/vbox/vbox_tmpl.c @@ -38,6 +38,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> +#include <libxml/xmlwriter.h> #include "internal.h" #include "datatypes.h" @@ -58,6 +59,8 @@ #include "fdstream.h" #include "viruri.h" #include "virstring.h" +#include "virtime.h" +#include "virutil.h" /* This one changes from version to version. */ #if VBOX_API_VERSION == 2002 @@ -271,10 +274,16 @@ static vboxGlobalData *g_pVBoxGlobalData = NULL; #endif /* VBOX_API_VERSION >= 4000 */ +#define reportInternalErrorIfNS_FAILED(message) \ + if (NS_FAILED(rc)) { \ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _(message)); \ + goto cleanup; \ + } + + static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml); static int vboxDomainCreate(virDomainPtr dom); static int vboxDomainUndefineFlags(virDomainPtr dom, unsigned int flags); - static void vboxDriverLock(vboxGlobalData *data) { virMutexLock(&data->lock); } @@ -283,6 +292,12 @@ static void vboxDriverUnlock(vboxGlobalData *data) { virMutexUnlock(&data->lock); } +typedef enum { + VBOX_STORAGE_DELETE_FLAG = 0, +#if VBOX_API_VERSION >= 4002 + VBOX_STORAGE_CLOSE_FLAG = 1, +#endif +} vboxStorageDeleteOrCloseFlags; #if VBOX_API_VERSION == 2002 static void nsIDtoChar(unsigned char *uuid, const nsID *iid) { @@ -5907,7 +5922,8 @@ vboxDomainSnapshotCreateXML(virDomainPtr dom, virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL); if (!(def = virDomainSnapshotDefParseString(xmlDesc, data->caps, - data->xmlopt, 0, 0))) + data->xmlopt, -1, VIR_DOMAIN_SNAPSHOT_PARSE_DISKS | + VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE))) goto cleanup; if (def->ndisks) { @@ -5915,7 +5931,6 @@ vboxDomainSnapshotCreateXML(virDomainPtr dom, _("disk snapshots not supported yet")); goto cleanup; } - vboxIIDFromUUID(&domiid, dom->uuid); rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine); if (NS_FAILED(rc)) { @@ -5923,7 +5938,6 @@ vboxDomainSnapshotCreateXML(virDomainPtr dom, _("no domain with matching UUID")); goto cleanup; } - rc = machine->vtbl->GetState(machine, &state); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -5998,6 +6012,344 @@ cleanup: return ret; } +#if VBOX_API_VERSION >=4002 +static +int vboxSnapshotGetReadWriteDisks(virDomainSnapshotDefPtr def, + virDomainSnapshotPtr snapshot) +{ + virDomainPtr dom = snapshot->domain; + VBOX_OBJECT_CHECK(dom->conn, int, -1); + vboxIID domiid = VBOX_IID_INITIALIZER; + IMachine *machine = NULL; + ISnapshot *snap = NULL; + IMachine *snapMachine = NULL; + bool error = false; + vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER; + PRUint32 maxPortPerInst[StorageBus_Floppy + 1] = {}; + PRUint32 maxSlotPerPort[StorageBus_Floppy + 1] = {}; + int diskCount = 0; + nsresult rc; + vboxIID snapIid = VBOX_IID_INITIALIZER; + char *snapshotUuidStr = NULL; + size_t i = 0; + vboxIIDFromUUID(&domiid, dom->uuid); + rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine); + reportInternalErrorIfNS_FAILED("no domain with matching UUID"); + if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name))) { + ret = -1; + goto cleanup; + } + rc = snap->vtbl->GetId(snap, &snapIid.value); + reportInternalErrorIfNS_FAILED("Could not get snapshot id"); + + VBOX_UTF16_TO_UTF8(snapIid.value, &snapshotUuidStr); + rc = snap->vtbl->GetMachine(snap, &snapMachine); + reportInternalErrorIfNS_FAILED("could not get machine"); + def->ndisks = 0; + rc = vboxArrayGet(&mediumAttachments, snapMachine, snapMachine->vtbl->GetMediumAttachments); + reportInternalErrorIfNS_FAILED("no medium attachments"); + /* get the number of attachments */ + for (i = 0; i < mediumAttachments.count; i++) { + IMediumAttachment *imediumattach = mediumAttachments.items[i]; + if (imediumattach) { + IMedium *medium = NULL; + + rc = imediumattach->vtbl->GetMedium(imediumattach, &medium); + reportInternalErrorIfNS_FAILED("cannot get medium"); + if (medium) { + def->ndisks++; + VBOX_RELEASE(medium); + } + } + } + /* Allocate mem, if fails return error */ + if (VIR_ALLOC_N(def->disks, def->ndisks) < 0) { + virReportOOMError(); + error = true; + } + if (!error) + error = !vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst, maxSlotPerPort); + + /* get the attachment details here */ + for (i = 0; i < mediumAttachments.count && diskCount < def->ndisks && !error; i++) { + IStorageController *storageController = NULL; + PRUnichar *storageControllerName = NULL; + PRUint32 deviceType = DeviceType_Null; + PRUint32 storageBus = StorageBus_Null; + IMedium *disk = NULL; + PRUnichar *childLocUtf16 = NULL; + char *childLocUtf8 = NULL; + PRUint32 deviceInst = 0; + PRInt32 devicePort = 0; + PRInt32 deviceSlot = 0; + vboxArray children = VBOX_ARRAY_INITIALIZER; + vboxArray snapshotIids = VBOX_ARRAY_INITIALIZER; + IMediumAttachment *imediumattach = mediumAttachments.items[i]; + size_t j = 0; + size_t k = 0; + if (!imediumattach) + continue; + rc = imediumattach->vtbl->GetMedium(imediumattach, &disk); + reportInternalErrorIfNS_FAILED("cannot get medium"); + if (!disk) + continue; + rc = imediumattach->vtbl->GetController(imediumattach, &storageControllerName); + reportInternalErrorIfNS_FAILED("cannot get medium"); + if (!storageControllerName) { + VBOX_RELEASE(disk); + continue; + } + rc= vboxArrayGet(&children, disk, disk->vtbl->GetChildren); + reportInternalErrorIfNS_FAILED("cannot get children disk"); + rc = vboxArrayGetWithPtrArg(&snapshotIids, disk, disk->vtbl->GetSnapshotIds, domiid.value); + reportInternalErrorIfNS_FAILED("cannot get snapshot ids"); + for (j = 0; j < children.count; ++j) { + IMedium *child = children.items[j]; + for (k = 0; k < snapshotIids.count; ++k) { + PRUnichar *diskSnapId = snapshotIids.items[k]; + char *diskSnapIdStr = NULL; + VBOX_UTF16_TO_UTF8(diskSnapId, &diskSnapIdStr); + if (STREQ(diskSnapIdStr, snapshotUuidStr)) { + rc = machine->vtbl->GetStorageControllerByName(machine, + storageControllerName, + &storageController); + VBOX_UTF16_FREE(storageControllerName); + if (!storageController) { + VBOX_RELEASE(child); + break; + } + rc = child->vtbl->GetLocation(child, &childLocUtf16); + reportInternalErrorIfNS_FAILED("cannot get disk location"); + VBOX_UTF16_TO_UTF8(childLocUtf16, &childLocUtf8); + VBOX_UTF16_FREE(childLocUtf16); + ignore_value(VIR_STRDUP(def->disks[diskCount].file, childLocUtf8)); + if (!(def->disks[diskCount].file)) { + VBOX_RELEASE(child); + VBOX_RELEASE(storageController); + virReportOOMError(); + error = true; + break; + } + VBOX_UTF8_FREE(childLocUtf8); + + rc = storageController->vtbl->GetBus(storageController, &storageBus); + reportInternalErrorIfNS_FAILED("cannot get storage controller bus"); + rc = imediumattach->vtbl->GetType(imediumattach, &deviceType); + reportInternalErrorIfNS_FAILED("cannot get medium attachment type"); + rc = imediumattach->vtbl->GetPort(imediumattach, &devicePort); + reportInternalErrorIfNS_FAILED("cannot get medium attachchment type"); + rc = imediumattach->vtbl->GetDevice(imediumattach, &deviceSlot); + reportInternalErrorIfNS_FAILED("cannot get medium attachment device"); + def->disks[diskCount].name = vboxGenerateMediumName(storageBus, + deviceInst, + devicePort, + deviceSlot, + maxPortPerInst, + maxSlotPerPort); + } + VBOX_UTF8_FREE(diskSnapIdStr); + } + } + VBOX_RELEASE(storageController); + VBOX_RELEASE(disk); + diskCount++; + } + vboxArrayRelease(&mediumAttachments); + /* cleanup on error */ + if (error) { + for (i = 0; i < def->dom->ndisks; i++) { + VIR_FREE(def->dom->disks[i]); + } + VIR_FREE(def->dom->disks); + def->dom->ndisks = 0; + return -1; + } + return 0; + +cleanup: + VBOX_RELEASE(snap); + return ret; +} + +static +int vboxSnapshotGetReadOnlyDisks(virDomainSnapshotPtr snapshot, + virDomainSnapshotDefPtr def) +{ + virDomainPtr dom = snapshot->domain; + VBOX_OBJECT_CHECK(dom->conn, int, -1); + vboxIID domiid = VBOX_IID_INITIALIZER; + ISnapshot *snap = NULL; + IMachine *machine = NULL; + IMachine *snapMachine = NULL; + IStorageController *storageController = NULL; + IMedium *disk = NULL; + nsresult rc; + vboxIIDFromUUID(&domiid, dom->uuid); + bool error = false; + vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER; + size_t i = 0; + PRUint32 maxPortPerInst[StorageBus_Floppy + 1] = {}; + PRUint32 maxSlotPerPort[StorageBus_Floppy + 1] = {}; + int diskCount = 0; + rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine); + if (NS_FAILED(rc)) { + virReportError(VIR_ERR_NO_DOMAIN, "%s", + _("no domain with matching UUID")); + return -1; + } + + if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name))) + return -1; + rc = snap->vtbl->GetMachine(snap, &snapMachine); + reportInternalErrorIfNS_FAILED("cannot get machine"); + /* + * Get READ ONLY disks + * In the snapshot metadata, these are the disks written inside the <domain> node + */ + rc = vboxArrayGet(&mediumAttachments, snapMachine, snapMachine->vtbl->GetMediumAttachments); + reportInternalErrorIfNS_FAILED("cannot get medium attachments"); + /* get the number of attachments */ + for (i = 0; i < mediumAttachments.count; i++) { + IMediumAttachment *imediumattach = mediumAttachments.items[i]; + if (imediumattach) { + IMedium *medium = NULL; + + rc = imediumattach->vtbl->GetMedium(imediumattach, &medium); + reportInternalErrorIfNS_FAILED("cannot get medium"); + if (medium) { + def->dom->ndisks++; + VBOX_RELEASE(medium); + } + } + } + + /* Allocate mem, if fails return error */ + if (VIR_ALLOC_N(def->dom->disks, def->dom->ndisks) >= 0) { + for (i = 0; i < def->dom->ndisks; i++) { + if (VIR_ALLOC(def->dom->disks[i]) < 0) { + virReportOOMError(); + error = true; + break; + } + } + } else { + virReportOOMError(); + error = true; + } + + if (!error) + error = !vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst, maxSlotPerPort); + + /* get the attachment details here */ + for (i = 0; i < mediumAttachments.count && diskCount < def->dom->ndisks && !error; i++) { + PRUnichar *storageControllerName = NULL; + PRUint32 deviceType = DeviceType_Null; + PRUint32 storageBus = StorageBus_Null; + PRBool readOnly = PR_FALSE; + PRUnichar *mediumLocUtf16 = NULL; + char *mediumLocUtf8 = NULL; + PRUint32 deviceInst = 0; + PRInt32 devicePort = 0; + PRInt32 deviceSlot = 0; + IMediumAttachment *imediumattach = mediumAttachments.items[i]; + if (!imediumattach) + continue; + rc = imediumattach->vtbl->GetMedium(imediumattach, &disk); + reportInternalErrorIfNS_FAILED("cannot get medium"); + if (!disk) + continue; + rc = imediumattach->vtbl->GetController(imediumattach, &storageControllerName); + reportInternalErrorIfNS_FAILED("cannot get storage controller name"); + if (!storageControllerName) { + continue; + } + rc = machine->vtbl->GetStorageControllerByName(machine, + storageControllerName, + &storageController); + reportInternalErrorIfNS_FAILED("cannot get storage controller"); + VBOX_UTF16_FREE(storageControllerName); + if (!storageController) { + continue; + } + rc = disk->vtbl->GetLocation(disk, &mediumLocUtf16); + reportInternalErrorIfNS_FAILED("cannot get disk location"); + VBOX_UTF16_TO_UTF8(mediumLocUtf16, &mediumLocUtf8); + VBOX_UTF16_FREE(mediumLocUtf16); + ignore_value(VIR_STRDUP(def->dom->disks[diskCount]->src, mediumLocUtf8)); + + if (!(def->dom->disks[diskCount]->src)) { + virReportOOMError(); + ret = -1; + goto cleanup; + } + VBOX_UTF8_FREE(mediumLocUtf8); + + rc = storageController->vtbl->GetBus(storageController, &storageBus); + reportInternalErrorIfNS_FAILED("cannot get storage controller bus"); + if (storageBus == StorageBus_IDE) { + def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_IDE; + } else if (storageBus == StorageBus_SATA) { + def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SATA; + } else if (storageBus == StorageBus_SCSI) { + def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SCSI; + } else if (storageBus == StorageBus_Floppy) { + def->dom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_FDC; + } + + rc = imediumattach->vtbl->GetType(imediumattach, &deviceType); + reportInternalErrorIfNS_FAILED("cannot get medium attachment type"); + if (deviceType == DeviceType_HardDisk) + def->dom->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_DISK; + else if (deviceType == DeviceType_Floppy) + def->dom->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY; + else if (deviceType == DeviceType_DVD) + def->dom->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_CDROM; + + rc = imediumattach->vtbl->GetPort(imediumattach, &devicePort); + reportInternalErrorIfNS_FAILED("cannot get medium attachment port"); + rc = imediumattach->vtbl->GetDevice(imediumattach, &deviceSlot); + reportInternalErrorIfNS_FAILED("cannot get device"); + rc = disk->vtbl->GetReadOnly(disk, &readOnly); + reportInternalErrorIfNS_FAILED("cannot get read only attribute"); + if (readOnly == PR_TRUE) + def->dom->disks[diskCount]->readonly = true; + def->dom->disks[diskCount]->type = VIR_DOMAIN_DISK_TYPE_FILE; + def->dom->disks[diskCount]->dst = vboxGenerateMediumName(storageBus, + deviceInst, + devicePort, + deviceSlot, + maxPortPerInst, + maxSlotPerPort); + if (!def->dom->disks[diskCount]->dst) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not generate medium name for the disk " + "at: controller instance:%u, port:%d, slot:%d"), + deviceInst, devicePort, deviceSlot); + ret = -1; + goto cleanup; + } + diskCount ++; + } + /* cleanup on error */ + if (error) { + for (i = 0; i < def->dom->ndisks; i++) { + VIR_FREE(def->dom->disks[i]); + } + VIR_FREE(def->dom->disks); + def->dom->ndisks = 0; + ret = -1; + goto cleanup; + } + ret = 0; +cleanup: + VBOX_RELEASE(disk); + VBOX_RELEASE(storageController); + vboxArrayRelease(&mediumAttachments); + VBOX_RELEASE(snap); + return ret; +} +#endif + static char * vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot, unsigned int flags) @@ -6015,6 +6367,10 @@ vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot, PRInt64 timestamp; PRBool online = PR_FALSE; char uuidstr[VIR_UUID_STRING_BUFLEN]; +#if VBOX_API_VERSION >=4002 + PRUint32 memorySize = 0; + PRUint32 CPUCount = 0; +#endif virCheckFlags(0, NULL); @@ -6029,11 +6385,40 @@ vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot, if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name))) goto cleanup; - if (VIR_ALLOC(def) < 0) + if (VIR_ALLOC(def) < 0 + || VIR_ALLOC(def->dom) < 0) goto cleanup; if (VIR_STRDUP(def->name, snapshot->name) < 0) goto cleanup; +#if VBOX_API_VERSION >=4002 + /* Register def->dom properties for them to be saved inside the snapshot XMl + * Otherwise, there is a problem while parsing the xml + */ + def->dom->virtType = VIR_DOMAIN_VIRT_VBOX; + def->dom->id = dom->id; + memcpy(def->dom->uuid, dom->uuid, VIR_UUID_BUFLEN); + ignore_value(VIR_STRDUP(def->dom->name, dom->name)); + machine->vtbl->GetMemorySize(machine, &memorySize); + def->dom->mem.cur_balloon = memorySize * 1024; + /* Currently setting memory and maxMemory as same, cause + * the notation here seems to be inconsistent while + * reading and while dumping xml + */ + def->dom->mem.max_balloon = memorySize * 1024; + ignore_value(VIR_STRDUP(def->dom->os.type, "hvm")); + def->dom->os.arch = virArchFromHost(); + machine->vtbl->GetCPUCount(machine, &CPUCount); + def->dom->maxvcpus = def->dom->vcpus = CPUCount; + if (vboxSnapshotGetReadWriteDisks(def, snapshot) < 0) { + VIR_DEBUG("Could not get read write disks for snapshot"); + } + + if (vboxSnapshotGetReadOnlyDisks(snapshot, def) <0) { + VIR_DEBUG("Could not get Readonly disks for snapshot"); + } +#endif /* VBOX_API_VERSION >= 4002 */ + rc = snap->vtbl->GetDescription(snap, &str16); if (NS_FAILED(rc)) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -6098,8 +6483,8 @@ vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot, def->state = VIR_DOMAIN_SHUTOFF; virUUIDFormat(dom->uuid, uuidstr); + memcpy(def->dom->uuid, dom->uuid, VIR_UUID_BUFLEN); ret = virDomainSnapshotDefFormat(uuidstr, def, flags, 0); - cleanup: virDomainSnapshotDefFree(def); VBOX_RELEASE(parent); @@ -6804,6 +7189,8 @@ cleanup: return ret; } + + static int vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, unsigned int flags) @@ -6839,8 +7226,9 @@ vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot, goto cleanup; } - /* VBOX snapshots do not require any libvirt metadata, making this - * flag trivial once we know we have a valid snapshot. */ + /* In case we just want to delete the metadata, we will edit the vbox file in order + *to remove the node concerning the snapshot + */ if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY) { ret = 0; goto cleanup; @@ -8662,8 +9050,9 @@ cleanup: return ret; } -static int vboxStorageVolDelete(virStorageVolPtr vol, - unsigned int flags) +static int vboxStorageDeleteOrClose(virStorageVolPtr vol, + unsigned int flags, + unsigned int flagDeleteOrClose) { VBOX_OBJECT_CHECK(vol->conn, int, -1); vboxIID hddIID = VBOX_IID_INITIALIZER; @@ -8818,8 +9207,18 @@ static int vboxStorageVolDelete(virStorageVolPtr vol, if (machineIdsSize == 0 || machineIdsSize == deregister) { IProgress *progress = NULL; - +#if VBOX_API_VERSION >= 4002 + if (flagDeleteOrClose & VBOX_STORAGE_CLOSE_FLAG) { + rc = hardDisk->vtbl->Close(hardDisk); + if (NS_SUCCEEDED(rc)) { + DEBUGIID("HardDisk closed, UUID", hddIID.value); + ret = 0; + } + } +#endif + if (flagDeleteOrClose & VBOX_STORAGE_DELETE_FLAG){ rc = hardDisk->vtbl->DeleteStorage(hardDisk, &progress); + } if (NS_SUCCEEDED(rc) && progress) { progress->vtbl->WaitForCompletion(progress, -1); @@ -8838,6 +9237,12 @@ static int vboxStorageVolDelete(virStorageVolPtr vol, return ret; } +static int vboxStorageVolDelete(virStorageVolPtr vol, + unsigned int flags) +{ + return vboxStorageDeleteOrClose(vol, flags, VBOX_STORAGE_DELETE_FLAG); +} + static int vboxStorageVolGetInfo(virStorageVolPtr vol, virStorageVolInfoPtr info) { VBOX_OBJECT_CHECK(vol->conn, int, -1); IHardDisk *hardDisk = NULL; -- 1.7.10.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list