
On Mon, Feb 18, 2008 at 09:51:28AM -0500, Daniel Veillard wrote:
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 ?
Yes a (harmless) bug -- I'll updated the numbers to remove the gap
+ VIR_STORAGE_BACKEND_POOL_SOURCE_DIR = (1<<3), + VIR_STORAGE_BACKEND_POOL_SOURCE_ADAPTER = (1<<4), +};
+ 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.
Yes will fix that.
+ 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.
Ok, reasonable enough.
+ 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.
Yes, I did 'make syntax-check' but seems to have missed those
+ 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
Well the format field is optional - not all pools support volumes with special formats. Fs/dir driver supports raw, qcow, vmdk, etc. The iSCSI driver though doesn't support any - you just get a block device, no choice, so the formatFromString and formatToString functions are not needed.
+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
The caller will never pass in a 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.
Yep, we know the caller won't pass in a NULL in this internal method.
[...]
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.
This isn't really error reporting - its just for a few harmless debug messages. We don't have any API for propagating log messages back to the application, though I've proposed it once before...
+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.
Yep, good idea.
+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
Hmm, yes, should return -1 if deletePool is not supported by the driver
+ +static int storagePoolRefresh(virStoragePoolPtr obj, + unsigned int flags ATTRIBUTE_UNUSED) {
we assume backend->refreshPool is always there, maybe a test is in order.
refreshPool & refreshVol are the two compulsory drivers methods for the backend, all the rest are optional. There's not much point in checking because anyone adding a new driver will immediately find that they're required because nothing will work without them Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|