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; }
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; }
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; }
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; }
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; }
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; }
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; }