[Libvir] PATCH: 9/16: main internal storage driver
Daniel Veillard
veillard at redhat.com
Mon Feb 18 14:51:28 UTC 2008
On Tue, Feb 12, 2008 at 04:36:04AM +0000, Daniel P. Berrange wrote:
> This patch provides the general purpose code for the storage driver.
> The storage_driver.{c,h} file implements the libvirt internal storage
> driver API. The storage_conf.{c,h} file takes care of parsing and
> formatting the XML for pools and volumes. This should be reusable by
> the test driver's impl of the storage APIs in the future. The final
> storage_backend.{c,h} file provides a 2nd level internal driver API.
> This allows the main storage driver to call into storage pool specific
> impls for iSCSI, disk, filesystem, LVM and more. The storage_backend.h
> definitions allow the specific drivers to declare particular parts of
> the generic pool XML which are mandatory. For example, a disk pool
> always requires a source device element.
[...]
> +/* Flags to indicate mandatory components in the pool source */
> +enum {
> + VIR_STORAGE_BACKEND_POOL_SOURCE_HOST = (1<<0),
> + VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE = (1<<1),
wondering about 1<<2 , is that the storage option your removed compared
to previous patches ?
> + VIR_STORAGE_BACKEND_POOL_SOURCE_DIR = (1<<3),
> + VIR_STORAGE_BACKEND_POOL_SOURCE_ADAPTER = (1<<4),
> +};
[...]
> +static virStoragePoolDefPtr virStoragePoolDefParseDoc(virConnectPtr conn,
> + xmlXPathContextPtr ctxt, xmlNodePtr root) {
[...]
> + if (options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE) {
> + xmlNodePtr *nodeset = NULL;
> + int nsource, i;
> +
> + if ((nsource = virXPathNodeSet("/pool/source/device", ctxt, &nodeset)) <= 0) {
> + virStorageReportError(conn, VIR_ERR_XML_ERROR, "cannot extract source devices");
> + goto cleanup;
> + }
> + if ((ret->source.devices = calloc(nsource, sizeof(*ret->source.devices))) == NULL) {
> + free(nodeset);
> + virStorageReportError(conn, VIR_ERR_NO_MEMORY, "device");
> + goto cleanup;
> + }
> + for (i = 0 ; i < nsource ; i++) {
> + xmlChar *path = xmlGetProp(nodeset[i], BAD_CAST "path");
> + if (path == NULL) {
> + virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing source device path");
hum nodeset is leaked here it seems.
> + goto cleanup;
> + }
> + ret->source.devices[i].path = (char *)path;
> + }
> + free(nodeset);
> + ret->source.ndevice = nsource;
> + }
[...]
> + authType = virXPathString("string(/pool/source/auth/@type)", ctxt);
> + if (authType == NULL) {
> + ret->source.authType = VIR_STORAGE_POOL_AUTH_NONE;
> + } else {
> + if (STREQ(authType, "chap")) {
> + ret->source.authType = VIR_STORAGE_POOL_AUTH_CHAP;
> + } else {
> + virStorageReportError(conn, VIR_ERR_XML_ERROR, "unknown auth type '%s'", (const char *)authType);
> + goto cleanup;
hum, the cleanup of authType is more complex than necessary, i would just
free(authType); here before goto cleanup;
> + }
> + free(authType);
> + authType = NULL;
remove this affectation
> + }
> +
[...]
> + return ret;
> +
> + cleanup:
> + free(uuid);
> + if (type)
> + xmlFree(type);
> + if (authType)
> + xmlFree(authType);
and remove this, basically keeping authType processing to just the block
where it is used.
> + virStoragePoolDefFree(ret);
> + return NULL;
> +}
> +
> +virStoragePoolDefPtr virStoragePoolDefParse(virConnectPtr conn,
> + const char *xmlStr, const char *filename) {
> + virStoragePoolDefPtr ret = NULL;
> + xmlDocPtr xml = NULL;
> + xmlNodePtr node = NULL;
> + xmlXPathContextPtr ctxt = NULL;
> +
[...]
> + xmlFreeDoc(xml);
> +
> + return ret;
> +
> + cleanup:
> + xmlXPathFreeContext(ctxt);
> + if (xml)
> + xmlFreeDoc(xml);
> + return NULL;
> +}
since we try to remove if (x) free(x) style, just call xmlFreeDoc(xml);
since xmlFreeDoc handles NULLs fine.
[...]
> + cleanup:
> + if (buf) virBufferFree(buf);
same here
> + return NULL;
[...]
> + ret->target.path = virXPathString("string(/volume/target/path)", ctxt);
> + if (options->formatFromString) {
> + char *format = virXPathString("string(/volume/target/format/@type)", ctxt);
> + if ((ret->target.format = (options->formatFromString)(conn, format)) < 0) {
So you have in a structure an optional function to do the formatting,
feels a bit strange, but okay
[...]
> + if (xml)
> + xmlFreeDoc(xml);
one more, they can probably be all cleaned up after the commit anyway
[...]
> +static virStoragePoolObjPtr
> +virStoragePoolObjLoad(virStorageDriverStatePtr driver,
> + const char *file,
> + const char *path,
> + const char *xml,
> + const char *autostartLink) {
> + virStoragePoolDefPtr def;
> + virStoragePoolObjPtr pool;
> +
> + if (!(def = virStoragePoolDefParse(NULL, xml, file))) {
> + virErrorPtr err = virGetLastError();
> + virStorageLog("Error parsing storage pool config '%s' : %s",
> + path, err->message);
> + return NULL;
> + }
> +
> + if (!virFileMatchesNameSuffix(file, def->name, ".xml")) {
> + virStorageLog("Storage Pool config filename '%s' does not match pool name '%s'",
> + path, def->name);
> + virStoragePoolDefFree(def);
> + return NULL;
> + }
> +
> + if (!(pool = virStoragePoolObjAssignDef(NULL, driver, def))) {
> + virStorageLog("Failed to load storage pool config '%s': out of memory", path);
> + virStoragePoolDefFree(def);
> + return NULL;
> + }
Shouldn't autostartLink and path be checked against NULL
> + pool->configFile = strdup(path);
> + if (pool->configFile == NULL) {
> + virStorageLog("Failed to load storage pool config '%s': out of memory", path);
> + virStoragePoolDefFree(def);
> + return NULL;
> + }
> + pool->autostartLink = strdup(autostartLink);
> + if (pool->autostartLink == NULL) {
> + virStorageLog("Failed to load storage pool config '%s': out of memory", path);
> + virStoragePoolDefFree(def);
> + return NULL;
> + }
Since that seems assumed in that function, okay it is not public, so
if internally we know the value is never NULL, fine, but otherwise we would
get a confusing error message.
[...]
> diff -r 77cf7f42edd4 src/storage_driver.c
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/src/storage_driver.c Thu Feb 07 12:59:40 2008 -0500
[...]
> +#define storageLog(msg...) fprintf(stderr, msg)
any way to integrate into normal error reporting ? But that should not
block from commiting to CVs.
[...]
> +static int storageListPools(virConnectPtr conn, char **const names, int nnames) {
> + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)conn->storagePrivateData;
> + virStoragePoolObjPtr pool = driver->pools;
> + int got = 0, i;
> + while (pool && got < nnames) {
> + if (virStoragePoolObjIsActive(pool)) {
> + if (!(names[got] = strdup(pool->def->name))) {
> + virStorageReportError(conn, VIR_ERR_NO_MEMORY, "names");
> + goto cleanup;
> + }
> + got++;
> + }
> + pool = pool->next;
> + }
> + return got;
> +
> + cleanup:
> + for (i = 0 ; i < got ; i++) {
> + free(names[i]);
> + names[i] = NULL;
> + }
Hum, that looks right, but when passed a array like that it may be a
good idea to memset(0) it it can help triggering errors early or the task
of debugging.
[...]
> +
> +static int storageListDefinedPools(virConnectPtr conn, char **const names, int nnames) {
> + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)conn->storagePrivateData;
> + virStoragePoolObjPtr pool = driver->pools;
> + int got = 0, i;
> + while (pool && got < nnames) {
> + if (!virStoragePoolObjIsActive(pool)) {
> + if (!(names[got] = strdup(pool->def->name))) {
> + virStorageReportError(conn, VIR_ERR_NO_MEMORY, "names");
> + goto cleanup;
> + }
> + got++;
> + }
> + pool = pool->next;
> + }
> + return got;
> +
> + cleanup:
> + for (i = 0 ; i < got ; i++) {
> + free(names[i]);
> + names[i] = NULL;
> + }
> + return -1;
> +}
Similar here.
[...]
> +static int storagePoolDelete(virStoragePoolPtr obj,
> + unsigned int flags) {
> + virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->conn->storagePrivateData;
> + virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
> + virStorageBackendPtr backend;
> +
> + if (!pool) {
> + virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
> + "no storage pool with matching uuid");
> + return -1;
> + }
> +
> + if ((backend = virStorageBackendForType(pool->def->type)) == NULL) {
> + return -1;
> + }
> +
> + if (virStoragePoolObjIsActive(pool)) {
> + virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
> + "storage pool is still active");
> + return -1;
> + }
> +
> + if (backend->deletePool &&
> + backend->deletePool(obj->conn, pool, flags) < 0)
> + return -1;
> +
> + return 0;
> +}
So you return 0 is the backend has no deletePool defined, looks a bit strange
> +
> +static int storagePoolRefresh(virStoragePoolPtr obj,
> + unsigned int flags ATTRIBUTE_UNUSED) {
we assume backend->refreshPool is always there, maybe a test is in
order.
> + if ((ret = backend->refreshPool(obj->conn, pool)) < 0) {
> + if (backend->stopPool)
> + backend->stopPool(obj->conn, pool);
okay, huge, but looks fine.
One thing I realize is that it adds a lot of new strings for localization
so it's better to push early if we want to get decent translations.
Daniel
--
Red Hat Virtualization group http://redhat.com/virtualization/
Daniel Veillard | virtualization library http://libvirt.org/
veillard at redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/
http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/
More information about the libvir-list
mailing list