int parallelsStorageVolDefRemove(virStoragePoolObjPtr privpool,
                                    virStorageVolDefPtr privvol)
{
    int ret = -1;
    char *xml_path = NULL;
    size_t i;

    privpool->def->allocation -= privvol->allocation;
    privpool->def->available = (privpool->def->capacity -
                                privpool->def->allocation);

    for (i = 0; i < privpool->volumes.count; i++) {
        if (privpool->volumes.objs[i] == privvol) {
            xml_path = parallelsAddFileExt(privvol->target.path, ".xml");
            if (!xml_path)
                goto cleanup;

            if (unlink(xml_path)) {
                virReportError(VIR_ERR_OPERATION_FAILED,
                               _("Can't remove file '%s'"), xml_path);
                goto cleanup;
            }

            virStorageVolDefFree(privvol);

            if (i < (privpool->volumes.count - 1))
                memmove(privpool->volumes.objs + i,
                        privpool->volumes.objs + i + 1,
                        sizeof(*(privpool->volumes.objs)) *
                        (privpool->volumes.count - (i + 1)));

            if (VIR_REALLOC_N(privpool->volumes.objs,
                              privpool->volumes.count - 1) < 0) {
                ;   /* Failure to reduce memory allocation isn't fatal */
            }
            privpool->volumes.count--;

            break;
        }
    }

    ret = 0;
cleanup:
    VIR_FREE(xml_path);
    return ret;
}
static int
test_vdi_list_parser(collie_test test, char *poolxml, char *volxml)
{
    int ret = -1;
    char *poolXmlData = NULL;
    char *volXmlData = NULL;
    char *output = NULL;
    virStoragePoolDefPtr pool = NULL;
    virStorageVolDefPtr vol = NULL;

    if (virtTestLoadFile(poolxml, &poolXmlData) < 0)
        goto cleanup;
    if (virtTestLoadFile(volxml, &volXmlData) < 0)
        goto cleanup;

    if (!(pool = virStoragePoolDefParseString(poolXmlData)))
        goto cleanup;

    if (!(vol = virStorageVolDefParseString(pool, volXmlData)))
        goto cleanup;

    output = strdup(test.output);
    if (!output)
        goto cleanup;

    if (virStorageBackendSheepdogParseVdiList(vol, output) !=
        test.expected_return)
        goto cleanup;

    if (test.expected_return) {
        ret = 0;
        goto cleanup;
    }

    if (vol->capacity == test.expected_capacity &&
        vol->allocation == test.expected_allocation)
        ret = 0;

  cleanup:
    VIR_FREE(output);
    VIR_FREE(poolXmlData);
    VIR_FREE(volXmlData);
    virStoragePoolDefFree(pool);
    virStorageVolDefFree(vol);
    return ret;
}
Exemple #3
0
static int
testCompareXMLToXMLFiles(const char *poolxml, const char *inxml,
                         const char *outxml)
{
    char *poolXmlData = NULL;
    char *inXmlData = NULL;
    char *outXmlData = NULL;
    char *actual = NULL;
    int ret = -1;
    virStoragePoolDefPtr pool = NULL;
    virStorageVolDefPtr dev = NULL;

    if (virtTestLoadFile(poolxml, &poolXmlData) < 0)
        goto fail;
    if (virtTestLoadFile(inxml, &inXmlData) < 0)
        goto fail;
    if (virtTestLoadFile(outxml, &outXmlData) < 0)
        goto fail;

    if (!(pool = virStoragePoolDefParseString(poolXmlData)))
        goto fail;

    if (!(dev = virStorageVolDefParseString(pool, inXmlData)))
        goto fail;

    if (!(actual = virStorageVolDefFormat(pool, dev)))
        goto fail;

    if (STRNEQ(outXmlData, actual)) {
        virtTestDifference(stderr, outXmlData, actual);
        goto fail;
    }

    ret = 0;

 fail:
    VIR_FREE(poolXmlData);
    VIR_FREE(inXmlData);
    VIR_FREE(outXmlData);
    VIR_FREE(actual);
    virStoragePoolDefFree(pool);
    virStorageVolDefFree(dev);
    return ret;
}
static int
virStorageBackendMpathNewVol(virStoragePoolObjPtr pool,
                             const int devnum,
                             const char *dev)
{
    virStorageVolDefPtr vol;
    int ret = -1;

    if (VIR_ALLOC(vol) < 0)
        goto cleanup;

    vol->type = VIR_STORAGE_VOL_BLOCK;

    if (virAsprintf(&(vol->name), "dm-%u", devnum) < 0)
        goto cleanup;

    if (virAsprintf(&vol->target.path, "/dev/%s", dev) < 0)
        goto cleanup;

    if (virStorageBackendMpathUpdateVolTargetInfo(&vol->target,
                                                  &vol->allocation,
                                                  &vol->capacity) < 0) {
        goto cleanup;
    }

    /* XXX should use logical unit's UUID instead */
    if (VIR_STRDUP(vol->key, vol->target.path) < 0)
        goto cleanup;

    if (VIR_APPEND_ELEMENT_COPY(pool->volumes.objs, pool->volumes.count, vol) < 0)
        goto cleanup;
    pool->def->capacity += vol->capacity;
    pool->def->allocation += vol->allocation;
    ret = 0;

cleanup:

    if (ret != 0)
        virStorageVolDefFree(vol);

    return ret;
}
static int parallelsAddDiskVolume(virStoragePoolObjPtr pool,
                                  virDomainObjPtr dom,
                                  const char *diskName,
                                  const char *diskPath,
                                  const char *diskDescPath)
{
    virStorageVolDefPtr def = NULL;

    if (VIR_ALLOC(def))
        goto error;

    if (virAsprintf(&def->name, "%s-%s", dom->def->name, diskName) < 0)
        goto error;

    def->type = VIR_STORAGE_VOL_FILE;

    if (parallelsDiskDescParse(diskDescPath, def) < 0)
        goto error;

    if (!(def->target.path = realpath(diskPath, NULL)))
        goto no_memory;

    if (VIR_STRDUP(def->key, def->target.path) < 0)
        goto error;

    if (VIR_REALLOC_N(pool->volumes.objs, pool->volumes.count + 1) < 0)
        goto error;

    pool->volumes.objs[pool->volumes.count++] = def;

    return 0;
no_memory:
    virReportOOMError();
error:
    virStorageVolDefFree(def);
    return -1;
}
static int
virStorageBackendLogicalMakeVol(virStoragePoolObjPtr pool,
                                char **const groups,
                                void *data)
{
    virStorageVolDefPtr vol = NULL;
    unsigned long long offset, size, length;

    /* See if we're only looking for a specific volume */
    if (data != NULL) {
        vol = data;
        if (STRNEQ(vol->name, groups[0]))
            return 0;
    }

    /* Or filling in more data on an existing volume */
    if (vol == NULL)
        vol = virStorageVolDefFindByName(pool, groups[0]);

    /* Or a completely new volume */
    if (vol == NULL) {
        if (VIR_ALLOC(vol) < 0) {
            virReportOOMError();
            return -1;
        }

        vol->type = VIR_STORAGE_VOL_BLOCK;

        if ((vol->name = strdup(groups[0])) == NULL) {
            virReportOOMError();
            virStorageVolDefFree(vol);
            return -1;
        }

        if (VIR_REALLOC_N(pool->volumes.objs,
                          pool->volumes.count + 1)) {
            virReportOOMError();
            virStorageVolDefFree(vol);
            return -1;
        }
        pool->volumes.objs[pool->volumes.count++] = vol;
    }

    if (vol->target.path == NULL) {
        if (virAsprintf(&vol->target.path, "%s/%s",
                        pool->def->target.path, vol->name) < 0) {
            virReportOOMError();
            virStorageVolDefFree(vol);
            return -1;
        }
    }

    if (groups[1] && !STREQ(groups[1], "")) {
        if (virAsprintf(&vol->backingStore.path, "%s/%s",
                        pool->def->target.path, groups[1]) < 0) {
            virReportOOMError();
            virStorageVolDefFree(vol);
            return -1;
        }

        vol->backingStore.format = VIR_STORAGE_POOL_LOGICAL_LVM2;
    }

    if (vol->key == NULL &&
        (vol->key = strdup(groups[2])) == NULL) {
        virReportOOMError();
        return -1;
    }

    if (virStorageBackendUpdateVolInfo(vol, 1) < 0)
        return -1;


    /* Finally fill in extents information */
    if (VIR_REALLOC_N(vol->source.extents,
                      vol->source.nextent + 1) < 0) {
        virReportOOMError();
        return -1;
    }

    if ((vol->source.extents[vol->source.nextent].path =
         strdup(groups[3])) == NULL) {
        virReportOOMError();
        return -1;
    }

    if (virStrToLong_ull(groups[4], NULL, 10, &offset) < 0) {
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                              "%s", _("malformed volume extent offset value"));
        return -1;
    }
    if (virStrToLong_ull(groups[5], NULL, 10, &length) < 0) {
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                              "%s", _("malformed volume extent length value"));
        return -1;
    }
    if (virStrToLong_ull(groups[6], NULL, 10, &size) < 0) {
        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
                              "%s", _("malformed volume extent size value"));
        return -1;
    }

    vol->source.extents[vol->source.nextent].start = offset * size;
    vol->source.extents[vol->source.nextent].end = (offset * size) + length;
    vol->source.nextent++;

    return 0;
}
static virStorageVolPtr
esxStorageVolCreateXML(virStoragePoolPtr pool,
                       const char *xmldesc,
                       unsigned int flags)
{
    virStorageVolPtr volume = NULL;
    esxPrivate *priv = pool->conn->privateData;
    virStoragePoolDef poolDef;
    virStorageVolDefPtr def = NULL;
    char *tmp;
    char *unescapedDatastorePath = NULL;
    char *unescapedDirectoryName = NULL;
    char *unescapedDirectoryAndFileName = NULL;
    char *directoryName = NULL;
    char *fileName = NULL;
    char *datastorePathWithoutFileName = NULL;
    char *datastorePath = NULL;
    esxVI_FileInfo *fileInfo = NULL;
    esxVI_FileBackedVirtualDiskSpec *virtualDiskSpec = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
    char *taskInfoErrorMessage = NULL;
    char *uuid_string = NULL;
    char *key = NULL;

    virCheckFlags(0, NULL);

    memset(&poolDef, 0, sizeof(poolDef));

    if (esxLookupVMFSStoragePoolType(priv->primary, pool->name,
                                     &poolDef.type) < 0) {
        goto cleanup;
    }

    /* Parse config */
    def = virStorageVolDefParseString(&poolDef, xmldesc);

    if (!def)
        goto cleanup;

    if (def->type != VIR_STORAGE_VOL_FILE) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Creating non-file volumes is not supported"));
        goto cleanup;
    }

    /* Validate config */
    tmp = strrchr(def->name, '/');

    if (!tmp || *def->name == '/' || tmp[1] == '\0') {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Volume name '%s' doesn't have expected format "
                         "'<directory>/<file>'"), def->name);
        goto cleanup;
    }

    if (! virFileHasSuffix(def->name, ".vmdk")) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Volume name '%s' has unsupported suffix, "
                         "expecting '.vmdk'"), def->name);
        goto cleanup;
    }

    if (virAsprintf(&unescapedDatastorePath, "[%s] %s", pool->name,
                    def->name) < 0)
        goto cleanup;

    if (def->target.format == VIR_STORAGE_FILE_VMDK) {
        /* Parse and escape datastore path */
        if (esxUtil_ParseDatastorePath(unescapedDatastorePath, NULL,
                                       &unescapedDirectoryName,
                                       &unescapedDirectoryAndFileName) < 0) {
            goto cleanup;
        }

        directoryName = esxUtil_EscapeDatastoreItem(unescapedDirectoryName);

        if (!directoryName)
            goto cleanup;

        fileName = esxUtil_EscapeDatastoreItem(unescapedDirectoryAndFileName +
                                               strlen(unescapedDirectoryName) + 1);

        if (!fileName)
            goto cleanup;

        if (virAsprintf(&datastorePathWithoutFileName, "[%s] %s", pool->name,
                        directoryName) < 0)
            goto cleanup;

        if (virAsprintf(&datastorePath, "[%s] %s/%s", pool->name, directoryName,
                        fileName) < 0)
            goto cleanup;

        /* Create directory, if it doesn't exist yet */
        if (esxVI_LookupFileInfoByDatastorePath
              (priv->primary, datastorePathWithoutFileName, true, &fileInfo,
               esxVI_Occurrence_OptionalItem) < 0) {
            goto cleanup;
        }

        if (!fileInfo) {
            if (esxVI_MakeDirectory(priv->primary, datastorePathWithoutFileName,
                                    priv->primary->datacenter->_reference,
                                    esxVI_Boolean_True) < 0) {
                goto cleanup;
            }
        }

        /* Create VirtualDisk */
        if (esxVI_FileBackedVirtualDiskSpec_Alloc(&virtualDiskSpec) < 0 ||
            esxVI_Long_Alloc(&virtualDiskSpec->capacityKb) < 0) {
            goto cleanup;
        }

        /* From the vSphere API documentation about VirtualDiskType ... */
        if (def->target.allocation == def->target.capacity) {
            /*
             * "A preallocated disk has all space allocated at creation time
             *  and the space is zeroed on demand as the space is used."
             */
            virtualDiskSpec->diskType = (char *)"preallocated";
        } else if (def->target.allocation == 0) {
            /*
             * "Space required for thin-provisioned virtual disk is allocated
             *  and zeroed on demand as the space is used."
             */
            virtualDiskSpec->diskType = (char *)"thin";
        } else {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Unsupported capacity-to-allocation relation"));
            goto cleanup;
        }

        /*
         * FIXME: The adapter type is a required parameter, but there is no
         * way to let the user specify it in the volume XML config. Therefore,
         * default to 'busLogic' here.
         */
        virtualDiskSpec->adapterType = (char *)"busLogic";

        virtualDiskSpec->capacityKb->value =
          VIR_DIV_UP(def->target.capacity, 1024); /* Scale from byte to kilobyte */

        if (esxVI_CreateVirtualDisk_Task
              (priv->primary, datastorePath,
               priv->primary->datacenter->_reference,
               esxVI_VirtualDiskSpec_DynamicCast(virtualDiskSpec), &task) < 0 ||
            esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
                                        esxVI_Occurrence_None,
                                        priv->parsedUri->autoAnswer,
                                        &taskInfoState,
                                        &taskInfoErrorMessage) < 0) {
            goto cleanup;
        }

        if (taskInfoState != esxVI_TaskInfoState_Success) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Could not create volume: %s"),
                           taskInfoErrorMessage);
            goto cleanup;
        }

        if (priv->primary->hasQueryVirtualDiskUuid) {
            if (VIR_ALLOC_N(key, VIR_UUID_STRING_BUFLEN) < 0)
                goto cleanup;

            if (esxVI_QueryVirtualDiskUuid(priv->primary, datastorePath,
                                           priv->primary->datacenter->_reference,
                                           &uuid_string) < 0) {
                goto cleanup;
            }

            if (esxUtil_ReformatUuid(uuid_string, key) < 0)
                goto cleanup;
        } else {
            /* Fall back to the path as key */
            if (VIR_STRDUP(key, datastorePath) < 0)
                goto cleanup;
        }
    } else {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Creation of %s volumes is not supported"),
                       virStorageFileFormatTypeToString(def->target.format));
        goto cleanup;
    }

    volume = virGetStorageVol(pool->conn, pool->name, def->name, key,
                              &esxStorageBackendVMFS, NULL);

 cleanup:
    if (virtualDiskSpec) {
        virtualDiskSpec->diskType = NULL;
        virtualDiskSpec->adapterType = NULL;
    }

    virStorageVolDefFree(def);
    VIR_FREE(unescapedDatastorePath);
    VIR_FREE(unescapedDirectoryName);
    VIR_FREE(unescapedDirectoryAndFileName);
    VIR_FREE(directoryName);
    VIR_FREE(fileName);
    VIR_FREE(datastorePathWithoutFileName);
    VIR_FREE(datastorePath);
    esxVI_FileInfo_Free(&fileInfo);
    esxVI_FileBackedVirtualDiskSpec_Free(&virtualDiskSpec);
    esxVI_ManagedObjectReference_Free(&task);
    VIR_FREE(taskInfoErrorMessage);
    VIR_FREE(uuid_string);
    VIR_FREE(key);

    return volume;
}
static virStorageVolPtr
esxStorageVolCreateXMLFrom(virStoragePoolPtr pool,
                           const char *xmldesc,
                           virStorageVolPtr sourceVolume,
                           unsigned int flags)
{
    virStorageVolPtr volume = NULL;
    esxPrivate *priv = pool->conn->privateData;
    virStoragePoolDef poolDef;
    char *sourceDatastorePath = NULL;
    virStorageVolDefPtr def = NULL;
    char *tmp;
    char *unescapedDatastorePath = NULL;
    char *unescapedDirectoryName = NULL;
    char *unescapedDirectoryAndFileName = NULL;
    char *directoryName = NULL;
    char *fileName = NULL;
    char *datastorePathWithoutFileName = NULL;
    char *datastorePath = NULL;
    esxVI_FileInfo *fileInfo = NULL;
    esxVI_ManagedObjectReference *task = NULL;
    esxVI_TaskInfoState taskInfoState;
    char *taskInfoErrorMessage = NULL;
    char *uuid_string = NULL;
    char *key = NULL;

    virCheckFlags(0, NULL);

    memset(&poolDef, 0, sizeof(poolDef));

    if (esxLookupVMFSStoragePoolType(priv->primary, pool->name,
                                     &poolDef.type) < 0) {
        goto cleanup;
    }

    if (virAsprintf(&sourceDatastorePath, "[%s] %s", sourceVolume->pool,
                    sourceVolume->name) < 0)
        goto cleanup;

    /* Parse config */
    def = virStorageVolDefParseString(&poolDef, xmldesc);

    if (!def)
        goto cleanup;

    if (def->type != VIR_STORAGE_VOL_FILE) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Creating non-file volumes is not supported"));
        goto cleanup;
    }

    /* Validate config */
    tmp = strrchr(def->name, '/');

    if (!tmp || *def->name == '/' || tmp[1] == '\0') {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Volume name '%s' doesn't have expected format "
                         "'<directory>/<file>'"), def->name);
        goto cleanup;
    }

    if (! virFileHasSuffix(def->name, ".vmdk")) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Volume name '%s' has unsupported suffix, "
                         "expecting '.vmdk'"), def->name);
        goto cleanup;
    }

    if (virAsprintf(&unescapedDatastorePath, "[%s] %s", pool->name,
                    def->name) < 0)
        goto cleanup;

    if (def->target.format == VIR_STORAGE_FILE_VMDK) {
        /* Parse and escape datastore path */
        if (esxUtil_ParseDatastorePath(unescapedDatastorePath, NULL,
                                       &unescapedDirectoryName,
                                       &unescapedDirectoryAndFileName) < 0) {
            goto cleanup;
        }

        directoryName = esxUtil_EscapeDatastoreItem(unescapedDirectoryName);

        if (!directoryName)
            goto cleanup;

        fileName = esxUtil_EscapeDatastoreItem(unescapedDirectoryAndFileName +
                                               strlen(unescapedDirectoryName) + 1);

        if (!fileName)
            goto cleanup;

        if (virAsprintf(&datastorePathWithoutFileName, "[%s] %s", pool->name,
                        directoryName) < 0)
            goto cleanup;

        if (virAsprintf(&datastorePath, "[%s] %s/%s", pool->name, directoryName,
                        fileName) < 0)
            goto cleanup;

        /* Create directory, if it doesn't exist yet */
        if (esxVI_LookupFileInfoByDatastorePath
              (priv->primary, datastorePathWithoutFileName, true, &fileInfo,
               esxVI_Occurrence_OptionalItem) < 0) {
            goto cleanup;
        }

        if (!fileInfo) {
            if (esxVI_MakeDirectory(priv->primary, datastorePathWithoutFileName,
                                    priv->primary->datacenter->_reference,
                                    esxVI_Boolean_True) < 0) {
                goto cleanup;
            }
        }

        /* Copy VirtualDisk */
        if (esxVI_CopyVirtualDisk_Task(priv->primary, sourceDatastorePath,
                                       priv->primary->datacenter->_reference,
                                       datastorePath,
                                       priv->primary->datacenter->_reference,
                                       NULL, esxVI_Boolean_False, &task) < 0 ||
            esxVI_WaitForTaskCompletion(priv->primary, task, NULL,
                                        esxVI_Occurrence_None,
                                        priv->parsedUri->autoAnswer,
                                        &taskInfoState,
                                        &taskInfoErrorMessage) < 0) {
            goto cleanup;
        }

        if (taskInfoState != esxVI_TaskInfoState_Success) {
            virReportError(VIR_ERR_INTERNAL_ERROR, _("Could not copy volume: %s"),
                           taskInfoErrorMessage);
            goto cleanup;
        }

        if (priv->primary->hasQueryVirtualDiskUuid) {
            if (VIR_ALLOC_N(key, VIR_UUID_STRING_BUFLEN) < 0)
                goto cleanup;

            if (esxVI_QueryVirtualDiskUuid(priv->primary, datastorePath,
                                           priv->primary->datacenter->_reference,
                                           &uuid_string) < 0) {
                goto cleanup;
            }

            if (esxUtil_ReformatUuid(uuid_string, key) < 0)
                goto cleanup;
        } else {
            /* Fall back to the path as key */
            if (VIR_STRDUP(key, datastorePath) < 0)
                goto cleanup;
        }
    } else {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Creation of %s volumes is not supported"),
                       virStorageFileFormatTypeToString(def->target.format));
        goto cleanup;
    }

    volume = virGetStorageVol(pool->conn, pool->name, def->name, key,
                              &esxStorageBackendVMFS, NULL);

 cleanup:
    VIR_FREE(sourceDatastorePath);
    virStorageVolDefFree(def);
    VIR_FREE(unescapedDatastorePath);
    VIR_FREE(unescapedDirectoryName);
    VIR_FREE(unescapedDirectoryAndFileName);
    VIR_FREE(directoryName);
    VIR_FREE(fileName);
    VIR_FREE(datastorePathWithoutFileName);
    VIR_FREE(datastorePath);
    esxVI_FileInfo_Free(&fileInfo);
    esxVI_ManagedObjectReference_Free(&task);
    VIR_FREE(taskInfoErrorMessage);
    VIR_FREE(uuid_string);
    VIR_FREE(key);

    return volume;
}
static int
virStorageBackendZFSParseVol(virStoragePoolObjPtr pool,
                             virStorageVolDefPtr vol,
                             const char *volume_string)
{
    int ret = -1;
    char **tokens;
    size_t count;
    char **name_tokens = NULL;
    char *vol_name;
    bool is_new_vol = false;
    virStorageVolDefPtr volume = NULL;

    if (!(tokens = virStringSplitCount(volume_string, "\t", 0, &count)))
        return -1;

    if (count != 2)
        goto cleanup;

    if (!(name_tokens = virStringSplit(tokens[0], "/", 2)))
        goto cleanup;

    vol_name = name_tokens[1];

    if (vol == NULL)
        volume = virStorageVolDefFindByName(pool, vol_name);
    else
        volume = vol;

    if (volume == NULL) {
        if (VIR_ALLOC(volume) < 0)
            goto cleanup;

        is_new_vol = true;
        volume->type = VIR_STORAGE_VOL_BLOCK;

        if (VIR_STRDUP(volume->name, vol_name) < 0)
            goto cleanup;
    }

    if (!volume->key && VIR_STRDUP(volume->key, tokens[0]) < 0)
        goto cleanup;

    if (volume->target.path == NULL) {
        if (virAsprintf(&volume->target.path, "%s/%s",
                        pool->def->target.path, volume->name) < 0)
            goto cleanup;
    }

    if (virStrToLong_ull(tokens[1], NULL, 10, &volume->target.capacity) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("malformed volsize reported"));
        goto cleanup;
    }

    if (is_new_vol &&
        VIR_APPEND_ELEMENT(pool->volumes.objs,
                           pool->volumes.count,
                           volume) < 0)
        goto cleanup;

    ret = 0;
 cleanup:
    virStringFreeList(tokens);
    virStringFreeList(name_tokens);
    if (is_new_vol)
        virStorageVolDefFree(volume);
    return ret;
}
static int virStorageBackendRBDRefreshPool(virConnectPtr conn,
                                           virStoragePoolObjPtr pool)
{
    size_t max_size = 1024;
    int ret = -1;
    int len = -1;
    int r = 0;
    char *name, *names = NULL;
    virStorageBackendRBDState ptr;
    ptr.cluster = NULL;
    ptr.ioctx = NULL;

    if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, pool) < 0) {
        goto cleanup;
    }

    if (virStorageBackendRBDOpenIoCTX(&ptr, pool) < 0) {
        goto cleanup;
    }

    struct rados_cluster_stat_t clusterstat;
    r = rados_cluster_stat(ptr.cluster, &clusterstat);
    if (r < 0) {
        virReportSystemError(-r, "%s", _("failed to stat the RADOS cluster"));
        goto cleanup;
    }

    struct rados_pool_stat_t poolstat;
    r = rados_ioctx_pool_stat(ptr.ioctx, &poolstat);
    if (r < 0) {
        virReportSystemError(-r, _("failed to stat the RADOS pool '%s'"),
                             pool->def->source.name);
        goto cleanup;
    }

    pool->def->capacity = clusterstat.kb * 1024;
    pool->def->available = clusterstat.kb_avail * 1024;
    pool->def->allocation = poolstat.num_bytes;

    VIR_DEBUG("Utilization of RBD pool %s: (kb: %llu kb_avail: %llu num_bytes: %llu)",
              pool->def->source.name, (unsigned long long)clusterstat.kb,
              (unsigned long long)clusterstat.kb_avail,
              (unsigned long long)poolstat.num_bytes);

    while (true) {
        if (VIR_ALLOC_N(names, max_size) < 0)
            goto cleanup;

        len = rbd_list(ptr.ioctx, names, &max_size);
        if (len >= 0)
            break;
        if (len != -ERANGE) {
            VIR_WARN("%s", _("A problem occurred while listing RBD images"));
            goto cleanup;
        }
        VIR_FREE(names);
    }

    for (name = names; name < names + max_size;) {
        virStorageVolDefPtr vol;

        if (VIR_REALLOC_N(pool->volumes.objs, pool->volumes.count + 1) < 0) {
            virStoragePoolObjClearVols(pool);
            goto cleanup;
        }

        if (STREQ(name, ""))
            break;

        if (VIR_ALLOC(vol) < 0)
            goto cleanup;

        if (VIR_STRDUP(vol->name, name) < 0) {
            VIR_FREE(vol);
            goto cleanup;
        }

        name += strlen(name) + 1;

        if (volStorageBackendRBDRefreshVolInfo(vol, pool, &ptr) < 0) {
            virStorageVolDefFree(vol);
            goto cleanup;
        }

        pool->volumes.objs[pool->volumes.count++] = vol;
    }

    VIR_DEBUG("Found %zu images in RBD pool %s",
              pool->volumes.count, pool->def->source.name);

    ret = 0;

