[libvirt] [PATCHv4 3/5] vbox_tmpl.c: Better XML description for snapshots

Manuel VIVES manuel.vives at diateam.net
Mon Dec 23 15:48:21 UTC 2013


> On 11/25/2013 07:23 PM, Manuel VIVES wrote:
> > It will be needed for the futur patches because we will
> > redefine snapshots
> 
> s/futur/future/ :-)
> 
> > ---
> > 
> >  src/conf/domain_conf.c |    2 +-
> >  src/vbox/vbox_tmpl.c   |  427
> >  ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 417
> >  insertions(+), 12 deletions(-)
> > 
> > diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> > index 7b0e3ea..ae20eb5 100644
> > --- a/src/conf/domain_conf.c
> > +++ b/src/conf/domain_conf.c
> > @@ -17054,7 +17054,7 @@ virDomainDefFormatInternal(virDomainDefPtr def,
> > 
> >          if (virDomainChrDefFormat(buf, &console, flags) < 0)
> >          
> >              goto error;
> >      
> >      }
> > 
> > -    if (STREQ(def->os.type, "hvm") &&
> > +    if (STREQ_NULLABLE(def->os.type, "hvm") &&
> > 
> >          def->nconsoles == 0 &&
> >          def->nserials > 0) {
> >          virDomainChrDef console;
> 
> This hunk should be a separate patch. BTW, is it valid for vbox domains
> to not have a valid os.type? virDomainDefPostParseInternal() requires it
> to be set, and there are several other places in domain_conf.c that
> compare it without allowing for NULL, so if NULL is valid, those other
> places should at least get scrutiny, or you should make sure that it's
> set when you construct the domain object in the vbox driver.
> 

This portion was safely removed from the patch.

> > diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c
> > index 983a595..e05ed97 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
> > 
> > @@ -273,10 +276,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; \
> > +    }
> > +
> > +
> 
> I would prefer these if() clauses with goto to be explicitly in the
> code, rather than hidden in a macro. That way it's easier to see all
> potential code paths when scanning through the code. If you have a goto
> hidden in a macro, then it's not immediately visible and that can only
> lead to problems.

I removed this macro in order to have 'goto' instructions clearly
visible but it increases the size of the patch.

> >  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) {
> 
> You should leave in that blank line, as it separates static function
> declarations from a function definition.
> 
> >      virMutexLock(&data->lock);
> >  
> >  }
> > 
> > @@ -285,6 +294,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) {
> > 
> > @@ -5957,7 +5972,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)))
> 
> Move the VIR_DOMAIN_SNAPSHOT... down one line so that it can be moved
> left and hopefully fit within 80 columns.
> 
> >          goto cleanup;
> >      
> >      if (def->ndisks) {
> > 
> > @@ -5965,7 +5981,6 @@ vboxDomainSnapshotCreateXML(virDomainPtr dom,
> > 
> >                         _("disk snapshots not supported yet"));
> >          
> >          goto cleanup;
> >      
> >      }
> > 
> > -
> 
> Any particular reason for removing this blank line (and the one below)?
> 
> >      vboxIIDFromUUID(&domiid, dom->uuid);
> >      rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
> >      if (NS_FAILED(rc)) {
> > 
> > @@ -5973,7 +5988,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",
> > 
> > @@ -6048,6 +6062,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;
> 
> The combination of having "error" and "ret" is confusing, and the
> possibility at the bottom of the function of either going to cleanup to
> return "ret" or dropping through to check for error == true and then
> return 0 or -1 is also confusing. You can probably make it much simpler
> by removing error, initializing ret = -1, then when you get to cleanup
> at the end, just check for ret < 0 and do the error cleanup in that case.
> 
> All of the places you set "error = true" would then just be "goto
> cleanup" (I'm not sure why your current code continues to process once
> it has encountered an error, but I'm making the assumption that is
> superfluous and not intentional).
> 
> For the case of success, you would just drop through to the cleanup
> label, and just before that would be a "ret = 0;". This is the way a
> vast majority of functions in libvirt are written, and it works very
> well for us in most cases.
> 
> > +    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();
> 
> You no longer need to report an error if VIR_ALLOC_N() fails - it's done
> for you; just return failure to your caller.
> 
> > +        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();
> 
> Same here - VIR_STRDUP() reports the error for you. (in the rare case
> that you *don't* want it automatically reported, you would call
> VIR_STRDUP_QUIET()).
> 
> (I probably ignored other occurrences of this problem in your patches...)
> 
> > +                        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);
> 
> Put a blank line between the automatic data declarations and the first
> statement.
> 
> > +    if (NS_FAILED(rc)) {
> > +        virReportError(VIR_ERR_NO_DOMAIN, "%s",
> > +                       _("no domain with matching UUID"));
> > +        return -1;
> > +    }
> 
> Hmm. You defined a macro to do almost exactly this, but couldn't use it
> here because you couldn't goto cleanup. Are the vbox cleanup
> unctions/macros not safe to call when the data they're cleaning up is
> still NULL?
> 

My mistake, I should have used the macro.

> (not that I think you should try to use that macro - I think it should
> be killed. I'm just curious why you didn't use it here)
> 
> > +
> > +    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;
> 
> Again, unneeded call to virReportOOMError(), and it would be better to
> have initialized ret = -1 at the top, then done "goto cleanup" here.
> 
> > +                break;
> > +    }
> > +        }
> > +    } else {
> > +        virReportOOMError();
> > +        error = true;
> 
> Likewise. I'll stop pointing these out now...
> 
> > +    }
> > +
> > +    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++) {
> 
> You' going to a lot of trouble to avoid executing this code after error
> has be set to true, again indicating that it would be simpler to just
> goto cleanup immediately when you encounter an error (and have cleanup
> contain the proper code to cleanup from an error).
> 
> > +        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 */
> 
> ... but not on *all* errors, since you sometimes set error = true and
> continue all the way down to here, and sometime you set set = -1 and
> goto cleanup (thus skipping this extra cleanup). ALL of the cleanup
> should be after the cleanup label, and you should always goto cleanup
> when you encounter an error. That way you won't have some error recovery
> paths that skip some of the cleanup.
> 
> > +    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)
> > 
> > @@ -6065,6 +6417,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);
> > 
> > @@ -6079,11 +6435,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,
> > 
> > @@ -6148,8 +6533,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);
> > 
> > @@ -6854,6 +7239,8 @@ cleanup:
> >      return ret;
> >  
> >  }
> > 
> > +
> > +
> > 
> >  static int
> >  vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
> >  
> >                           unsigned int flags)
> > 
> > @@ -6889,8 +7276,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;
> > 
> > @@ -8716,8 +9104,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;
> > 
> > @@ -8872,8 +9261,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);
> > 
> > @@ -8892,6 +9291,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;




More information about the libvir-list mailing list