[libvirt] [PATCH] Support for virtualbox version 3.1

Matthias Bolte matthias.bolte at googlemail.com
Fri Nov 20 00:22:20 UTC 2009


2009/11/17 pritesh <Pritesh.Kothari at sun.com>:
> Hi All,
>
> I have just added support for VirtualBox Version 3.1 (works for the beta as
> well) in the libvirt vbox driver.
>
> The patch for the same is attached below.
>
> Regards,
> Pritesh
>

Well, apart from the new auto generated files for version 3.1 support
a huge part of the patch affects vbox_tmpl.c, ~7700 lines changed.
Most of that are pure indentation level changes, due to inverting the
logic of some common error checks. Applying the patch and creating a
new patch using git diff -b to ignore pure whitespace changes results
in ~2200 lines changed. And even most of this 2200 lines are due to
the wrapping of some common code patterns into macros; mostly
free/release calls. The actual functional change of this patch is
fairly small. You should have split this at least into two separate
patches.

> diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c
> index cd60b72..ed4406f 100644
> --- a/src/vbox/vbox_tmpl.c
> +++ b/src/vbox/vbox_tmpl.c
[...]
> @@ -351,6 +406,265 @@ static void vboxUtf8toIID(virConnectPtr conn, char *uuidstr, vboxIID **iid) {
>          virReportOOMError(conn);
>  }
>
> +#if VBOX_API_VERSION >= 3001
> +
> +/**
> + * function to generate the name for medium,
> + * for e.g: hda, sda, etc
> + *
> + * Limitation: 1) max (26+(26*26)+(26*26*26)) i.e
> + *                18,278 names for now
> + *
> + * @returns     null terminated string with device name or NULL
> + *              for failures
> + * @param       conn            Input Connection Pointer
> + * @param       storageBus      Input storage bus type
> + * @param       deviceInst      Input device instance number
> + * @param       devicePort      Input port number
> + * @param       deviceSlot      Input slot number
> + * @param       aMaxPortPerInst Input array of max port per device instance
> + * @param       aMaxSlotPerPort Input array of max slot per device port
> + *
> + */
> +static char *vboxGenerateMediumName(virConnectPtr conn,
> +                                    PRUint32  storageBus,
> +                                    PRInt32   deviceInst,
> +                                    PRInt32   devicePort,
> +                                    PRInt32   deviceSlot,
> +                                    PRUint32 *aMaxPortPerInst,
> +                                    PRUint32 *aMaxSlotPerPort) {
> +    char *name  = NULL;
> +    int   len   = 4;
> +    int   total = 0;
> +    PRUint32 maxPortPerInst = 0;
> +    PRUint32 maxSlotPerPort = 0;
> +
> +    if (   !aMaxPortPerInst
> +        || !aMaxSlotPerPort)
> +        return NULL;
> +
> +    maxPortPerInst = aMaxPortPerInst[storageBus];
> +    maxSlotPerPort = aMaxSlotPerPort[storageBus];
> +    total =   (deviceInst * maxPortPerInst * maxSlotPerPort)
> +            + (devicePort * maxSlotPerPort)
> +            + deviceSlot;
> +
> +    if ((total >= 26) && (total < 26*26 + 26))
> +        len = 5;
> +    else if ((total >= 26*26 + 26) && (total < 26*26*26 + 26*26 + 26))
> +        len = 6;
> +
> +    if (VIR_ALLOC_N(name, len) < 0) {
> +        virReportOOMError(conn);
> +        return NULL;
> +    }
> +
> +    if (storageBus == StorageBus_IDE) {
> +        name[0] = 'h';
> +        name[1] = 'd';
> +    } else if (   (storageBus == StorageBus_SATA)
> +               || (storageBus == StorageBus_SCSI)) {
> +        name[0] = 's';
> +        name[1] = 'd';
> +    } else if (storageBus == StorageBus_Floppy) {
> +        name[0] = 'f';
> +        name[1] = 'd';
> +    }

You're missing an else branch here to handle the case of the storage
bus being none of the checked values.

> +    if (len == 4) {
> +        name[2] = (char)(97 + total);

If total is out-of-range len will also be 4, because 4 is the default
value and you have no out-or-range checks to catch such a situation.
So you're going to create a bogus name then.

> +    } else if (len == 5) {
> +        name[2] = (char)(96 + (total / 26));
> +        name[3] = (char)(97 + (total % 26));
> +    } else if (len == 6) {
> +        name[2] = (char)(96 + (total / 26*26));
> +        name[3] = (char)(96 + ((total % (26*26)) / 26));
> +        name[4] = (char)(97 + ((total % (26*26)) % 26));
> +    }

You should use virDiskNameToIndex() in vboxGetDeviceDetails() (see
below). So you should use the matching inverse function here. I added
esxVMX_IndexToDiskName() for the ESX driver, because libvirt doesn't
have this function yet. Maybe I should post a patch to add it to
src/util/util.[ch].

Actually, it seems you do the correct inverse operation to
virDiskNameToIndex() with this code.

> +    name[len - 1] = '\0';
> +    DEBUG("name=%s, len=%d, total=%d, storageBus=%u, deviceInst=%d, "
> +          "devicePort=%d deviceSlot=%d, maxPortPerInst=%u maxSlotPerPort=%u",
> +          name, len, total, storageBus, deviceInst, devicePort,
> +          deviceSlot, maxPortPerInst, maxSlotPerPort);
> +    return name;
> +}
> +
> +/**
> + * function to get the StorageBus, Port number
> + * and Device number for the given devicename
> + * e.g: hda has StorageBus = IDE, port = 0,
> + *      device = 0
> + *
> + * Limitation: only name till 4 chars supported
> + *             i.e from hda till hdzz
> + *
> + * @returns     true on Success, false on failure.
> + * @param       deviceName      Input device name
> + * @param       aMaxPortPerInst Input array of max port per device instance
> + * @param       aMaxSlotPerPort Input array of max slot per device port
> + * @param       storageBus      Input storage bus type
> + * @param       deviceInst      Output device instance number
> + * @param       devicePort      Output port number
> + * @param       deviceSlot      Output slot number
> + *
> + */
> +static bool vboxGetDeviceDetails(const char *deviceName,
> +                                 PRUint32   *aMaxPortPerInst,
> +                                 PRUint32   *aMaxSlotPerPort,
> +                                 PRUint32    storageBus,
> +                                 PRInt32    *deviceInst,
> +                                 PRInt32    *devicePort,
> +                                 PRInt32    *deviceSlot) {
> +    int len   = 0;
> +    int total = 0;
> +    PRUint32 maxPortPerInst = 0;
> +    PRUint32 maxSlotPerPort = 0;
> +
> +    if (   !deviceName
> +        || !storageBus
> +        || !deviceInst
> +        || !devicePort
> +        || !deviceSlot
> +        || !aMaxPortPerInst
> +        || !aMaxSlotPerPort)
> +        return false;
> +
> +    len = strlen(deviceName);
> +
> +    /* support till hdzz only so 4 chars */
> +    if (len > 4)
> +        return false;
> +
> +    maxPortPerInst = aMaxPortPerInst[storageBus];
> +    maxSlotPerPort = aMaxSlotPerPort[storageBus];
> +
> +    if (   !maxPortPerInst
> +        || !maxSlotPerPort)
> +        return false;
> +
> +    if (len == 3) {
> +        total = (deviceName[2] - 97);
> +    } else if (len == 4) {
> +        total = ((deviceName[2] - 96) * 26) + (deviceName[3] - 97);
> +    }

You assume that you got sane input here. This code is going to fail
due to char underflow if the input is 'hdA' instead of 'hda'. You
should use the more robust virDiskNameToIndex() here.

> +    *deviceInst = total / (maxPortPerInst * maxSlotPerPort);
> +    *devicePort = (total % (maxPortPerInst * maxSlotPerPort)) / maxSlotPerPort;
> +    *deviceSlot = (total % (maxPortPerInst * maxSlotPerPort)) % maxSlotPerPort;
> +
> +    DEBUG("name=%s, len=%d, total=%d, storageBus=%u, deviceInst=%d, "
> +          "devicePort=%d deviceSlot=%d, maxPortPerInst=%u maxSlotPerPort=%u",
> +          deviceName, len, total, storageBus, *deviceInst, *devicePort,
> +          *deviceSlot, maxPortPerInst, maxSlotPerPort);
> +
> +    return true;
> +}
[...]
> +/**
> + * Converts Utf-16 string to int
> + */
> +static int PRUnicharToInt(PRUnichar *strUtf16) {
> +    char *strUtf8 = NULL;
> +    int ret = 0;
> +
> +    if (!strUtf16)
> +        return -1;
> +
> +    g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(strUtf16, &strUtf8);
> +    if (!strUtf8)
> +        return -1;
> +
> +    ret = atoi(strUtf8);
> +    g_pVBoxGlobalData->pFuncs->pfnUtf8Free(strUtf8);
> +
> +    return ret;
> +}
> +
> +/**
> + * Converts int to Utf-16 string
> + */
> +static PRUnichar *PRUnicharFromInt(int n) {
> +    PRUnichar *strUtf16 = NULL;
> +    char c, s[24] = {};
> +    int sign, i = 0, j = 0;
> +
> +    if ((sign = n) < 0)
> +        n = -n;
> +    do {
> +        s[i++] = n % 10 + '0';
> +    } while ((n /= 10) > 0);
> +    if (sign < 0)
> +        s[i++] = '-';
> +    s[i] = '\0';
> +    for (j = 0; j < i; j++, i--) {
> +        c = s[j];
> +        s[j] = s[i];
> +        s[i] = c;
> +    }
> +
> +    g_pVBoxGlobalData->pFuncs->pfnUtf8ToUtf16(s, &strUtf16);
> +
> +    return strUtf16;
> +}

I don't understand why you do this in such a complex way. What about snprintf?

PRUnichar *strUtf16 = NULL;
char s[24];

snprintf(s, sizeof(s), "%d", n);

g_pVBoxGlobalData->pFuncs->pfnUtf8ToUtf16(s, &strUtf16);

return strUtf16;

> +#endif /* VBOX_API_VERSION >= 3001 */
> +
>  #endif /* !(VBOX_API_VERSION == 2002) */
>
>  static virCapsPtr vboxCapsInit(void) {

ACK, apart from the minor issues in vboxGenerateMediumName() and
vboxGetDeviceDetails().

Matthias




More information about the libvir-list mailing list