cleanup:
    VIR_FREE(names);
    virStorageBackendRBDCloseRADOSConn(&ptr);
    return ret;
}
static int
testCompareXMLToArgvFiles(bool shouldFail,
                          const char *poolxml,
                          const char *volxml,
                          const char *inputpoolxml,
                          const char *inputvolxml,
                          const char *cmdline,
                          unsigned int flags,
                          unsigned long parse_flags)
{
    char *actualCmdline = NULL;
    virStorageVolEncryptConvertStep convertStep = VIR_STORAGE_VOL_ENCRYPT_NONE;
    int ret = -1;

    virCommandPtr cmd = NULL;

    virStorageVolDefPtr vol = NULL, inputvol = NULL;
    virStoragePoolDefPtr def = NULL;
    virStoragePoolDefPtr inputpool = NULL;
    virStoragePoolObjPtr obj = NULL;

    if (!(def = virStoragePoolDefParseFile(poolxml)))
        goto cleanup;

    if (!(obj = virStoragePoolObjNew())) {
        virStoragePoolDefFree(def);
        goto cleanup;
    }
    virStoragePoolObjSetDef(obj, def);

    if (inputpoolxml) {
        if (!(inputpool = virStoragePoolDefParseFile(inputpoolxml)))
            goto cleanup;
    }

    if (inputvolxml)
        parse_flags |= VIR_VOL_XML_PARSE_NO_CAPACITY;

    if (!(vol = virStorageVolDefParseFile(def, volxml, parse_flags)))
        goto cleanup;

    if (inputvolxml &&
        !(inputvol = virStorageVolDefParseFile(inputpool, inputvolxml, 0)))
        goto cleanup;

    testSetVolumeType(vol, def);
    testSetVolumeType(inputvol, inputpool);

    /* Using an input file for encryption requires a multi-step process
     * to create an image of the same size as the inputvol and then to
     * convert the inputvol afterwards. Since we only care about the
     * command line we have to copy code from storageBackendCreateQemuImg
     * and adjust it for the test needs. */
    if (inputvol && (vol->target.encryption || inputvol->target.encryption))
        convertStep = VIR_STORAGE_VOL_ENCRYPT_CREATE;

    do {
        cmd = virStorageBackendCreateQemuImgCmdFromVol(obj, vol,
                                                       inputvol, flags,
                                                       create_tool,
                                                       "/path/to/secretFile",
                                                       "/path/to/inputSecretFile",
                                                       convertStep);
        if (!cmd) {
            if (shouldFail) {
                virResetLastError();
                ret = 0;
            }
            goto cleanup;
        }

        if (convertStep != VIR_STORAGE_VOL_ENCRYPT_CONVERT) {
            if (!(actualCmdline = virCommandToString(cmd)))
                goto cleanup;
        } else {
            char *createCmdline = actualCmdline;
            char *cvtCmdline;
            int rc;

            if (!(cvtCmdline = virCommandToString(cmd)))
                goto cleanup;

            rc = virAsprintf(&actualCmdline, "%s\n%s",
                             createCmdline, cvtCmdline);

            VIR_FREE(createCmdline);
            VIR_FREE(cvtCmdline);
            if (rc < 0)
                goto cleanup;
        }

        if (convertStep == VIR_STORAGE_VOL_ENCRYPT_NONE)
            convertStep = VIR_STORAGE_VOL_ENCRYPT_DONE;
        else if (convertStep == VIR_STORAGE_VOL_ENCRYPT_CREATE)
            convertStep = VIR_STORAGE_VOL_ENCRYPT_CONVERT;
        else if (convertStep == VIR_STORAGE_VOL_ENCRYPT_CONVERT)
            convertStep = VIR_STORAGE_VOL_ENCRYPT_DONE;

    } while (convertStep != VIR_STORAGE_VOL_ENCRYPT_DONE);

    if (virTestCompareToFile(actualCmdline, cmdline) < 0)
        goto cleanup;

    ret = 0;

 cleanup:
    virStoragePoolDefFree(inputpool);
    virStorageVolDefFree(vol);
    virStorageVolDefFree(inputvol);
    virCommandFree(cmd);
    VIR_FREE(actualCmdline);
    virStoragePoolObjEndAPI(&obj);
    return ret;
}
Exemple #12
0
static int virStorageBackendRBDRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
        virStoragePoolObjPtr pool)
{
    size_t max_size = 1024;
    int ret = -1;
    int len = -1;
    int i;
    char *name, *names = NULL;
    virStorageBackendRBDStatePtr ptr;
    ptr.cluster = NULL;
    ptr.ioctx = NULL;

    if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, pool) < 0) {
        goto cleanup;
    }

    if (rados_ioctx_create(ptr.cluster,
                           pool->def->source.name, &ptr.ioctx) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to create the RBD IoCTX. Does the pool '%s' exist?"),
                       pool->def->source.name);
        goto cleanup;
    }

    struct rados_cluster_stat_t stat;
    if (rados_cluster_stat(ptr.cluster, &stat) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("failed to stat the RADOS cluster"));
        goto cleanup;
    }

    struct rados_pool_stat_t poolstat;
    if (rados_ioctx_pool_stat(ptr.ioctx, &poolstat) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to stat the RADOS pool '%s'"),
                       pool->def->source.name);
        goto cleanup;
    }

    pool->def->capacity = stat.kb * 1024;
    pool->def->available = stat.kb_avail * 1024;
    pool->def->allocation = poolstat.num_bytes;

    VIR_DEBUG("Utilization of RBD pool %s: (kb: %llu kb_avail: %llu num_bytes: %llu)",
              pool->def->source.name, (unsigned long long)stat.kb,
              (unsigned long long)stat.kb_avail,
              (unsigned long long)poolstat.num_bytes);

    while (true) {
        if (VIR_ALLOC_N(names, max_size) < 0)
            goto out_of_memory;

        len = rbd_list(ptr.ioctx, names, &max_size);
        if (len >= 0)
            break;
        if (len != -ERANGE) {
            VIR_WARN("%s", _("A problem occurred while listing RBD images"));
            goto cleanup;
        }
        VIR_FREE(names);
    }

    for (i = 0, name = names; name < names + max_size; i++) {
        virStorageVolDefPtr vol;

        if (VIR_REALLOC_N(pool->volumes.objs, pool->volumes.count + 1) < 0) {
            virStoragePoolObjClearVols(pool);
            goto out_of_memory;
        }

        if (STREQ(name, ""))
            break;

        if (VIR_ALLOC(vol) < 0)
            goto out_of_memory;

        vol->name = strdup(name);
        if (vol->name == NULL) {
            VIR_FREE(vol);
            goto out_of_memory;
        }

        name += strlen(name) + 1;

        if (volStorageBackendRBDRefreshVolInfo(vol, pool, ptr) < 0) {
            virStorageVolDefFree(vol);
            goto cleanup;
        }

        pool->volumes.objs[pool->volumes.count++] = vol;
    }

    VIR_DEBUG("Found %d images in RBD pool %s",
              pool->volumes.count, pool->def->source.name);

    ret = 0;

