[Libvir] PATCH: 9/16: main internal storage driver
Daniel P. Berrange
berrange at redhat.com
Mon Feb 18 15:59:54 UTC 2008
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 -=|
More information about the libvir-list
mailing list