/* * storage_driver.c: core driver for storage APIs * * Copyright (C) 2006-2008 Red Hat, Inc. * Copyright (C) 2006-2008 Daniel P. Berrange * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Daniel P. Berrange */ #include #include #include #include #if HAVE_PWD_H #include #endif #include #include #include "virterror_internal.h" #include "datatypes.h" #include "driver.h" #include "util.h" #include "storage_driver.h" #include "storage_conf.h" #include "memory.h" #include "storage_backend.h" #define storageLog(msg...) fprintf(stderr, msg) static virStorageDriverStatePtr driverState; static int storageDriverShutdown(void); static void storageDriverLock(virStorageDriverStatePtr driver) { pthread_mutex_lock(&driver->lock); } static void storageDriverUnlock(virStorageDriverStatePtr driver) { pthread_mutex_unlock(&driver->lock); } static void storageDriverAutostart(virStorageDriverStatePtr driver) { unsigned int i; for (i = 0 ; i < driver->pools.count ; i++) { virStoragePoolObjPtr pool = driver->pools.objs[i]; virStoragePoolObjLock(pool); if (pool->autostart && !virStoragePoolObjIsActive(pool)) { virStorageBackendPtr backend; if ((backend = virStorageBackendForType(pool->def->type)) == NULL) { storageLog("Missing backend %d", pool->def->type); virStoragePoolObjUnlock(pool); continue; } if (backend->startPool && backend->startPool(NULL, pool) < 0) { virErrorPtr err = virGetLastError(); storageLog("Failed to autostart storage pool '%s': %s", pool->def->name, err ? err->message : NULL); virStoragePoolObjUnlock(pool); continue; } if (backend->refreshPool(NULL, pool) < 0) { virErrorPtr err = virGetLastError(); if (backend->stopPool) backend->stopPool(NULL, pool); storageLog("Failed to autostart storage pool '%s': %s", pool->def->name, err ? err->message : NULL); virStoragePoolObjUnlock(pool); continue; } pool->active = 1; } virStoragePoolObjUnlock(pool); } } /** * virStorageStartup: * * Initialization function for the QEmu daemon */ static int storageDriverStartup(void) { uid_t uid = geteuid(); struct passwd *pw; char *base = NULL; char driverConf[PATH_MAX]; if (VIR_ALLOC(driverState) < 0) return -1; pthread_mutex_init(&driverState->lock, NULL); storageDriverLock(driverState); if (!uid) { if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL) goto out_of_memory; } else { if (!(pw = getpwuid(uid))) { storageLog("Failed to find user record for uid '%d': %s", uid, strerror(errno)); goto out_of_memory; } if (asprintf (&base, "%s/.libvirt", pw->pw_dir) == -1) { storageLog("out of memory in asprintf"); goto out_of_memory; } } /* Configuration paths are either ~/.libvirt/storage/... (session) or * /etc/libvirt/storage/... (system). */ if (snprintf (driverConf, sizeof(driverConf), "%s/storage.conf", base) == -1) goto out_of_memory; driverConf[sizeof(driverConf)-1] = '\0'; if (asprintf (&driverState->configDir, "%s/storage", base) == -1) goto out_of_memory; if (asprintf (&driverState->autostartDir, "%s/storage/autostart", base) == -1) goto out_of_memory; VIR_FREE(base); /* if (virStorageLoadDriverConfig(driver, driverConf) < 0) { virStorageDriverShutdown(); return -1; } */ if (virStoragePoolLoadAllConfigs(NULL, &driverState->pools, driverState->configDir, driverState->autostartDir) < 0) goto error; storageDriverAutostart(driverState); storageDriverUnlock(driverState); return 0; out_of_memory: storageLog("virStorageStartup: out of memory"); error: VIR_FREE(base); storageDriverUnlock(driverState); storageDriverShutdown(); return -1; } /** * virStorageReload: * * Function to restart the storage driver, it will recheck the configuration * files and update its state */ static int storageDriverReload(void) { if (!driverState) return -1; storageDriverLock(driverState); virStoragePoolLoadAllConfigs(NULL, &driverState->pools, driverState->configDir, driverState->autostartDir); storageDriverAutostart(driverState); storageDriverUnlock(driverState); return 0; } /** * virStorageActive: * * Checks if the storage driver is active, i.e. has an active pool * * Returns 1 if active, 0 otherwise */ static int storageDriverActive(void) { unsigned int i; int active = 0; if (!driverState) return 0; storageDriverLock(driverState); for (i = 0 ; i < driverState->pools.count ; i++) { virStoragePoolObjLock(driverState->pools.objs[i]); if (virStoragePoolObjIsActive(driverState->pools.objs[i])) active = 1; virStoragePoolObjUnlock(driverState->pools.objs[i]); } storageDriverUnlock(driverState); return active; } /** * virStorageShutdown: * * Shutdown the storage driver, it will stop all active storage pools */ static int storageDriverShutdown(void) { unsigned int i; if (!driverState) return -1; storageDriverLock(driverState); /* shutdown active pools */ for (i = 0 ; i < driverState->pools.count ; i++) { virStoragePoolObjPtr pool = driverState->pools.objs[i]; if (virStoragePoolObjIsActive(pool)) { virStorageBackendPtr backend; if ((backend = virStorageBackendForType(pool->def->type)) == NULL) { storageLog("Missing backend"); continue; } if (backend->stopPool && backend->stopPool(NULL, pool) < 0) { virErrorPtr err = virGetLastError(); storageLog("Failed to stop storage pool '%s': %s", pool->def->name, err ? err->message : NULL); } virStoragePoolObjClearVols(pool); } } /* free inactive pools */ virStoragePoolObjListFree(&driverState->pools); VIR_FREE(driverState->configDir); VIR_FREE(driverState->autostartDir); storageDriverUnlock(driverState); VIR_FREE(driverState); return 0; } static virStoragePoolPtr storagePoolLookupByUUID(virConnectPtr conn, const unsigned char *uuid) { virStorageDriverStatePtr driver = conn->storagePrivateData; virStoragePoolObjPtr pool; virStoragePoolPtr ret = NULL; storageDriverLock(driver); pool = virStoragePoolObjFindByUUID(&driver->pools, uuid); storageDriverUnlock(driver); if (!pool) { virStorageReportError(conn, VIR_ERR_NO_STORAGE_POOL, "%s", _("no pool with matching uuid")); goto cleanup; } ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid); cleanup: if (pool) virStoragePoolObjUnlock(pool); return ret; } static virStoragePoolPtr storagePoolLookupByName(virConnectPtr conn, const char *name) { virStorageDriverStatePtr driver = conn->storagePrivateData; virStoragePoolObjPtr pool; virStoragePoolPtr ret = NULL; storageDriverLock(driver); pool = virStoragePoolObjFindByName(&driver->pools, name); storageDriverUnlock(driver); if (!pool) { virStorageReportError(conn, VIR_ERR_NO_STORAGE_POOL, "%s", _("no pool with matching name")); goto cleanup; } ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid); cleanup: if (pool) virStoragePoolObjUnlock(pool); return ret; } static virStoragePoolPtr storagePoolLookupByVolume(virStorageVolPtr vol) { return storagePoolLookupByName(vol->conn, vol->pool); } static virDrvOpenStatus storageOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED) { if (!driverState) return VIR_DRV_OPEN_DECLINED; conn->storagePrivateData = driverState; return VIR_DRV_OPEN_SUCCESS; } static int storageClose(virConnectPtr conn) { conn->storagePrivateData = NULL; return 0; } static int storageNumPools(virConnectPtr conn) { virStorageDriverStatePtr driver = conn->storagePrivateData; unsigned int i, nactive = 0; storageDriverLock(driver); for (i = 0 ; i < driver->pools.count ; i++) { virStoragePoolObjLock(driver->pools.objs[i]); if (virStoragePoolObjIsActive(driver->pools.objs[i])) nactive++; virStoragePoolObjUnlock(driver->pools.objs[i]); } storageDriverUnlock(driver); return nactive; } static int storageListPools(virConnectPtr conn, char **const names, int nnames) { virStorageDriverStatePtr driver = conn->storagePrivateData; int got = 0, i; storageDriverLock(driver); for (i = 0 ; i < driver->pools.count && got < nnames ; i++) { virStoragePoolObjLock(driver->pools.objs[i]); if (virStoragePoolObjIsActive(driver->pools.objs[i])) { if (!(names[got] = strdup(driver->pools.objs[i]->def->name))) { virStoragePoolObjUnlock(driver->pools.objs[i]); virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("names")); goto cleanup; } got++; } virStoragePoolObjUnlock(driver->pools.objs[i]); } storageDriverUnlock(driver); return got; cleanup: storageDriverUnlock(driver); for (i = 0 ; i < got ; i++) VIR_FREE(names[i]); memset(names, 0, nnames * sizeof(*names)); return -1; } static int storageNumDefinedPools(virConnectPtr conn) { virStorageDriverStatePtr driver = conn->storagePrivateData; unsigned int i, nactive = 0; storageDriverLock(driver); for (i = 0 ; i < driver->pools.count ; i++) { virStoragePoolObjLock(driver->pools.objs[i]); if (!virStoragePoolObjIsActive(driver->pools.objs[i])) nactive++; virStoragePoolObjUnlock(driver->pools.objs[i]); } storageDriverUnlock(driver); return nactive; } static int storageListDefinedPools(virConnectPtr conn, char **const names, int nnames) { virStorageDriverStatePtr driver = conn->storagePrivateData; int got = 0, i; storageDriverLock(driver); for (i = 0 ; i < driver->pools.count && got < nnames ; i++) { virStoragePoolObjLock(driver->pools.objs[i]); if (!virStoragePoolObjIsActive(driver->pools.objs[i])) { if (!(names[got] = strdup(driver->pools.objs[i]->def->name))) { virStoragePoolObjUnlock(driver->pools.objs[i]); virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("names")); goto cleanup; } got++; } virStoragePoolObjUnlock(driver->pools.objs[i]); } storageDriverUnlock(driver); return got; cleanup: storageDriverUnlock(driver); for (i = 0 ; i < got ; i++) { free(names[i]); names[i] = NULL; } memset(names, 0, nnames * sizeof(*names)); return -1; } /* This method is required to be re-entrant / thread safe, so uses no driver lock */ static char * storageFindPoolSources(virConnectPtr conn, const char *type, const char *srcSpec, unsigned int flags) { int backend_type; virStorageBackendPtr backend; char *ret = NULL; backend_type = virStoragePoolTypeFromString(type); if (backend_type < 0) goto cleanup; backend = virStorageBackendForType(backend_type); if (backend == NULL) goto cleanup; if (backend->findPoolSources) ret = backend->findPoolSources(conn, srcSpec, flags); cleanup: return ret; } static virStoragePoolPtr storagePoolCreate(virConnectPtr conn, const char *xml, unsigned int flags ATTRIBUTE_UNUSED) { virStorageDriverStatePtr driver = conn->storagePrivateData; virStoragePoolDefPtr def; virStoragePoolObjPtr pool = NULL; virStoragePoolPtr ret = NULL; virStorageBackendPtr backend; storageDriverLock(driver); if (!(def = virStoragePoolDefParse(conn, xml, NULL))) goto cleanup; pool = virStoragePoolObjFindByUUID(&driver->pools, def->uuid); if (!pool) pool = virStoragePoolObjFindByName(&driver->pools, def->name); if (pool) { virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("storage pool already exists")); goto cleanup; } if ((backend = virStorageBackendForType(def->type)) == NULL) goto cleanup; if (!(pool = virStoragePoolObjAssignDef(conn, &driver->pools, def))) goto cleanup; def = NULL; if (backend->startPool && backend->startPool(conn, pool) < 0) goto cleanup; if (backend->refreshPool(conn, pool) < 0) { if (backend->stopPool) backend->stopPool(conn, pool); goto cleanup; } pool->active = 1; ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid); cleanup: virStoragePoolDefFree(def); if (pool) virStoragePoolObjUnlock(pool); storageDriverUnlock(driver); return ret; } static virStoragePoolPtr storagePoolDefine(virConnectPtr conn, const char *xml, unsigned int flags ATTRIBUTE_UNUSED) { virStorageDriverStatePtr driver = conn->storagePrivateData; virStoragePoolDefPtr def; virStoragePoolObjPtr pool = NULL; virStoragePoolPtr ret = NULL; virStorageBackendPtr backend; storageDriverLock(driver); if (!(def = virStoragePoolDefParse(conn, xml, NULL))) goto cleanup; if ((backend = virStorageBackendForType(def->type)) == NULL) goto cleanup; if (!(pool = virStoragePoolObjAssignDef(conn, &driver->pools, def))) goto cleanup; if (virStoragePoolObjSaveDef(conn, driver, pool, def) < 0) { virStoragePoolObjRemove(&driver->pools, pool); def = NULL; goto cleanup; } def = NULL; ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid); cleanup: virStoragePoolDefFree(def); if (pool) virStoragePoolObjUnlock(pool); storageDriverUnlock(driver); return ret; } static int storagePoolUndefine(virStoragePoolPtr obj) { virStorageDriverStatePtr driver = obj->conn->storagePrivateData; virStoragePoolObjPtr pool; int ret = -1; storageDriverLock(driver); pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid); if (!pool) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage pool with matching uuid")); goto cleanup; } if (virStoragePoolObjIsActive(pool)) { virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("pool is still active")); goto cleanup; } if (virStoragePoolObjDeleteDef(obj->conn, pool) < 0) goto cleanup; if (unlink(pool->autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) storageLog("Failed to delete autostart link '%s': %s", pool->autostartLink, strerror(errno)); VIR_FREE(pool->configFile); VIR_FREE(pool->autostartLink); virStoragePoolObjRemove(&driver->pools, pool); pool = NULL; ret = 0; cleanup: if (pool) virStoragePoolObjUnlock(pool); storageDriverUnlock(driver); return ret; } static int storagePoolStart(virStoragePoolPtr obj, unsigned int flags ATTRIBUTE_UNUSED) { virStorageDriverStatePtr driver = obj->conn->storagePrivateData; virStoragePoolObjPtr pool; virStorageBackendPtr backend; int ret = -1; storageDriverLock(driver); pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid); storageDriverUnlock(driver); if (!pool) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage pool with matching uuid")); goto cleanup; } if ((backend = virStorageBackendForType(pool->def->type)) == NULL) goto cleanup; if (virStoragePoolObjIsActive(pool)) { virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("pool already active")); goto cleanup; } if (backend->startPool && backend->startPool(obj->conn, pool) < 0) goto cleanup; if (backend->refreshPool(obj->conn, pool) < 0) { if (backend->stopPool) backend->stopPool(obj->conn, pool); goto cleanup; } pool->active = 1; ret = 0; cleanup: if (pool) virStoragePoolObjUnlock(pool); return ret; } static int storagePoolBuild(virStoragePoolPtr obj, unsigned int flags) { virStorageDriverStatePtr driver = obj->conn->storagePrivateData; virStoragePoolObjPtr pool; virStorageBackendPtr backend; int ret = -1; storageDriverLock(driver); pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid); storageDriverUnlock(driver); if (!pool) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage pool with matching uuid")); goto cleanup; } if ((backend = virStorageBackendForType(pool->def->type)) == NULL) goto cleanup; if (virStoragePoolObjIsActive(pool)) { virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("storage pool is already active")); goto cleanup; } if (backend->buildPool && backend->buildPool(obj->conn, pool, flags) < 0) goto cleanup; ret = 0; cleanup: if (pool) virStoragePoolObjUnlock(pool); return ret; } static int storagePoolDestroy(virStoragePoolPtr obj) { virStorageDriverStatePtr driver = obj->conn->storagePrivateData; virStoragePoolObjPtr pool; virStorageBackendPtr backend; int ret = -1; storageDriverLock(driver); pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid); if (!pool) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage pool with matching uuid")); goto cleanup; } if ((backend = virStorageBackendForType(pool->def->type)) == NULL) goto cleanup; if (!virStoragePoolObjIsActive(pool)) { virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("storage pool is not active")); goto cleanup; } if (backend->stopPool && backend->stopPool(obj->conn, pool) < 0) goto cleanup; virStoragePoolObjClearVols(pool); pool->active = 0; if (pool->configFile == NULL) { virStoragePoolObjRemove(&driver->pools, pool); pool = NULL; } ret = 0; cleanup: if (pool) virStoragePoolObjUnlock(pool); storageDriverUnlock(driver); return ret; } static int storagePoolDelete(virStoragePoolPtr obj, unsigned int flags) { virStorageDriverStatePtr driver = obj->conn->storagePrivateData; virStoragePoolObjPtr pool; virStorageBackendPtr backend; int ret = -1; storageDriverLock(driver); pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid); storageDriverUnlock(driver); if (!pool) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage pool with matching uuid")); goto cleanup; } if ((backend = virStorageBackendForType(pool->def->type)) == NULL) goto cleanup; if (virStoragePoolObjIsActive(pool)) { virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("storage pool is still active")); goto cleanup; } if (!backend->deletePool) { virStorageReportError(obj->conn, VIR_ERR_NO_SUPPORT, "%s", _("pool does not support volume delete")); goto cleanup; } if (backend->deletePool(obj->conn, pool, flags) < 0) goto cleanup; ret = 0; cleanup: if (pool) virStoragePoolObjUnlock(pool); return ret; } static int storagePoolRefresh(virStoragePoolPtr obj, unsigned int flags ATTRIBUTE_UNUSED) { virStorageDriverStatePtr driver = obj->conn->storagePrivateData; virStoragePoolObjPtr pool; virStorageBackendPtr backend; int ret = -1; storageDriverLock(driver); pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid); storageDriverUnlock(driver); if (!pool) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage pool with matching uuid")); goto cleanup; } if ((backend = virStorageBackendForType(pool->def->type)) == NULL) goto cleanup; if (!virStoragePoolObjIsActive(pool)) { virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("storage pool is not active")); goto cleanup; } virStoragePoolObjClearVols(pool); if (backend->refreshPool(obj->conn, pool) < 0) { if (backend->stopPool) backend->stopPool(obj->conn, pool); pool->active = 0; if (pool->configFile == NULL) { virStoragePoolObjRemove(&driver->pools, pool); pool = NULL; } goto cleanup; } ret = 0; cleanup: if (pool) virStoragePoolObjUnlock(pool); return ret; } static int storagePoolGetInfo(virStoragePoolPtr obj, virStoragePoolInfoPtr info) { virStorageDriverStatePtr driver = obj->conn->storagePrivateData; virStoragePoolObjPtr pool; virStorageBackendPtr backend; int ret = -1; storageDriverLock(driver); pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid); storageDriverUnlock(driver); if (!pool) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage pool with matching uuid")); goto cleanup; } if ((backend = virStorageBackendForType(pool->def->type)) == NULL) goto cleanup; memset(info, 0, sizeof(virStoragePoolInfo)); if (pool->active) info->state = VIR_STORAGE_POOL_RUNNING; else info->state = VIR_STORAGE_POOL_INACTIVE; info->capacity = pool->def->capacity; info->allocation = pool->def->allocation; info->available = pool->def->available; ret = 0; cleanup: if (pool) virStoragePoolObjUnlock(pool); return ret; } static char * storagePoolDumpXML(virStoragePoolPtr obj, unsigned int flags ATTRIBUTE_UNUSED) { virStorageDriverStatePtr driver = obj->conn->storagePrivateData; virStoragePoolObjPtr pool; char *ret = NULL; storageDriverLock(driver); pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid); storageDriverUnlock(driver); if (!pool) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage pool with matching uuid")); goto cleanup; } ret = virStoragePoolDefFormat(obj->conn, pool->def); cleanup: if (pool) virStoragePoolObjUnlock(pool); return ret; } static int storagePoolGetAutostart(virStoragePoolPtr obj, int *autostart) { virStorageDriverStatePtr driver = obj->conn->storagePrivateData; virStoragePoolObjPtr pool; int ret = -1; storageDriverLock(driver); pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid); storageDriverUnlock(driver); if (!pool) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no pool with matching uuid")); goto cleanup; } if (!pool->configFile) { *autostart = 0; } else { *autostart = pool->autostart; } ret = 0; cleanup: if (pool) virStoragePoolObjUnlock(pool); return ret; } static int storagePoolSetAutostart(virStoragePoolPtr obj, int autostart) { virStorageDriverStatePtr driver = obj->conn->storagePrivateData; virStoragePoolObjPtr pool; int ret = -1; storageDriverLock(driver); pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid); storageDriverUnlock(driver); if (!pool) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no pool with matching uuid")); goto cleanup; } if (!pool->configFile) { virStorageReportError(obj->conn, VIR_ERR_INVALID_ARG, "%s", _("pool has no config file")); goto cleanup; } autostart = (autostart != 0); if (pool->autostart != autostart) { if (autostart) { int err; if ((err = virFileMakePath(driver->autostartDir))) { virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, _("cannot create autostart directory %s: %s"), driver->autostartDir, strerror(err)); goto cleanup; } if (symlink(pool->configFile, pool->autostartLink) < 0) { virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, _("Failed to create symlink '%s' to '%s': %s"), pool->autostartLink, pool->configFile, strerror(errno)); goto cleanup; } } else { if (unlink(pool->autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) { virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, _("Failed to delete symlink '%s': %s"), pool->autostartLink, strerror(errno)); goto cleanup; } } pool->autostart = autostart; } ret = 0; cleanup: if (pool) virStoragePoolObjUnlock(pool); return ret; } static int storagePoolNumVolumes(virStoragePoolPtr obj) { virStorageDriverStatePtr driver = obj->conn->storagePrivateData; virStoragePoolObjPtr pool; int ret = -1; storageDriverLock(driver); pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid); storageDriverUnlock(driver); if (!pool) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage pool with matching uuid")); goto cleanup; } if (!virStoragePoolObjIsActive(pool)) { virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("storage pool is not active")); goto cleanup; } ret = pool->volumes.count; cleanup: if (pool) virStoragePoolObjUnlock(pool); return ret; } static int storagePoolListVolumes(virStoragePoolPtr obj, char **const names, int maxnames) { virStorageDriverStatePtr driver = obj->conn->storagePrivateData; virStoragePoolObjPtr pool; int i, n = 0; memset(names, 0, maxnames * sizeof(*names)); storageDriverLock(driver); pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid); storageDriverUnlock(driver); if (!pool) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage pool with matching uuid")); goto cleanup; } if (!virStoragePoolObjIsActive(pool)) { virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("storage pool is not active")); goto cleanup; } for (i = 0 ; i < pool->volumes.count && n < maxnames ; i++) { if ((names[n++] = strdup(pool->volumes.objs[i]->name)) == NULL) { virStorageReportError(obj->conn, VIR_ERR_NO_MEMORY, "%s", _("name")); goto cleanup; } } virStoragePoolObjUnlock(pool); return n; cleanup: if (pool) virStoragePoolObjUnlock(pool); for (n = 0 ; n < maxnames ; n++) VIR_FREE(names[n]); memset(names, 0, maxnames * sizeof(*names)); return -1; } static virStorageVolPtr storageVolumeLookupByName(virStoragePoolPtr obj, const char *name) { virStorageDriverStatePtr driver = obj->conn->storagePrivateData; virStoragePoolObjPtr pool; virStorageVolDefPtr vol; virStorageVolPtr ret = NULL; storageDriverLock(driver); pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid); storageDriverUnlock(driver); if (!pool) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage pool with matching uuid")); goto cleanup; } if (!virStoragePoolObjIsActive(pool)) { virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("storage pool is not active")); goto cleanup; } vol = virStorageVolDefFindByName(pool, name); if (!vol) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage vol with matching name")); goto cleanup; } ret = virGetStorageVol(obj->conn, pool->def->name, vol->name, vol->key); cleanup: if (pool) virStoragePoolObjUnlock(pool); return ret; } static virStorageVolPtr storageVolumeLookupByKey(virConnectPtr conn, const char *key) { virStorageDriverStatePtr driver = conn->storagePrivateData; unsigned int i; virStorageVolPtr ret = NULL; storageDriverLock(driver); for (i = 0 ; i < driver->pools.count && !ret ; i++) { virStoragePoolObjLock(driver->pools.objs[i]); if (virStoragePoolObjIsActive(driver->pools.objs[i])) { virStorageVolDefPtr vol = virStorageVolDefFindByKey(driver->pools.objs[i], key); if (vol) ret = virGetStorageVol(conn, driver->pools.objs[i]->def->name, vol->name, vol->key); } virStoragePoolObjUnlock(driver->pools.objs[i]); } storageDriverUnlock(driver); if (!ret) virStorageReportError(conn, VIR_ERR_INVALID_STORAGE_VOL, "%s", _("no storage vol with matching key")); return ret; } static virStorageVolPtr storageVolumeLookupByPath(virConnectPtr conn, const char *path) { virStorageDriverStatePtr driver = conn->storagePrivateData; unsigned int i; virStorageVolPtr ret = NULL; storageDriverLock(driver); for (i = 0 ; i < driver->pools.count && !ret ; i++) { virStoragePoolObjLock(driver->pools.objs[i]); if (virStoragePoolObjIsActive(driver->pools.objs[i])) { virStorageVolDefPtr vol; const char *stable_path; stable_path = virStorageBackendStablePath(conn, driver->pools.objs[i], path); /* * virStorageBackendStablePath already does * virStorageReportError if it fails; we just need to keep * propagating the return code */ if (stable_path == NULL) { virStoragePoolObjUnlock(driver->pools.objs[i]); goto cleanup; } vol = virStorageVolDefFindByPath(driver->pools.objs[i], stable_path); VIR_FREE(stable_path); if (vol) ret = virGetStorageVol(conn, driver->pools.objs[i]->def->name, vol->name, vol->key); } virStoragePoolObjUnlock(driver->pools.objs[i]); } if (!ret) virStorageReportError(conn, VIR_ERR_INVALID_STORAGE_VOL, "%s", _("no storage vol with matching path")); cleanup: storageDriverUnlock(driver); return ret; } static virStorageVolPtr storageVolumeCreateXML(virStoragePoolPtr obj, const char *xmldesc, unsigned int flags ATTRIBUTE_UNUSED) { virStorageDriverStatePtr driver = obj->conn->storagePrivateData; virStoragePoolObjPtr pool; virStorageBackendPtr backend; virStorageVolDefPtr vol = NULL; virStorageVolPtr ret = NULL; storageDriverLock(driver); pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid); storageDriverUnlock(driver); if (!pool) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage pool with matching uuid")); goto cleanup; } if (!virStoragePoolObjIsActive(pool)) { virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("storage pool is not active")); goto cleanup; } if ((backend = virStorageBackendForType(pool->def->type)) == NULL) goto cleanup; vol = virStorageVolDefParse(obj->conn, pool->def, xmldesc, NULL); if (vol == NULL) goto cleanup; if (virStorageVolDefFindByName(pool, vol->name)) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("storage vol already exists")); goto cleanup; } if (VIR_REALLOC_N(pool->volumes.objs, pool->volumes.count+1) < 0) { virStorageReportError(obj->conn, VIR_ERR_NO_MEMORY, NULL); goto cleanup; } if (!backend->createVol) { virStorageReportError(obj->conn, VIR_ERR_NO_SUPPORT, "%s", _("storage pool does not support volume creation")); goto cleanup; } /* XXX ought to drop pool lock while creating instance */ if (backend->createVol(obj->conn, pool, vol) < 0) { goto cleanup; } pool->volumes.objs[pool->volumes.count++] = vol; ret = virGetStorageVol(obj->conn, pool->def->name, vol->name, vol->key); vol = NULL; cleanup: virStorageVolDefFree(vol); if (pool) virStoragePoolObjUnlock(pool); return ret; } static int storageVolumeDelete(virStorageVolPtr obj, unsigned int flags) { virStorageDriverStatePtr driver = obj->conn->storagePrivateData; virStoragePoolObjPtr pool; virStorageBackendPtr backend; virStorageVolDefPtr vol = NULL; unsigned int i; int ret = -1; storageDriverLock(driver); pool = virStoragePoolObjFindByName(&driver->pools, obj->pool); storageDriverUnlock(driver); if (!pool) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage pool with matching uuid")); goto cleanup; } if (!virStoragePoolObjIsActive(pool)) { virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("storage pool is not active")); goto cleanup; } if ((backend = virStorageBackendForType(pool->def->type)) == NULL) goto cleanup; vol = virStorageVolDefFindByName(pool, obj->name); if (!vol) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage vol with matching name")); goto cleanup; } if (!backend->deleteVol) { virStorageReportError(obj->conn, VIR_ERR_NO_SUPPORT, "%s", _("storage pool does not support vol deletion")); goto cleanup; } if (backend->deleteVol(obj->conn, pool, vol, flags) < 0) goto cleanup; for (i = 0 ; i < pool->volumes.count ; i++) { if (pool->volumes.objs[i] == vol) { virStorageVolDefFree(vol); vol = NULL; if (i < (pool->volumes.count - 1)) memmove(pool->volumes.objs + i, pool->volumes.objs + i + 1, sizeof(*(pool->volumes.objs)) * (pool->volumes.count - (i + 1))); if (VIR_REALLOC_N(pool->volumes.objs, pool->volumes.count - 1) < 0) { ; /* Failure to reduce memory allocation isn't fatal */ } pool->volumes.count--; break; } } ret = 0; cleanup: virStorageVolDefFree(vol); if (pool) virStoragePoolObjUnlock(pool); return ret; } static int storageVolumeGetInfo(virStorageVolPtr obj, virStorageVolInfoPtr info) { virStorageDriverStatePtr driver = obj->conn->storagePrivateData; virStoragePoolObjPtr pool; virStorageBackendPtr backend; virStorageVolDefPtr vol; int ret = -1; storageDriverLock(driver); pool = virStoragePoolObjFindByName(&driver->pools, obj->pool); storageDriverUnlock(driver); if (!pool) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage pool with matching uuid")); goto cleanup; } if (!virStoragePoolObjIsActive(pool)) { virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("storage pool is not active")); goto cleanup; } vol = virStorageVolDefFindByName(pool, obj->name); if (!vol) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage vol with matching name")); goto cleanup; } if ((backend = virStorageBackendForType(pool->def->type)) == NULL) goto cleanup; if (backend->refreshVol && backend->refreshVol(obj->conn, pool, vol) < 0) goto cleanup; memset(info, 0, sizeof(*info)); info->type = vol->type; info->capacity = vol->capacity; info->allocation = vol->allocation; ret = 0; cleanup: if (pool) virStoragePoolObjUnlock(pool); return ret; } static char * storageVolumeGetXMLDesc(virStorageVolPtr obj, unsigned int flags ATTRIBUTE_UNUSED) { virStorageDriverStatePtr driver = obj->conn->storagePrivateData; virStoragePoolObjPtr pool; virStorageBackendPtr backend; virStorageVolDefPtr vol; char *ret = NULL; storageDriverLock(driver); pool = virStoragePoolObjFindByName(&driver->pools, obj->pool); storageDriverUnlock(driver); if (!pool) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage pool with matching uuid")); goto cleanup; } if (!virStoragePoolObjIsActive(pool)) { virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("storage pool is not active")); goto cleanup; } vol = virStorageVolDefFindByName(pool, obj->name); if (!vol) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage vol with matching name")); goto cleanup; } if ((backend = virStorageBackendForType(pool->def->type)) == NULL) goto cleanup; ret = virStorageVolDefFormat(obj->conn, pool->def, vol); cleanup: if (pool) virStoragePoolObjUnlock(pool); return ret; } static char * storageVolumeGetPath(virStorageVolPtr obj) { virStorageDriverStatePtr driver = obj->conn->storagePrivateData; virStoragePoolObjPtr pool; virStorageVolDefPtr vol; char *ret = NULL; storageDriverLock(driver); pool = virStoragePoolObjFindByName(&driver->pools, obj->pool); storageDriverUnlock(driver); if (!pool) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage pool with matching uuid")); goto cleanup; } if (!virStoragePoolObjIsActive(pool)) { virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, "%s", _("storage pool is not active")); goto cleanup; } vol = virStorageVolDefFindByName(pool, obj->name); if (!vol) { virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL, "%s", _("no storage vol with matching name")); goto cleanup; } ret = strdup(vol->target.path); if (ret == NULL) virStorageReportError(obj->conn, VIR_ERR_NO_MEMORY, "%s", _("path")); cleanup: if (pool) virStoragePoolObjUnlock(pool); return ret; } static virStorageDriver storageDriver = { .name = "storage", .open = storageOpen, .close = storageClose, .numOfPools = storageNumPools, .listPools = storageListPools, .numOfDefinedPools = storageNumDefinedPools, .listDefinedPools = storageListDefinedPools, .findPoolSources = storageFindPoolSources, .poolLookupByName = storagePoolLookupByName, .poolLookupByUUID = storagePoolLookupByUUID, .poolLookupByVolume = storagePoolLookupByVolume, .poolCreateXML = storagePoolCreate, .poolDefineXML = storagePoolDefine, .poolBuild = storagePoolBuild, .poolUndefine = storagePoolUndefine, .poolCreate = storagePoolStart, .poolDestroy = storagePoolDestroy, .poolDelete = storagePoolDelete, .poolRefresh = storagePoolRefresh, .poolGetInfo = storagePoolGetInfo, .poolGetXMLDesc = storagePoolDumpXML, .poolGetAutostart = storagePoolGetAutostart, .poolSetAutostart = storagePoolSetAutostart, .poolNumOfVolumes = storagePoolNumVolumes, .poolListVolumes = storagePoolListVolumes, .volLookupByName = storageVolumeLookupByName, .volLookupByKey = storageVolumeLookupByKey, .volLookupByPath = storageVolumeLookupByPath, .volCreateXML = storageVolumeCreateXML, .volDelete = storageVolumeDelete, .volGetInfo = storageVolumeGetInfo, .volGetXMLDesc = storageVolumeGetXMLDesc, .volGetPath = storageVolumeGetPath, }; static virStateDriver stateDriver = { .initialize = storageDriverStartup, .cleanup = storageDriverShutdown, .reload = storageDriverReload, .active = storageDriverActive, }; int storageRegister(void) { virRegisterStorageDriver(&storageDriver); virRegisterStateDriver(&stateDriver); return 0; }