cleanup:
    VIR_FREE(names);
    virStorageBackendRBDCloseRADOSConn(ptr);
    return ret;

out_of_memory:
    virReportOOMError();
    goto cleanup;
}
Exemple #13
0
static virStorageVolDefPtr
parallelsStorageVolDefineXML(virStoragePoolObjPtr pool,
                             const char *xmldesc,
                             const char *xmlfile, bool is_new)
{
    virStorageVolDefPtr privvol = NULL;
    virStorageVolDefPtr ret = NULL;
    char *xml_path = NULL;

    if (xmlfile)
        privvol = virStorageVolDefParseFile(pool->def, xmlfile);
    else
        privvol = virStorageVolDefParseString(pool->def, xmldesc);

    if (privvol == NULL)
        goto cleanup;

    if (virStorageVolDefFindByName(pool, privvol->name)) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("storage vol already exists"));
        goto cleanup;
    }

    if (is_new) {
        /* Make sure enough space */
        if ((pool->def->allocation + privvol->target.allocation) >
            pool->def->capacity) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Not enough free space in pool for volume '%s'"),
                           privvol->name);
            goto cleanup;
        }
    }

    if (virAsprintf(&privvol->target.path, "%s/%s",
                    pool->def->target.path, privvol->name) < 0)
        goto cleanup;

    if (VIR_STRDUP(privvol->key, privvol->target.path) < 0)
        goto cleanup;

    if (is_new) {
        xml_path = parallelsAddFileExt(privvol->target.path, ".xml");
        if (!xml_path)
            goto cleanup;

        if (virXMLSaveFile(xml_path, NULL, "volume-create", xmldesc)) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("Can't create file with volume description"));
            goto cleanup;
        }

        pool->def->allocation += privvol->target.allocation;
        pool->def->available = (pool->def->capacity -
                                pool->def->allocation);
    }

    if (VIR_APPEND_ELEMENT_COPY(pool->volumes.objs,
                                pool->volumes.count, privvol) < 0)
        goto cleanup;

    ret = privvol;
    privvol = NULL;

 cleanup:
    virStorageVolDefFree(privvol);
    VIR_FREE(xml_path);
    return ret;
}
Exemple #14
0
static int
virStorageBackendDiskMakeDataVol(virStoragePoolObjPtr pool,
                                 char **const groups,
                                 virStorageVolDefPtr vol)
{
    char *tmp, *devpath;

    if (vol == NULL) {
        if (VIR_ALLOC(vol) < 0) {
            virReportOOMError();
            return -1;
        }

        if (VIR_REALLOC_N(pool->volumes.objs,
                          pool->volumes.count+1) < 0) {
            virReportOOMError();
            virStorageVolDefFree(vol);
            return -1;
        }
        pool->volumes.objs[pool->volumes.count++] = vol;

        /* Prepended path will be same for all partitions, so we can
         * strip the path to form a reasonable pool-unique name
         */
        tmp = strrchr(groups[0], '/');
        if ((vol->name = strdup(tmp ? tmp + 1 : groups[0])) == NULL) {
            virReportOOMError();
            return -1;
        }
    }

    if (vol->target.path == NULL) {
        if ((devpath = strdup(groups[0])) == NULL) {
            virReportOOMError();
            return -1;
        }

        /* Now figure out the stable path
         *
         * XXX this method is O(N) because it scans the pool target
         * dir every time its run. Should figure out a more efficient
         * way of doing this...
         */
        vol->target.path = virStorageBackendStablePath(pool, devpath, true);
        VIR_FREE(devpath);
        if (vol->target.path == NULL)
            return -1;
    }

    if (vol->key == NULL) {
        /* XXX base off a unique key of the underlying disk */
        if ((vol->key = strdup(vol->target.path)) == NULL) {
            virReportOOMError();
            return -1;
        }
    }

    if (vol->source.extents == NULL) {
        if (VIR_ALLOC(vol->source.extents) < 0) {
            virReportOOMError();
            return -1;
        }
        vol->source.nextent = 1;

        if (virStrToLong_ull(groups[3], NULL, 10,
                             &vol->source.extents[0].start) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("cannot parse device start location"));
            return -1;
        }

        if (virStrToLong_ull(groups[4], NULL, 10,
                             &vol->source.extents[0].end) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("cannot parse device end location"));
            return -1;
        }

        if ((vol->source.extents[0].path =
             strdup(pool->def->source.devices[0].path)) == NULL) {
            virReportOOMError();
            return -1;
        }
    }

    /* Refresh allocation/capacity/perms */
    if (virStorageBackendUpdateVolInfo(vol, 1) < 0)
        return -1;

    /* set partition type */
    if (STREQ(groups[1], "normal"))
       vol->target.type = VIR_STORAGE_VOL_DISK_TYPE_PRIMARY;
    else if (STREQ(groups[1], "logical"))
       vol->target.type = VIR_STORAGE_VOL_DISK_TYPE_LOGICAL;
    else if (STREQ(groups[1], "extended"))
       vol->target.type = VIR_STORAGE_VOL_DISK_TYPE_EXTENDED;
    else
       vol->target.type = VIR_STORAGE_VOL_DISK_TYPE_NONE;

    vol->type = VIR_STORAGE_VOL_BLOCK;

    /* The above gets allocation wrong for
     * extended partitions, so overwrite it */
    vol->allocation = vol->capacity =
        (vol->source.extents[0].end - vol->source.extents[0].start);

    if (STRNEQ(groups[2], "metadata"))
        pool->def->allocation += vol->allocation;
    if (vol->source.extents[0].end > pool->def->capacity)
        pool->def->capacity = vol->source.extents[0].end;

    return 0;
}
/**
 * Iterate over the pool's directory and enumerate all disk images
 * within it. This is non-recursive.
 */
