[libvirt] [PATCH v2 8/9] pvs: add storage driver

Stefan Berger stefanb at linux.vnet.ibm.com
Wed Apr 18 19:53:03 UTC 2012


On 04/18/2012 02:07 PM, Dmitry Guryanov wrote:
> PVS has one serious discrepancy with libvirt: libvirt stores
> domain configuration files always in one place, and storage files
> in other places (with API of storage pools and storage volumes).
> PVS store all domain data in a single directory, for example, you
> may have domain with name fedora-15, which will be located in
> '/var/parallels/fedora-15.pvm', and it's hard disk image will be
> in '/var/parallels/fedora-15.pvm/harddisk1.hdd'.
>
> I've decided to create storage driver, which produces pseudo-volumes
> (xml files with volume description), and they will be 'converted' to
> real disk images after attaching to a VM.
>
> So if someone creates VM with one hard disk using virt-manager,
> at first virt-manager creates a new volume, and then defines a
> domain. We can lookup a volume by path in XML domain definition
> and find out location of new domain and size of its hard disk.
>
> This code mostly duplicates code in libvirt's default storage
> driver, but I haven't found, how functions from that driver can
> be reused. So if it possible I'll be very grateful for the advice,
> how to do it.
>

[...]

> +
> +static int
> +pvsFindVolumes(virStoragePoolObjPtr pool)
> +{
> +    int ret;
> +    DIR *dir;
> +    struct dirent *ent;
> +    char *path;
> +
> +    if (!(dir = opendir(pool->def->target.path))) {
> +        virReportSystemError(errno,
> +                             _("cannot open path '%s'"),
> +                             pool->def->target.path);
> +        goto cleanup;

Need to set ret = -1.

> +    }
> +
> +    while ((ent = readdir(dir)) != NULL) {
> +        if (!virFileHasSuffix(ent->d_name, ".xml"))
> +            continue;
> +
> +        if (!(path = virFileBuildPath(pool->def->target.path,
> +                                      ent->d_name, NULL)))
> +            goto no_memory;
> +        if (!pvsStorageVolumeDefine(pool, NULL, path, false))
> +            goto cleanup;
> +        VIR_FREE(path);
> +    }
> +

Nothing assigns a value to ret...

> +    return ret;
> +  no_memory:
> +    virReportOOMError();
> +  cleanup:
> +    return ret;
> +
> +}
> +
> +static virDrvOpenStatus
> +pvsStorageOpen(virConnectPtr conn,
> +               virConnectAuthPtr auth ATTRIBUTE_UNUSED, unsigned int flags)
> +{
> +    char *base = NULL;
> +    virStorageDriverStatePtr storageState;
> +    int privileged = (geteuid() == 0);
> +    pvsConnPtr privconn = conn->privateData;
> +    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
> +
> +    if (STRNEQ(conn->driver->name, "PVS"))
> +        return VIR_DRV_OPEN_DECLINED;
> +
> +    if (VIR_ALLOC(storageState)<  0)
> +        return VIR_DRV_OPEN_ERROR;

virReportOOMError() ?


> +
> +    if (virMutexInit(&storageState->lock)<  0) {
> +        VIR_FREE(storageState);
> +        return VIR_DRV_OPEN_ERROR;
> +    }
> +    pvsStorageLock(storageState);
> +
> +    if (privileged) {
> +        if ((base = strdup(SYSCONFDIR "/libvirt")) == NULL)
> +            goto out_of_memory;
> +    } else {
> +        uid_t uid = geteuid();
> +
> +        char *userdir = virGetUserDirectory(uid);
> +
> +        if (!userdir)
> +            goto error;
> +
> +        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
> +            VIR_FREE(userdir);
> +            goto out_of_memory;
> +        }
> +        VIR_FREE(userdir);
> +    }
> +
> +    /* Configuration paths are either ~/.libvirt/storage/... (session) or
> +     * /etc/libvirt/storage/... (system).
> +     */
> +    if (virAsprintf(&storageState->configDir,
> +                    "%s/pvs-storage", base) == -1)
> +        goto out_of_memory;
> +
> +    if (virAsprintf(&storageState->autostartDir,
> +                    "%s/pvs-storage/autostart", base) == -1)
> +        goto out_of_memory;
> +
> +    VIR_FREE(base);
> +
> +    if (virStoragePoolLoadAllConfigs(&privconn->pools,
> +                                     storageState->configDir,
> +                                     storageState->autostartDir)<  0) {
> +        pvsError(VIR_ERR_INTERNAL_ERROR, _("Failed to load pool configs"));
> +        goto error;
> +    }
> +
> +    for (int i = 0; i<  privconn->pools.count; i++) {
> +        virStoragePoolObjLock(privconn->pools.objs[i]);
> +        virStoragePoolObjPtr pool;
> +
> +        pool = privconn->pools.objs[i];
> +        if (pool->autostart)
> +            pool->active = 1;
> +        pool->active = 1;

pool is always active ? test before seems redundant

> +
> +		if (pvsStoragePoolGetAlloc(pool->def))

< 0 check

> +			goto error;
> +
> +        if (pvsFindVolumes(pool))

< 0 check ?

> +            goto error;
> +
> +        virStoragePoolObjUnlock(privconn->pools.objs[i]);
> +    }
> +
> +    pvsStorageUnlock(storageState);
> +
> +    conn->storagePrivateData = storageState;
> +
> +    return VIR_DRV_OPEN_SUCCESS;
> +
> +  out_of_memory:
> +    virReportOOMError();
> +  error:
> +    VIR_FREE(base);
> +    pvsStorageUnlock(storageState);
> +    pvsStorageClose(conn);
> +    return -1;
> +}
> +
> +static int
> +pvsStorageClose(virConnectPtr conn)
> +{
> +    pvsConnPtr privconn = conn->privateData;
> +    virStorageDriverStatePtr storageState = conn->storagePrivateData;

add empty line here after var decl.

> +    conn->storagePrivateData = NULL;
> +
> +    pvsStorageLock(storageState);
> +    virStoragePoolObjListFree(&privconn->pools);+
> +/*
> + * Fill capacity, available and allocation
> + * fields in pool definition.
> + */
> +static int
> +pvsStoragePoolGetAlloc(virStoragePoolDefPtr def)
> +{
> +	struct statvfs sb;
> +

Different spacing here?

> +	if (statvfs(def->target.path,&sb)<  0) {
> +		virReportSystemError(errno,
> +							 _("cannot statvfs path '%s'"),
> +							 def->target.path);
> +		return -1;
> +	}
> +
> +	def->capacity = ((unsigned long long)sb.f_frsize *
> +					 (unsigned long long)sb.f_blocks);
> +	def->available = ((unsigned long long)sb.f_bfree *
> +							(unsigned long long)sb.f_bsize);
> +	def->allocation = def->capacity - def->available;
> +
> +	return 0;
> +}
> +
> +static virStoragePoolPtr
> +pvsStoragePoolDefine(virConnectPtr conn,
> +                     const char *xml, unsigned int flags)
> +{
[...]
> +
> +    if (virStoragePoolSourceFindDuplicate(&privconn->pools, def)<  0)
> +        goto cleanup;
> +
> +	if (pvsStoragePoolGetAlloc(def))
> +		goto cleanup;

Spacing...

> +pvsStoragePoolDestroy(virStoragePoolPtr pool)
> +{
> +    pvsConnPtr privconn = pool->conn->privateData;
> +    virStoragePoolObjPtr privpool;
> +    int ret = -1;
> +
> +    pvsDriverLock(privconn);
> +    privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
> +
> +    if (privpool == NULL) {
> +        pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
> +        goto cleanup;
> +    }
> +
> +    if (!virStoragePoolObjIsActive(privpool)) {
> +        pvsError(VIR_ERR_OPERATION_INVALID,
> +                 _("storage pool '%s' is not active"), pool->name);
> +        goto cleanup;
> +    }
> +
> +    privpool->active = 0;
> +

No need to set this...


> +pvsStorageVolumeDefine(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)) {
> +        pvsError(VIR_ERR_OPERATION_FAILED,
> +                 "%s", _("storage vol already exists"));
> +        goto cleanup;
> +    }
> +
> +    if (is_new) {
> +        /* Make sure enough space */
> +        if ((pool->def->allocation + privvol->allocation)>
> +            pool->def->capacity) {
> +            pvsError(VIR_ERR_INTERNAL_ERROR,
> +                     _("Not enough free space in pool for volume '%s'"),
> +                     privvol->name);
> +            goto cleanup;
> +        }
> +    }
> +
> +    if (VIR_REALLOC_N(pool->volumes.objs, pool->volumes.count + 1)<  0) {
> +        virReportOOMError();
> +        goto cleanup;
> +    }
> +
> +    if (virAsprintf(&privvol->target.path, "%s/%s",
> +                    pool->def->target.path, privvol->name) == -1) {

Nit: < 0

> +static virStorageVolPtr
> +pvsStorageVolumeCreateXML(virStoragePoolPtr pool,
> +                          const char *xmldesc, unsigned int flags)
> +{
> +    pvsConnPtr privconn = pool->conn->privateData;
> +    virStoragePoolObjPtr privpool;
> +    virStorageVolPtr ret = NULL;
> +    virStorageVolDefPtr privvol = NULL;
> +
> +    virCheckFlags(0, NULL);
> +
> +    pvsDriverLock(privconn);
> +    privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
> +    pvsDriverUnlock(privconn);
> +
> +    if (privpool == NULL) {
> +        pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
> +        goto cleanup;
> +    }
> +
> +    if (!virStoragePoolObjIsActive(privpool)) {
> +        pvsError(VIR_ERR_OPERATION_INVALID,
> +                 _("storage pool '%s' is not active"), pool->name);
> +        goto cleanup;
> +    }
> +
> +    privvol = pvsStorageVolumeDefine(privpool, xmldesc, NULL, true);
> +

NULL pointer test?

> +/*
> + * Return new file path in malloced string created by
> + * concatenating first and second function arguments.
> + */
> +char *
> +pvsAddFileExt(const char *path, const char *ext)
> +{
> +    char *new_path = NULL;
> +    size_t len = strlen(path) + strlen(ext) + 1;
> +
> +    if (VIR_ALLOC_N(new_path, len)<  0)
> +        return NULL;
> +

Nit: virReportOOMError() right where it happens rather than at the callers

> +    if (!virStrcpy(new_path, path, len))
> +        return NULL;
> +    strcat(new_path, ext);
> +
> +    return new_path;
> +}




More information about the libvir-list mailing list