static int
virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED,
                                   virStoragePoolObjPtr pool)
{
    DIR *dir;
    struct dirent *ent;
    struct statvfs sb;
    virStorageVolDefPtr vol = NULL;

    if (!(dir = opendir(pool->def->target.path))) {
        virReportSystemError(errno,
                             _("cannot open path '%s'"),
                             pool->def->target.path);
        goto cleanup;
    }

    while ((ent = readdir(dir)) != NULL) {
        int ret;
        char *backingStore;

        if (VIR_ALLOC(vol) < 0)
            goto no_memory;

        if ((vol->name = strdup(ent->d_name)) == NULL)
            goto no_memory;

        vol->type = VIR_STORAGE_VOL_FILE;
        vol->target.format = VIR_STORAGE_FILE_RAW; /* Real value is filled in during probe */
        if (virAsprintf(&vol->target.path, "%s/%s",
                        pool->def->target.path,
                        vol->name) == -1)
            goto no_memory;

        if ((vol->key = strdup(vol->target.path)) == NULL)
            goto no_memory;

        if ((ret = virStorageBackendProbeTarget(&vol->target,
                                                &backingStore,
                                                &vol->allocation,
                                                &vol->capacity,
                                                &vol->target.encryption)) < 0) {
            if (ret == -1)
                goto cleanup;
            else {
                /* Silently ignore non-regular files,
                 * eg '.' '..', 'lost+found' */
                virStorageVolDefFree(vol);
                vol = NULL;
                continue;
            }
        }

        if (backingStore != NULL) {
            if (vol->target.format == VIR_STORAGE_FILE_QCOW2 &&
                STRPREFIX("fmt:", backingStore)) {
                char *fmtstr = backingStore + 4;
                char *path = strchr(fmtstr, ':');
                if (!path) {
                    VIR_FREE(backingStore);
                } else {
                    *path = '\0';
                    if ((vol->backingStore.format =
                         virStorageFileFormatTypeFromString(fmtstr)) < 0) {
                        VIR_FREE(backingStore);
                    } else {
                        memmove(backingStore, path, strlen(path) + 1);
                        vol->backingStore.path = backingStore;

                        if (virStorageBackendUpdateVolTargetInfo(&vol->backingStore,
                                                                 NULL,
                                                                 NULL) < 0)
                            VIR_FREE(vol->backingStore);
                    }
                }
            } else {
                vol->backingStore.path = backingStore;

                if ((ret = virStorageBackendProbeTarget(&vol->backingStore,
                                                        NULL, NULL, NULL,
                                                        NULL)) < 0) {
                    if (ret == -1)
                        goto cleanup;
                    else {
                        /* Silently ignore non-regular files,
                         * eg '.' '..', 'lost+found' */
                        VIR_FREE(vol->backingStore);
                    }
                }
            }
        }



        if (VIR_REALLOC_N(pool->volumes.objs,
                          pool->volumes.count+1) < 0)
            goto no_memory;
        pool->volumes.objs[pool->volumes.count++] = vol;
        vol = NULL;
    }
    closedir(dir);


    if (statvfs(pool->def->target.path, &sb) < 0) {
        virReportSystemError(errno,
                             _("cannot statvfs path '%s'"),
                             pool->def->target.path);
        return -1;
    }
    pool->def->capacity = ((unsigned long long)sb.f_frsize *
                           (unsigned long long)sb.f_blocks);
    pool->def->available = ((unsigned long long)sb.f_bfree *
                            (unsigned long long)sb.f_bsize);
    pool->def->allocation = pool->def->capacity - pool->def->available;

    return 0;

no_memory:
    virReportOOMError();
    /* fallthrough */

 cleanup:
    if (dir)
        closedir(dir);
    virStorageVolDefFree(vol);
    virStoragePoolObjClearVols(pool);
    return -1;
}
static int
testCompareXMLToArgvFiles(bool shouldFail,
                          const char *poolxml,
                          const char *volxml,
                          const char *inputpoolxml,
                          const char *inputvolxml,
                          const char *cmdline,
                          unsigned int flags,
                          int imgformat,
                          unsigned long parse_flags)
{
    char *actualCmdline = NULL;
    int ret = -1;

    virCommandPtr cmd = NULL;
    virConnectPtr conn;

    virStorageVolDefPtr vol = NULL, inputvol = NULL;
    virStoragePoolDefPtr pool = NULL;
    virStoragePoolDefPtr inputpool = NULL;
    virStoragePoolObj poolobj = {.def = NULL };


    if (!(conn = virGetConnect()))
        goto cleanup;

    if (!(pool = virStoragePoolDefParseFile(poolxml)))
        goto cleanup;

    poolobj.def = pool;

    if (inputpoolxml) {
        if (!(inputpool = virStoragePoolDefParseFile(inputpoolxml)))
            goto cleanup;
    }

    if (inputvolxml)
        parse_flags |= VIR_VOL_XML_PARSE_NO_CAPACITY;

    if (!(vol = virStorageVolDefParseFile(pool, volxml, parse_flags)))
        goto cleanup;

    if (inputvolxml &&
            !(inputvol = virStorageVolDefParseFile(inputpool, inputvolxml, 0)))
        goto cleanup;

    testSetVolumeType(vol, pool);
    testSetVolumeType(inputvol, inputpool);

    cmd = virStorageBackendCreateQemuImgCmdFromVol(conn, &poolobj, vol,
            inputvol, flags,
            create_tool, imgformat);
    if (!cmd) {
        if (shouldFail) {
            virResetLastError();
            ret = 0;
        }
        goto cleanup;
    }

    if (!(actualCmdline = virCommandToString(cmd)))
        goto cleanup;

    if (virTestCompareToFile(actualCmdline, cmdline) < 0)
        goto cleanup;

    ret = 0;

cleanup:
    virStoragePoolDefFree(pool);
    virStoragePoolDefFree(inputpool);
    virStorageVolDefFree(vol);
    virStorageVolDefFree(inputvol);
    virCommandFree(cmd);
    VIR_FREE(actualCmdline);
    virObjectUnref(conn);
    return ret;
}
/*
 * Attempt to create a new LUN
 *
 * Returns:
 *
 *  0  => Success
 *  -1 => Failure due to some sort of OOM or other fatal issue found when
 *        attempting to get/update information about a found volume
 *  -2 => Failure to find a stable path, not fatal, caller can try another
 */
static int
virStorageBackendSCSINewLun(virStoragePoolObjPtr pool,
                            uint32_t host ATTRIBUTE_UNUSED,
                            uint32_t bus,
                            uint32_t target,
                            uint32_t lun,
                            const char *dev)
{
    virStorageVolDefPtr vol = NULL;
    char *devpath = NULL;
    int retval = -1;

    /* Check if the pool is using a stable target path. The call to
     * virStorageBackendStablePath will fail if the pool target path
     * isn't stable and just return the strdup'd 'devpath' anyway.
     * This would be indistinguishable to failing to find the stable
     * path to the device if the virDirRead loop to search the
     * target pool path for our devpath had failed.
     */
    if (!virStorageBackendPoolPathIsStable(pool->def->target.path) &&
        !(STREQ(pool->def->target.path, "/dev") ||
          STREQ(pool->def->target.path, "/dev/"))) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unable to use target path '%s' for dev '%s'"),
                       NULLSTR(pool->def->target.path), dev);
        goto cleanup;
    }

    if (VIR_ALLOC(vol) < 0)
        goto cleanup;

    vol->type = VIR_STORAGE_VOL_BLOCK;

    /* 'host' is dynamically allocated by the kernel, first come,
     * first served, per HBA. As such it isn't suitable for use
     * in the volume name. We only need uniqueness per-pool, so
     * just leave 'host' out
     */
    if (virAsprintf(&(vol->name), "unit:%u:%u:%u", bus, target, lun) < 0)
        goto cleanup;

    if (virAsprintf(&devpath, "/dev/%s", dev) < 0)
        goto cleanup;

    VIR_DEBUG("Trying to create volume for '%s'", devpath);

    /* Now figure out the stable path
     *
     * XXX this method is O(N) because it scans the pool target
     * dir every time its run. Should figure out a more efficient
     * way of doing this...
     */
    if ((vol->target.path = virStorageBackendStablePath(pool,
                                                        devpath,
                                                        true)) == NULL)
        goto cleanup;

    if (STREQ(devpath, vol->target.path) &&
        !(STREQ(pool->def->target.path, "/dev") ||
          STREQ(pool->def->target.path, "/dev/"))) {

        VIR_DEBUG("No stable path found for '%s' in '%s'",
                  devpath, pool->def->target.path);

        retval = -2;
        goto cleanup;
    }

    /* Allow a volume read failure to ignore or skip this block file */
    if ((retval = virStorageBackendUpdateVolInfo(vol, true,
                                                 VIR_STORAGE_VOL_OPEN_DEFAULT,
                                                 VIR_STORAGE_VOL_READ_NOERROR)) < 0)
        goto cleanup;

    if (!(vol->key = virStorageBackendSCSISerial(vol->target.path)))
        goto cleanup;

    pool->def->capacity += vol->target.capacity;
    pool->def->allocation += vol->target.allocation;

    if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0)
        goto cleanup;

    vol = NULL;
    retval = 0;

 cleanup:
    virStorageVolDefFree(vol);
    VIR_FREE(devpath);
    return retval;
}
Exemple #18
0
static virStorageVolPtr
parallelsStorageVolCreateXMLFrom(virStoragePoolPtr pool,
                                    const char *xmldesc,
                                    virStorageVolPtr clonevol,
                                    unsigned int flags)
{
    parallelsConnPtr privconn = pool->conn->privateData;
    virStoragePoolObjPtr privpool;
    virStorageVolDefPtr privvol = NULL, origvol = NULL;
    virStorageVolPtr ret = NULL;

    virCheckFlags(0, NULL);

    parallelsDriverLock(privconn);
    privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
    parallelsDriverUnlock(privconn);

    if (privpool == NULL) {
        parallelsPoolNotFoundError(pool->name);
        goto cleanup;
    }

    if (!virStoragePoolObjIsActive(privpool)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("storage pool '%s' is not active"), pool->name);
        goto cleanup;
    }

    privvol = virStorageVolDefParseString(privpool->def, xmldesc);
    if (privvol == NULL)
        goto cleanup;

    if (virStorageVolDefFindByName(privpool, privvol->name)) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("storage vol already exists"));
        goto cleanup;
    }

    origvol = virStorageVolDefFindByName(privpool, clonevol->name);
    if (!origvol) {
        virReportError(VIR_ERR_NO_STORAGE_VOL,
                       _("no storage vol with matching name '%s'"),
                       clonevol->name);
        goto cleanup;
    }

    /* Make sure enough space */
    if ((privpool->def->allocation + privvol->target.allocation) >
        privpool->def->capacity) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Not enough free space in pool for volume '%s'"),
                       privvol->name);
        goto cleanup;
    }
    privpool->def->available = (privpool->def->capacity -
                                privpool->def->allocation);

    if (virAsprintf(&privvol->target.path, "%s/%s",
                    privpool->def->target.path, privvol->name) == -1)
        goto cleanup;

    if (VIR_STRDUP(privvol->key, privvol->target.path) < 0)
        goto cleanup;

    privpool->def->allocation += privvol->target.allocation;
    privpool->def->available = (privpool->def->capacity -
                                privpool->def->allocation);

    if (VIR_APPEND_ELEMENT_COPY(privpool->volumes.objs,
                                privpool->volumes.count, privvol) < 0)
        goto cleanup;

    ret = virGetStorageVol(pool->conn, privpool->def->name,
                           privvol->name, privvol->key,
                           NULL, NULL);
    privvol = NULL;

 cleanup:
    virStorageVolDefFree(privvol);
    if (privpool)
        virStoragePoolObjUnlock(privpool);
    return ret;
}
static int
virStorageBackendSCSINewLun(virStoragePoolObjPtr pool,
                            uint32_t host ATTRIBUTE_UNUSED,
                            uint32_t bus,
                            uint32_t target,
                            uint32_t lun,
                            const char *dev)
{
    virStorageVolDefPtr vol;
    char *devpath = NULL;
    int retval = 0;

    if (VIR_ALLOC(vol) < 0) {
        retval = -1;
        goto out;
    }

    vol->type = VIR_STORAGE_VOL_BLOCK;

    /* 'host' is dynamically allocated by the kernel, first come,
     * first served, per HBA. As such it isn't suitable for use
     * in the volume name. We only need uniqueness per-pool, so
     * just leave 'host' out
     */
    if (virAsprintf(&(vol->name), "unit:%u:%u:%u", bus, target, lun) < 0) {
        retval = -1;
        goto free_vol;
    }

    if (virAsprintf(&devpath, "/dev/%s", dev) < 0) {
        retval = -1;
        goto free_vol;
    }

    VIR_DEBUG("Trying to create volume for '%s'", devpath);

    /* Now figure out the stable path
     *
     * XXX this method is O(N) because it scans the pool target
     * dir every time its run. Should figure out a more efficient
     * way of doing this...
     */
    if ((vol->target.path = virStorageBackendStablePath(pool,
                                                        devpath,
                                                        true)) == NULL) {
        retval = -1;
        goto free_vol;
    }

    if (STREQ(devpath, vol->target.path) &&
        !(STREQ(pool->def->target.path, "/dev") ||
          STREQ(pool->def->target.path, "/dev/"))) {

        VIR_DEBUG("No stable path found for '%s' in '%s'",
                  devpath, pool->def->target.path);

        retval = -1;
        goto free_vol;
    }

    if (virStorageBackendSCSIUpdateVolTargetInfo(&vol->target,
                                                 &vol->allocation,
                                                 &vol->capacity) < 0) {

        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to update volume for '%s'"),
                       devpath);
        retval = -1;
        goto free_vol;
    }

    if (!(vol->key = virStorageBackendSCSISerial(vol->target.path))) {
        retval = -1;
        goto free_vol;
    }

    pool->def->capacity += vol->capacity;
    pool->def->allocation += vol->allocation;

    if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0) {
        retval = -1;
        goto free_vol;
    }

    goto out;

free_vol:
    virStorageVolDefFree(vol);
out:
    VIR_FREE(devpath);
    return retval;
}
Exemple #20
0
static virStorageVolPtr
vboxStorageVolCreateXML(virStoragePoolPtr pool,
                        const char *xml, unsigned int flags)
{
    vboxDriverPtr data = pool->conn->privateData;
    virStorageVolDefPtr def = NULL;
    PRUnichar *hddFormatUtf16 = NULL;
    PRUnichar *hddNameUtf16 = NULL;
    virStoragePoolDef poolDef;
    nsresult rc;
    vboxIID hddIID;
    unsigned char uuid[VIR_UUID_BUFLEN];
    char key[VIR_UUID_STRING_BUFLEN] = "";
    IMedium *hardDisk = NULL;
    IProgress *progress = NULL;
    PRUint64 logicalSize = 0;
    PRUint32 variant = HardDiskVariant_Standard;
    resultCodeUnion resultCode;
    virStorageVolPtr ret = NULL;

    if (!data->vboxObj)
        return ret;

    virCheckFlags(0, NULL);

    /* since there is currently one default pool now
     * and virStorageVolDefFormat() just checks it type
     * so just assign it for now, change the behaviour
     * when vbox supports pools.
     */
    memset(&poolDef, 0, sizeof(poolDef));
    poolDef.type = VIR_STORAGE_POOL_DIR;

    if ((def = virStorageVolDefParseString(&poolDef, xml, 0)) == NULL)
        goto cleanup;

    if (!def->name ||
        (def->type != VIR_STORAGE_VOL_FILE))
        goto cleanup;

    /* For now only the vmdk, vpc and vdi type harddisk
     * variants can be created.  For historical reason, we default to vdi */
    if (def->target.format == VIR_STORAGE_FILE_VMDK) {
        VBOX_UTF8_TO_UTF16("VMDK", &hddFormatUtf16);
    } else if (def->target.format == VIR_STORAGE_FILE_VPC) {
        VBOX_UTF8_TO_UTF16("VHD", &hddFormatUtf16);
    } else {
        VBOX_UTF8_TO_UTF16("VDI", &hddFormatUtf16);
    }

    /* If target.path isn't given, use default path ~/.VirtualBox/image_name */
    if (def->target.path == NULL &&
        virAsprintf(&def->target.path, "%s/.VirtualBox/%s", virGetUserDirectory(), def->name) < 0)
        goto cleanup;
    VBOX_UTF8_TO_UTF16(def->target.path, &hddNameUtf16);

    if (!hddFormatUtf16 || !hddNameUtf16)
        goto cleanup;

    rc = gVBoxAPI.UIVirtualBox.CreateHardDisk(data->vboxObj, hddFormatUtf16, hddNameUtf16, &hardDisk);
    if (NS_FAILED(rc)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not create harddisk, rc=%08x"),
                       (unsigned)rc);
        goto cleanup;
    }

    logicalSize = VIR_DIV_UP(def->target.capacity, 1024 * 1024);

    if (def->target.capacity == def->target.allocation)
        variant = HardDiskVariant_Fixed;

    rc = gVBoxAPI.UIMedium.CreateBaseStorage(hardDisk, logicalSize, variant, &progress);
    if (NS_FAILED(rc) || !progress) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not create base storage, rc=%08x"),
                       (unsigned)rc);
        goto cleanup;
    }

    gVBoxAPI.UIProgress.WaitForCompletion(progress, -1);
    gVBoxAPI.UIProgress.GetResultCode(progress, &resultCode);
    if (RC_FAILED(resultCode)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not create base storage, rc=%08x"),
                       (unsigned)resultCode.uResultCode);
        goto cleanup;
    }

    VBOX_IID_INITIALIZE(&hddIID);
    rc = gVBoxAPI.UIMedium.GetId(hardDisk, &hddIID);
    if (NS_FAILED(rc))
        goto cleanup;

    vboxIIDToUUID(&hddIID, uuid);
    virUUIDFormat(uuid, key);

    ret = virGetStorageVol(pool->conn, pool->name, def->name, key,
                           NULL, NULL);

 cleanup:
    vboxIIDUnalloc(&hddIID);
    VBOX_RELEASE(progress);
    VBOX_UTF16_FREE(hddFormatUtf16);
    VBOX_UTF16_FREE(hddNameUtf16);
    virStorageVolDefFree(def);
    return ret;
}
static int
virStorageBackendLogicalMakeVol(virStoragePoolObjPtr pool,
                                char **const groups,
                                void *data)
{
    virStorageVolDefPtr vol = NULL;
    bool is_new_vol = false;
    unsigned long long offset, size, length;
    const char *regex_unit = "(\\S+)\\((\\S+)\\)";
    char *regex = NULL;
    regex_t *reg = NULL;
    regmatch_t *vars = NULL;
    char *p = NULL;
    size_t i;
    int err, nextents, nvars, ret = -1;
    const char *attrs = groups[9];

    /* Skip inactive volume */
    if (attrs[4] != 'a')
        return 0;

    /*
     * Skip thin pools(t). These show up in normal lvs output
     * but do not have a corresponding /dev/$vg/$lv device that
     * is created by udev. This breaks assumptions in later code.
     */
    if (attrs[0] == 't')
        return 0;

    /* See if we're only looking for a specific volume */
    if (data != NULL) {
        vol = data;
        if (STRNEQ(vol->name, groups[0]))
            return 0;
    }

    /* Or filling in more data on an existing volume */
    if (vol == NULL)
        vol = virStorageVolDefFindByName(pool, groups[0]);

    /* Or a completely new volume */
    if (vol == NULL) {
        if (VIR_ALLOC(vol) < 0)
            return -1;

        is_new_vol = true;
        vol->type = VIR_STORAGE_VOL_BLOCK;

        if (VIR_STRDUP(vol->name, groups[0]) < 0)
            goto cleanup;

        if (VIR_REALLOC_N(pool->volumes.objs,
                          pool->volumes.count + 1))
            goto cleanup;
    }

    if (vol->target.path == NULL) {
        if (virAsprintf(&vol->target.path, "%s/%s",
                        pool->def->target.path, vol->name) < 0)
            goto cleanup;
    }

    /* Skips the backingStore of lv created with "--virtualsize",
     * its original device "/dev/$vgname/$lvname_vorigin" is
     * just for lvm internal use, one should never use it.
     *
     * (lvs outputs "[$lvname_vorigin] for field "origin" if the
     *  lv is created with "--virtualsize").
     */
    if (groups[1] && !STREQ(groups[1], "") && (groups[1][0] != '[')) {
        if (virAsprintf(&vol->backingStore.path, "%s/%s",
                        pool->def->target.path, groups[1]) < 0)
            goto cleanup;

        vol->backingStore.format = VIR_STORAGE_POOL_LOGICAL_LVM2;
    }

    if (!vol->key && VIR_STRDUP(vol->key, groups[2]) < 0)
        goto cleanup;

    if (virStorageBackendUpdateVolInfo(vol, 1) < 0)
        goto cleanup;

    nextents = 1;
    if (STREQ(groups[4], VIR_STORAGE_VOL_LOGICAL_SEGTYPE_STRIPED)) {
        if (virStrToLong_i(groups[5], NULL, 10, &nextents) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("malformed volume extent stripes value"));
            goto cleanup;
        }
    }

    /* Finally fill in extents information */
    if (VIR_REALLOC_N(vol->source.extents,
                      vol->source.nextent + nextents) < 0)
        goto cleanup;

    if (virStrToLong_ull(groups[6], NULL, 10, &length) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("malformed volume extent length value"));
        goto cleanup;
    }
    if (virStrToLong_ull(groups[7], NULL, 10, &size) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("malformed volume extent size value"));
        goto cleanup;
    }
    if (virStrToLong_ull(groups[8], NULL, 10, &vol->allocation) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("malformed volume allocation value"));
        goto cleanup;
    }

    /* Now parse the "devices" field separately */
    if (VIR_STRDUP(regex, regex_unit) < 0)
        goto cleanup;

    for (i = 1; i < nextents; i++) {
        if (VIR_REALLOC_N(regex, strlen(regex) + strlen(regex_unit) + 2) < 0)
            goto cleanup;
        /* "," is the separator of "devices" field */
        strcat(regex, ",");
        strncat(regex, regex_unit, strlen(regex_unit));
    }

    if (VIR_ALLOC(reg) < 0)
        goto cleanup;

    /* Each extent has a "path:offset" pair, and vars[0] will
     * be the whole matched string.
     */
    nvars = (nextents * 2) + 1;
    if (VIR_ALLOC_N(vars, nvars) < 0)
        goto cleanup;

    err = regcomp(reg, regex, REG_EXTENDED);
    if (err != 0) {
        char error[100];
        regerror(err, reg, error, sizeof(error));
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to compile regex %s"),
                       error);
        goto cleanup;
    }

    err = regexec(reg, groups[3], nvars, vars, 0);
    regfree(reg);
    if (err != 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("malformed volume extent devices value"));
        goto cleanup;
    }

    p = groups[3];

    /* vars[0] is skipped */
    for (i = 0; i < nextents; i++) {
        size_t j;
        int len;
        char *offset_str = NULL;

        j = (i * 2) + 1;
        len = vars[j].rm_eo - vars[j].rm_so;
        p[vars[j].rm_eo] = '\0';

        if (VIR_STRNDUP(vol->source.extents[vol->source.nextent].path,
                        p + vars[j].rm_so, len) < 0)
            goto cleanup;

        len = vars[j + 1].rm_eo - vars[j + 1].rm_so;
        if (VIR_STRNDUP(offset_str, p + vars[j + 1].rm_so, len) < 0)
            goto cleanup;

        if (virStrToLong_ull(offset_str, NULL, 10, &offset) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("malformed volume extent offset value"));
            VIR_FREE(offset_str);
            goto cleanup;
        }

        VIR_FREE(offset_str);

        vol->source.extents[vol->source.nextent].start = offset * size;
        vol->source.extents[vol->source.nextent].end = (offset * size) + length;
        vol->source.nextent++;
    }

    if (is_new_vol)
        pool->volumes.objs[pool->volumes.count++] = vol;

    ret = 0;

cleanup:
    VIR_FREE(regex);
    VIR_FREE(reg);
    VIR_FREE(vars);
    if (is_new_vol && (ret == -1))
        virStorageVolDefFree(vol);
    return ret;
}
static int
testCompareXMLToArgvFiles(bool shouldFail,
                          const char *poolxml,
                          const char *volxml,
                          const char *inputpoolxml,
                          const char *inputvolxml,
                          const char *cmdline,
                          unsigned int flags,
                          int imgformat)
{
    char *volXmlData = NULL;
    char *poolXmlData = NULL;
    char *inputpoolXmlData = NULL;
    char *inputvolXmlData = NULL;
    char *expectedCmdline = NULL;
    char *actualCmdline = NULL;
    int ret = -1;

    int len;

    virCommandPtr cmd = NULL;
    virConnectPtr conn;

    virStorageVolDefPtr vol = NULL, inputvol = NULL;
    virStoragePoolDefPtr pool = NULL;
    virStoragePoolDefPtr inputpool = NULL;
    virStoragePoolObj poolobj = {.def = NULL };


    if (!(conn = virGetConnect()))
        goto cleanup;

    if (virtTestLoadFile(poolxml, &poolXmlData) < 0)
        goto cleanup;
    if (virtTestLoadFile(volxml, &volXmlData) < 0)
        goto cleanup;
    if (inputvolxml &&
        virtTestLoadFile(inputvolxml, &inputvolXmlData) < 0)
        goto cleanup;

    if (!(pool = virStoragePoolDefParseString(poolXmlData)))
        goto cleanup;

    poolobj.def = pool;

    if (inputpoolxml) {
        if (virtTestLoadFile(inputpoolxml, &inputpoolXmlData) < 0)
            goto cleanup;
        if (!(inputpool = virStoragePoolDefParseString(inputpoolXmlData)))
            goto cleanup;
    }

    if (!(vol = virStorageVolDefParseString(pool, volXmlData)))
        goto cleanup;

    if (inputvolxml &&
        !(inputvol = virStorageVolDefParseString(inputpool, inputvolXmlData)))
        goto cleanup;

    testSetVolumeType(vol, pool);
    testSetVolumeType(inputvol, inputpool);

    cmd = virStorageBackendCreateQemuImgCmd(conn, &poolobj, vol, inputvol,
                                            flags, create_tool, imgformat);
    if (!cmd) {
        if (shouldFail) {
            virResetLastError();
            ret = 0;
        }
        goto cleanup;
    }

    if (!(actualCmdline = virCommandToString(cmd)))
        goto cleanup;

    len = virtTestLoadFile(cmdline, &expectedCmdline);
    if (len < 0)
        goto cleanup;
    if (len && expectedCmdline[len-1] == '\n')
        expectedCmdline[len-1] = '\0';

    if (STRNEQ_NULLABLE(expectedCmdline, actualCmdline)) {
        virtTestDifference(stderr, expectedCmdline, actualCmdline);
        goto cleanup;
    }

    ret = 0;

cleanup:
    virStoragePoolDefFree(pool);
    virStoragePoolDefFree(inputpool);
    virStorageVolDefFree(vol);
    virStorageVolDefFree(inputvol);
    virCommandFree(cmd);
    VIR_FREE(actualCmdline);
    VIR_FREE(expectedCmdline);
    VIR_FREE(inputpoolXmlData);
    VIR_FREE(poolXmlData);
    VIR_FREE(volXmlData);
    VIR_FREE(inputvolXmlData);
    virObjectUnref(conn);
    return ret;
}