mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-11 15:27:47 +00:00
storage: Create common file/dir pool backend helpers
Move some pool functions to storage_util to create local/common helpers using the same naming syntax as the existing upload, download, and wipe virStorageBackend*Local API's. In the process of doing so, found a few API's that can now become local to storage_util. In order to distinguish between local/external - I changed the names of the now local only ones from "virStorageBackend..." to just "storageBackend..." Signed-off-by: John Ferlan <jferlan@redhat.com>
This commit is contained in:
parent
e26c21629e
commit
5f07c3c079
@ -23,11 +23,9 @@
|
|||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include <sys/statvfs.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <dirent.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -53,126 +51,6 @@
|
|||||||
|
|
||||||
VIR_LOG_INIT("storage.storage_backend_fs");
|
VIR_LOG_INIT("storage.storage_backend_fs");
|
||||||
|
|
||||||
#define VIR_STORAGE_VOL_FS_OPEN_FLAGS (VIR_STORAGE_VOL_OPEN_DEFAULT | \
|
|
||||||
VIR_STORAGE_VOL_OPEN_DIR)
|
|
||||||
#define VIR_STORAGE_VOL_FS_PROBE_FLAGS (VIR_STORAGE_VOL_FS_OPEN_FLAGS | \
|
|
||||||
VIR_STORAGE_VOL_OPEN_NOERROR)
|
|
||||||
|
|
||||||
static int
|
|
||||||
virStorageBackendProbeTarget(virStorageSourcePtr target,
|
|
||||||
virStorageEncryptionPtr *encryption)
|
|
||||||
{
|
|
||||||
int backingStoreFormat;
|
|
||||||
int fd = -1;
|
|
||||||
int ret = -1;
|
|
||||||
int rc;
|
|
||||||
virStorageSourcePtr meta = NULL;
|
|
||||||
struct stat sb;
|
|
||||||
|
|
||||||
if (encryption)
|
|
||||||
*encryption = NULL;
|
|
||||||
|
|
||||||
if ((rc = virStorageBackendVolOpen(target->path, &sb,
|
|
||||||
VIR_STORAGE_VOL_FS_PROBE_FLAGS)) < 0)
|
|
||||||
return rc; /* Take care to propagate rc, it is not always -1 */
|
|
||||||
fd = rc;
|
|
||||||
|
|
||||||
if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &sb) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if (S_ISDIR(sb.st_mode)) {
|
|
||||||
if (virStorageBackendIsPloopDir(target->path)) {
|
|
||||||
if (virStorageBackendRedoPloopUpdate(target, &sb, &fd,
|
|
||||||
VIR_STORAGE_VOL_FS_PROBE_FLAGS) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
} else {
|
|
||||||
target->format = VIR_STORAGE_FILE_DIR;
|
|
||||||
ret = 0;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(meta = virStorageFileGetMetadataFromFD(target->path,
|
|
||||||
fd,
|
|
||||||
VIR_STORAGE_FILE_AUTO,
|
|
||||||
&backingStoreFormat)))
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if (meta->backingStoreRaw) {
|
|
||||||
if (!(target->backingStore = virStorageSourceNewFromBacking(meta)))
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
target->backingStore->format = backingStoreFormat;
|
|
||||||
|
|
||||||
/* XXX: Remote storage doesn't play nicely with volumes backed by
|
|
||||||
* remote storage. To avoid trouble, just fake the backing store is RAW
|
|
||||||
* and put the string from the metadata as the path of the target. */
|
|
||||||
if (!virStorageSourceIsLocalStorage(target->backingStore)) {
|
|
||||||
virStorageSourceFree(target->backingStore);
|
|
||||||
|
|
||||||
if (VIR_ALLOC(target->backingStore) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
target->backingStore->type = VIR_STORAGE_TYPE_NETWORK;
|
|
||||||
target->backingStore->path = meta->backingStoreRaw;
|
|
||||||
meta->backingStoreRaw = NULL;
|
|
||||||
target->backingStore->format = VIR_STORAGE_FILE_RAW;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target->backingStore->format == VIR_STORAGE_FILE_AUTO) {
|
|
||||||
if ((rc = virStorageFileProbeFormat(target->backingStore->path,
|
|
||||||
-1, -1)) < 0) {
|
|
||||||
/* If the backing file is currently unavailable or is
|
|
||||||
* accessed via remote protocol only log an error, fake the
|
|
||||||
* format as RAW and continue. Returning -1 here would
|
|
||||||
* disable the whole storage pool, making it unavailable for
|
|
||||||
* even maintenance. */
|
|
||||||
target->backingStore->format = VIR_STORAGE_FILE_RAW;
|
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
||||||
_("cannot probe backing volume format: %s"),
|
|
||||||
target->backingStore->path);
|
|
||||||
} else {
|
|
||||||
target->backingStore->format = rc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
target->format = meta->format;
|
|
||||||
|
|
||||||
/* Default to success below this point */
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
if (meta->capacity)
|
|
||||||
target->capacity = meta->capacity;
|
|
||||||
|
|
||||||
if (encryption && meta->encryption) {
|
|
||||||
*encryption = meta->encryption;
|
|
||||||
meta->encryption = NULL;
|
|
||||||
|
|
||||||
/* XXX ideally we'd fill in secret UUID here
|
|
||||||
* but we cannot guarantee 'conn' is non-NULL
|
|
||||||
* at this point in time :-( So we only fill
|
|
||||||
* in secrets when someone first queries a vol
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
virBitmapFree(target->features);
|
|
||||||
target->features = meta->features;
|
|
||||||
meta->features = NULL;
|
|
||||||
|
|
||||||
if (meta->compat) {
|
|
||||||
VIR_FREE(target->compat);
|
|
||||||
target->compat = meta->compat;
|
|
||||||
meta->compat = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
VIR_FORCE_CLOSE(fd);
|
|
||||||
virStorageSourceFree(meta);
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#if WITH_STORAGE_FS
|
#if WITH_STORAGE_FS
|
||||||
|
|
||||||
# include <mntent.h>
|
# include <mntent.h>
|
||||||
@ -574,8 +452,6 @@ static int
|
|||||||
virStorageBackendFileSystemStop(virConnectPtr conn ATTRIBUTE_UNUSED,
|
virStorageBackendFileSystemStop(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||||
virStoragePoolObjPtr pool)
|
virStoragePoolObjPtr pool)
|
||||||
{
|
{
|
||||||
virCommandPtr cmd = NULL;
|
|
||||||
int ret = -1;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (virStorageBackendFileSystemIsValid(pool) < 0)
|
if (virStorageBackendFileSystemIsValid(pool) < 0)
|
||||||
@ -585,17 +461,7 @@ virStorageBackendFileSystemStop(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
if ((rc = virStorageBackendFileSystemIsMounted(pool)) != 1)
|
if ((rc = virStorageBackendFileSystemIsMounted(pool)) != 1)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
cmd = virCommandNewArgList(UMOUNT,
|
return virStorageBackendUmountLocal(pool);
|
||||||
pool->def->target.path,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (virCommandRun(cmd, NULL) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
cleanup:
|
|
||||||
virCommandFree(cmd);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
#endif /* WITH_STORAGE_FS */
|
#endif /* WITH_STORAGE_FS */
|
||||||
|
|
||||||
@ -742,237 +608,18 @@ virStorageBackendFileSystemBuild(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
virStoragePoolObjPtr pool,
|
virStoragePoolObjPtr pool,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
|
||||||
char *parent = NULL;
|
|
||||||
char *p = NULL;
|
|
||||||
mode_t mode;
|
|
||||||
bool needs_create_as_uid;
|
|
||||||
unsigned int dir_create_flags;
|
|
||||||
|
|
||||||
virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE |
|
virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE |
|
||||||
VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret);
|
VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, -1);
|
||||||
|
|
||||||
VIR_EXCLUSIVE_FLAGS_GOTO(VIR_STORAGE_POOL_BUILD_OVERWRITE,
|
VIR_EXCLUSIVE_FLAGS_RET(VIR_STORAGE_POOL_BUILD_OVERWRITE,
|
||||||
VIR_STORAGE_POOL_BUILD_NO_OVERWRITE,
|
VIR_STORAGE_POOL_BUILD_NO_OVERWRITE,
|
||||||
error);
|
-1);
|
||||||
|
|
||||||
if (VIR_STRDUP(parent, pool->def->target.path) < 0)
|
if (virStorageBackendBuildLocal(pool) < 0)
|
||||||
goto error;
|
|
||||||
if (!(p = strrchr(parent, '/'))) {
|
|
||||||
virReportError(VIR_ERR_INVALID_ARG,
|
|
||||||
_("path '%s' is not absolute"),
|
|
||||||
pool->def->target.path);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p != parent) {
|
|
||||||
/* assure all directories in the path prior to the final dir
|
|
||||||
* exist, with default uid/gid/mode. */
|
|
||||||
*p = '\0';
|
|
||||||
if (virFileMakePath(parent) < 0) {
|
|
||||||
virReportSystemError(errno, _("cannot create path '%s'"),
|
|
||||||
parent);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dir_create_flags = VIR_DIR_CREATE_ALLOW_EXIST;
|
|
||||||
needs_create_as_uid = (pool->def->type == VIR_STORAGE_POOL_NETFS);
|
|
||||||
mode = pool->def->target.perms.mode;
|
|
||||||
|
|
||||||
if (mode == (mode_t) -1 &&
|
|
||||||
(needs_create_as_uid || !virFileExists(pool->def->target.path)))
|
|
||||||
mode = VIR_STORAGE_DEFAULT_POOL_PERM_MODE;
|
|
||||||
if (needs_create_as_uid)
|
|
||||||
dir_create_flags |= VIR_DIR_CREATE_AS_UID;
|
|
||||||
|
|
||||||
/* Now create the final dir in the path with the uid/gid/mode
|
|
||||||
* requested in the config. If the dir already exists, just set
|
|
||||||
* the perms. */
|
|
||||||
if (virDirCreate(pool->def->target.path,
|
|
||||||
mode,
|
|
||||||
pool->def->target.perms.uid,
|
|
||||||
pool->def->target.perms.gid,
|
|
||||||
dir_create_flags) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (flags != 0) {
|
|
||||||
ret = virStorageBackendMakeFileSystem(pool, flags);
|
|
||||||
} else {
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
error:
|
|
||||||
VIR_FREE(parent);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterate over the pool's directory and enumerate all disk images
|
|
||||||
* within it. This is non-recursive.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
virStorageBackendFileSystemRefresh(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
||||||
virStoragePoolObjPtr pool)
|
|
||||||
{
|
|
||||||
DIR *dir;
|
|
||||||
struct dirent *ent;
|
|
||||||
struct statvfs sb;
|
|
||||||
struct stat statbuf;
|
|
||||||
virStorageVolDefPtr vol = NULL;
|
|
||||||
virStorageSourcePtr target = NULL;
|
|
||||||
int direrr;
|
|
||||||
int fd = -1, ret = -1;
|
|
||||||
|
|
||||||
if (virDirOpen(&dir, pool->def->target.path) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
while ((direrr = virDirRead(dir, &ent, pool->def->target.path)) > 0) {
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (virStringHasControlChars(ent->d_name)) {
|
|
||||||
VIR_WARN("Ignoring file with control characters under '%s'",
|
|
||||||
pool->def->target.path);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (VIR_ALLOC(vol) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if (VIR_STRDUP(vol->name, ent->d_name) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
vol->type = VIR_STORAGE_VOL_FILE;
|
|
||||||
vol->target.format = VIR_STORAGE_FILE_RAW; /* Real value is filled in during probe */
|
|
||||||
if (virAsprintf(&vol->target.path, "%s/%s",
|
|
||||||
pool->def->target.path,
|
|
||||||
vol->name) == -1)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if (VIR_STRDUP(vol->key, vol->target.path) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if ((err = virStorageBackendProbeTarget(&vol->target,
|
|
||||||
&vol->target.encryption)) < 0) {
|
|
||||||
if (err == -2) {
|
|
||||||
/* Silently ignore non-regular files,
|
|
||||||
* eg 'lost+found', dangling symbolic link */
|
|
||||||
virStorageVolDefFree(vol);
|
|
||||||
vol = NULL;
|
|
||||||
continue;
|
|
||||||
} else if (err == -3) {
|
|
||||||
/* The backing file is currently unavailable, its format is not
|
|
||||||
* explicitly specified, the probe to auto detect the format
|
|
||||||
* failed: continue with faked RAW format, since AUTO will
|
|
||||||
* break virStorageVolTargetDefFormat() generating the line
|
|
||||||
* <format type='...'/>. */
|
|
||||||
} else {
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* directory based volume */
|
|
||||||
if (vol->target.format == VIR_STORAGE_FILE_DIR)
|
|
||||||
vol->type = VIR_STORAGE_VOL_DIR;
|
|
||||||
|
|
||||||
if (vol->target.format == VIR_STORAGE_FILE_PLOOP)
|
|
||||||
vol->type = VIR_STORAGE_VOL_PLOOP;
|
|
||||||
|
|
||||||
if (vol->target.backingStore) {
|
|
||||||
ignore_value(virStorageBackendUpdateVolTargetInfo(VIR_STORAGE_VOL_FILE,
|
|
||||||
vol->target.backingStore,
|
|
||||||
false,
|
|
||||||
VIR_STORAGE_VOL_OPEN_DEFAULT, 0));
|
|
||||||
/* If this failed, the backing file is currently unavailable,
|
|
||||||
* the capacity, allocation, owner, group and mode are unknown.
|
|
||||||
* An error message was raised, but we just continue. */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
if (direrr < 0)
|
|
||||||
goto cleanup;
|
|
||||||
VIR_DIR_CLOSE(dir);
|
|
||||||
vol = NULL;
|
|
||||||
|
|
||||||
if (VIR_ALLOC(target))
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if ((fd = open(pool->def->target.path, O_RDONLY)) < 0) {
|
|
||||||
virReportSystemError(errno,
|
|
||||||
_("cannot open path '%s'"),
|
|
||||||
pool->def->target.path);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fstat(fd, &statbuf) < 0) {
|
|
||||||
virReportSystemError(errno,
|
|
||||||
_("cannot stat path '%s'"),
|
|
||||||
pool->def->target.path);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &statbuf) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
/* VolTargetInfoFD doesn't update capacity correctly for the pool case */
|
|
||||||
if (statvfs(pool->def->target.path, &sb) < 0) {
|
|
||||||
virReportSystemError(errno,
|
|
||||||
_("cannot statvfs path '%s'"),
|
|
||||||
pool->def->target.path);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
pool->def->capacity = ((unsigned long long)sb.f_frsize *
|
|
||||||
(unsigned long long)sb.f_blocks);
|
|
||||||
pool->def->available = ((unsigned long long)sb.f_bfree *
|
|
||||||
(unsigned long long)sb.f_frsize);
|
|
||||||
pool->def->allocation = pool->def->capacity - pool->def->available;
|
|
||||||
|
|
||||||
pool->def->target.perms.mode = target->perms->mode;
|
|
||||||
pool->def->target.perms.uid = target->perms->uid;
|
|
||||||
pool->def->target.perms.gid = target->perms->gid;
|
|
||||||
VIR_FREE(pool->def->target.perms.label);
|
|
||||||
if (VIR_STRDUP(pool->def->target.perms.label, target->perms->label) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
cleanup:
|
|
||||||
VIR_DIR_CLOSE(dir);
|
|
||||||
VIR_FORCE_CLOSE(fd);
|
|
||||||
virStorageVolDefFree(vol);
|
|
||||||
virStorageSourceFree(target);
|
|
||||||
if (ret < 0)
|
|
||||||
virStoragePoolObjClearVols(pool);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @conn connection to report errors against
|
|
||||||
* @pool storage pool to delete
|
|
||||||
*
|
|
||||||
* Delete a directory based storage pool
|
|
||||||
*
|
|
||||||
* Returns 0 on success, -1 on error
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
virStorageBackendFileSystemDelete(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|
||||||
virStoragePoolObjPtr pool,
|
|
||||||
unsigned int flags)
|
|
||||||
{
|
|
||||||
virCheckFlags(0, -1);
|
|
||||||
|
|
||||||
/* XXX delete all vols first ? */
|
|
||||||
|
|
||||||
if (rmdir(pool->def->target.path) < 0) {
|
|
||||||
virReportSystemError(errno,
|
|
||||||
_("failed to remove pool '%s'"),
|
|
||||||
pool->def->target.path);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
if (flags != 0)
|
||||||
|
return virStorageBackendMakeFileSystem(pool, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1319,8 +966,8 @@ virStorageBackend virStorageBackendDirectory = {
|
|||||||
|
|
||||||
.buildPool = virStorageBackendFileSystemBuild,
|
.buildPool = virStorageBackendFileSystemBuild,
|
||||||
.checkPool = virStorageBackendFileSystemCheck,
|
.checkPool = virStorageBackendFileSystemCheck,
|
||||||
.refreshPool = virStorageBackendFileSystemRefresh,
|
.refreshPool = virStorageBackendRefreshLocal,
|
||||||
.deletePool = virStorageBackendFileSystemDelete,
|
.deletePool = virStorageBackendDeleteLocal,
|
||||||
.buildVol = virStorageBackendFileSystemVolBuild,
|
.buildVol = virStorageBackendFileSystemVolBuild,
|
||||||
.buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
|
.buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
|
||||||
.createVol = virStorageBackendFileSystemVolCreate,
|
.createVol = virStorageBackendFileSystemVolCreate,
|
||||||
@ -1339,9 +986,9 @@ virStorageBackend virStorageBackendFileSystem = {
|
|||||||
.buildPool = virStorageBackendFileSystemBuild,
|
.buildPool = virStorageBackendFileSystemBuild,
|
||||||
.checkPool = virStorageBackendFileSystemCheck,
|
.checkPool = virStorageBackendFileSystemCheck,
|
||||||
.startPool = virStorageBackendFileSystemStart,
|
.startPool = virStorageBackendFileSystemStart,
|
||||||
.refreshPool = virStorageBackendFileSystemRefresh,
|
.refreshPool = virStorageBackendRefreshLocal,
|
||||||
.stopPool = virStorageBackendFileSystemStop,
|
.stopPool = virStorageBackendFileSystemStop,
|
||||||
.deletePool = virStorageBackendFileSystemDelete,
|
.deletePool = virStorageBackendDeleteLocal,
|
||||||
.buildVol = virStorageBackendFileSystemVolBuild,
|
.buildVol = virStorageBackendFileSystemVolBuild,
|
||||||
.buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
|
.buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
|
||||||
.createVol = virStorageBackendFileSystemVolCreate,
|
.createVol = virStorageBackendFileSystemVolCreate,
|
||||||
@ -1359,9 +1006,9 @@ virStorageBackend virStorageBackendNetFileSystem = {
|
|||||||
.checkPool = virStorageBackendFileSystemCheck,
|
.checkPool = virStorageBackendFileSystemCheck,
|
||||||
.startPool = virStorageBackendFileSystemStart,
|
.startPool = virStorageBackendFileSystemStart,
|
||||||
.findPoolSources = virStorageBackendFileSystemNetFindPoolSources,
|
.findPoolSources = virStorageBackendFileSystemNetFindPoolSources,
|
||||||
.refreshPool = virStorageBackendFileSystemRefresh,
|
.refreshPool = virStorageBackendRefreshLocal,
|
||||||
.stopPool = virStorageBackendFileSystemStop,
|
.stopPool = virStorageBackendFileSystemStop,
|
||||||
.deletePool = virStorageBackendFileSystemDelete,
|
.deletePool = virStorageBackendDeleteLocal,
|
||||||
.buildVol = virStorageBackendFileSystemVolBuild,
|
.buildVol = virStorageBackendFileSystemVolBuild,
|
||||||
.buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
|
.buildVolFrom = virStorageBackendFileSystemVolBuildFrom,
|
||||||
.createVol = virStorageBackendFileSystemVolCreate,
|
.createVol = virStorageBackendFileSystemVolCreate,
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/statvfs.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include "dirname.h"
|
#include "dirname.h"
|
||||||
@ -1675,8 +1676,8 @@ virStorageBackendVolOpen(const char *path, struct stat *sb,
|
|||||||
/* virStorageIsPloop function checks whether given directory is ploop volume's
|
/* virStorageIsPloop function checks whether given directory is ploop volume's
|
||||||
* directory.
|
* directory.
|
||||||
*/
|
*/
|
||||||
bool
|
static bool
|
||||||
virStorageBackendIsPloopDir(char *path)
|
storageBackendIsPloopDir(char *path)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
char *root = NULL;
|
char *root = NULL;
|
||||||
@ -1702,8 +1703,8 @@ virStorageBackendIsPloopDir(char *path)
|
|||||||
* and etc. we need to perform virStorageBackendVolOpen and
|
* and etc. we need to perform virStorageBackendVolOpen and
|
||||||
* virStorageBackendUpdateVolTargetFd once again.
|
* virStorageBackendUpdateVolTargetFd once again.
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
virStorageBackendRedoPloopUpdate(virStorageSourcePtr target, struct stat *sb,
|
storageBackendRedoPloopUpdate(virStorageSourcePtr target, struct stat *sb,
|
||||||
int *fd, unsigned int flags)
|
int *fd, unsigned int flags)
|
||||||
{
|
{
|
||||||
char *path = NULL;
|
char *path = NULL;
|
||||||
@ -1723,7 +1724,7 @@ virStorageBackendRedoPloopUpdate(virStorageSourcePtr target, struct stat *sb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* virStorageBackendUpdateVolTargetInfo
|
* storageBackendUpdateVolTargetInfo
|
||||||
* @voltype: Volume type
|
* @voltype: Volume type
|
||||||
* @target: target definition ptr of volume to update
|
* @target: target definition ptr of volume to update
|
||||||
* @withBlockVolFormat: true if caller determined a block file
|
* @withBlockVolFormat: true if caller determined a block file
|
||||||
@ -1736,8 +1737,8 @@ virStorageBackendRedoPloopUpdate(virStorageSourcePtr target, struct stat *sb,
|
|||||||
* open error occurred. It is up to the caller to handle. A -2 may also
|
* open error occurred. It is up to the caller to handle. A -2 may also
|
||||||
* be returned if the caller passed a readflagsflag.
|
* be returned if the caller passed a readflagsflag.
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
virStorageBackendUpdateVolTargetInfo(virStorageVolType voltype,
|
storageBackendUpdateVolTargetInfo(virStorageVolType voltype,
|
||||||
virStorageSourcePtr target,
|
virStorageSourcePtr target,
|
||||||
bool withBlockVolFormat,
|
bool withBlockVolFormat,
|
||||||
unsigned int openflags,
|
unsigned int openflags,
|
||||||
@ -1758,8 +1759,8 @@ virStorageBackendUpdateVolTargetInfo(virStorageVolType voltype,
|
|||||||
if ((voltype == VIR_STORAGE_VOL_FILE || voltype == VIR_STORAGE_VOL_BLOCK) &&
|
if ((voltype == VIR_STORAGE_VOL_FILE || voltype == VIR_STORAGE_VOL_BLOCK) &&
|
||||||
target->format != VIR_STORAGE_FILE_NONE) {
|
target->format != VIR_STORAGE_FILE_NONE) {
|
||||||
if (S_ISDIR(sb.st_mode)) {
|
if (S_ISDIR(sb.st_mode)) {
|
||||||
if (virStorageBackendIsPloopDir(target->path)) {
|
if (storageBackendIsPloopDir(target->path)) {
|
||||||
if ((ret = virStorageBackendRedoPloopUpdate(target, &sb, &fd,
|
if ((ret = storageBackendRedoPloopUpdate(target, &sb, &fd,
|
||||||
openflags)) < 0)
|
openflags)) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
target->format = VIR_STORAGE_FILE_PLOOP;
|
target->format = VIR_STORAGE_FILE_PLOOP;
|
||||||
@ -1826,14 +1827,14 @@ virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol,
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if ((ret = virStorageBackendUpdateVolTargetInfo(vol->type,
|
if ((ret = storageBackendUpdateVolTargetInfo(vol->type,
|
||||||
&vol->target,
|
&vol->target,
|
||||||
withBlockVolFormat,
|
withBlockVolFormat,
|
||||||
openflags, readflags)) < 0)
|
openflags, readflags)) < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (vol->target.backingStore &&
|
if (vol->target.backingStore &&
|
||||||
(ret = virStorageBackendUpdateVolTargetInfo(VIR_STORAGE_VOL_FILE,
|
(ret = storageBackendUpdateVolTargetInfo(VIR_STORAGE_VOL_FILE,
|
||||||
vol->target.backingStore,
|
vol->target.backingStore,
|
||||||
withBlockVolFormat,
|
withBlockVolFormat,
|
||||||
VIR_STORAGE_VOL_OPEN_DEFAULT |
|
VIR_STORAGE_VOL_OPEN_DEFAULT |
|
||||||
@ -2407,6 +2408,118 @@ virStorageBackendVolWipeLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @pool: storage pool to build
|
||||||
|
* @dir_create_flags: flags for directory creation
|
||||||
|
*
|
||||||
|
* Common code to build a directory based storage pool
|
||||||
|
*
|
||||||
|
* Returns 0 on success, -1 on failure
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
virStorageBackendBuildLocal(virStoragePoolObjPtr pool)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
char *parent = NULL;
|
||||||
|
char *p = NULL;
|
||||||
|
mode_t mode;
|
||||||
|
bool needs_create_as_uid;
|
||||||
|
unsigned int dir_create_flags;
|
||||||
|
|
||||||
|
if (VIR_STRDUP(parent, pool->def->target.path) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
if (!(p = strrchr(parent, '/'))) {
|
||||||
|
virReportError(VIR_ERR_INVALID_ARG,
|
||||||
|
_("path '%s' is not absolute"),
|
||||||
|
pool->def->target.path);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p != parent) {
|
||||||
|
/* assure all directories in the path prior to the final dir
|
||||||
|
* exist, with default uid/gid/mode. */
|
||||||
|
*p = '\0';
|
||||||
|
if (virFileMakePath(parent) < 0) {
|
||||||
|
virReportSystemError(errno, _("cannot create path '%s'"),
|
||||||
|
parent);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dir_create_flags = VIR_DIR_CREATE_ALLOW_EXIST;
|
||||||
|
needs_create_as_uid = (pool->def->type == VIR_STORAGE_POOL_NETFS);
|
||||||
|
mode = pool->def->target.perms.mode;
|
||||||
|
|
||||||
|
if (mode == (mode_t) -1 &&
|
||||||
|
(needs_create_as_uid || !virFileExists(pool->def->target.path)))
|
||||||
|
mode = VIR_STORAGE_DEFAULT_POOL_PERM_MODE;
|
||||||
|
if (needs_create_as_uid)
|
||||||
|
dir_create_flags |= VIR_DIR_CREATE_AS_UID;
|
||||||
|
|
||||||
|
/* Now create the final dir in the path with the uid/gid/mode
|
||||||
|
* requested in the config. If the dir already exists, just set
|
||||||
|
* the perms. */
|
||||||
|
if (virDirCreate(pool->def->target.path,
|
||||||
|
mode,
|
||||||
|
pool->def->target.perms.uid,
|
||||||
|
pool->def->target.perms.gid,
|
||||||
|
dir_create_flags) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(parent);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
virStorageBackendUmountLocal(virStoragePoolObjPtr pool)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
virCommandPtr cmd = virCommandNewArgList(UMOUNT, pool->def->target.path,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (virCommandRun(cmd, NULL) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
virCommandFree(cmd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @conn connection to report errors against
|
||||||
|
* @pool storage pool to delete
|
||||||
|
*
|
||||||
|
* Delete a directory based storage pool
|
||||||
|
*
|
||||||
|
* Returns 0 on success, -1 on error
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
virStorageBackendDeleteLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||||
|
virStoragePoolObjPtr pool,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
virCheckFlags(0, -1);
|
||||||
|
|
||||||
|
/* XXX delete all vols first ? */
|
||||||
|
|
||||||
|
if (rmdir(pool->def->target.path) < 0) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("failed to remove pool '%s'"),
|
||||||
|
pool->def->target.path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* virStorageBackendFindGlusterPoolSources:
|
* virStorageBackendFindGlusterPoolSources:
|
||||||
* @host: host to detect volumes on
|
* @host: host to detect volumes on
|
||||||
@ -2919,6 +3032,263 @@ virStorageBackendDeviceIsEmpty(const char *devpath,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
storageBackendProbeTarget(virStorageSourcePtr target,
|
||||||
|
virStorageEncryptionPtr *encryption)
|
||||||
|
{
|
||||||
|
int backingStoreFormat;
|
||||||
|
int fd = -1;
|
||||||
|
int ret = -1;
|
||||||
|
int rc;
|
||||||
|
virStorageSourcePtr meta = NULL;
|
||||||
|
struct stat sb;
|
||||||
|
|
||||||
|
if (encryption)
|
||||||
|
*encryption = NULL;
|
||||||
|
|
||||||
|
if ((rc = virStorageBackendVolOpen(target->path, &sb,
|
||||||
|
VIR_STORAGE_VOL_FS_PROBE_FLAGS)) < 0)
|
||||||
|
return rc; /* Take care to propagate rc, it is not always -1 */
|
||||||
|
fd = rc;
|
||||||
|
|
||||||
|
if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &sb) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (S_ISDIR(sb.st_mode)) {
|
||||||
|
if (storageBackendIsPloopDir(target->path)) {
|
||||||
|
if (storageBackendRedoPloopUpdate(target, &sb, &fd,
|
||||||
|
VIR_STORAGE_VOL_FS_PROBE_FLAGS) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
} else {
|
||||||
|
target->format = VIR_STORAGE_FILE_DIR;
|
||||||
|
ret = 0;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(meta = virStorageFileGetMetadataFromFD(target->path,
|
||||||
|
fd,
|
||||||
|
VIR_STORAGE_FILE_AUTO,
|
||||||
|
&backingStoreFormat)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (meta->backingStoreRaw) {
|
||||||
|
if (!(target->backingStore = virStorageSourceNewFromBacking(meta)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
target->backingStore->format = backingStoreFormat;
|
||||||
|
|
||||||
|
/* XXX: Remote storage doesn't play nicely with volumes backed by
|
||||||
|
* remote storage. To avoid trouble, just fake the backing store is RAW
|
||||||
|
* and put the string from the metadata as the path of the target. */
|
||||||
|
if (!virStorageSourceIsLocalStorage(target->backingStore)) {
|
||||||
|
virStorageSourceFree(target->backingStore);
|
||||||
|
|
||||||
|
if (VIR_ALLOC(target->backingStore) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
target->backingStore->type = VIR_STORAGE_TYPE_NETWORK;
|
||||||
|
target->backingStore->path = meta->backingStoreRaw;
|
||||||
|
meta->backingStoreRaw = NULL;
|
||||||
|
target->backingStore->format = VIR_STORAGE_FILE_RAW;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target->backingStore->format == VIR_STORAGE_FILE_AUTO) {
|
||||||
|
if ((rc = virStorageFileProbeFormat(target->backingStore->path,
|
||||||
|
-1, -1)) < 0) {
|
||||||
|
/* If the backing file is currently unavailable or is
|
||||||
|
* accessed via remote protocol only log an error, fake the
|
||||||
|
* format as RAW and continue. Returning -1 here would
|
||||||
|
* disable the whole storage pool, making it unavailable for
|
||||||
|
* even maintenance. */
|
||||||
|
target->backingStore->format = VIR_STORAGE_FILE_RAW;
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("cannot probe backing volume format: %s"),
|
||||||
|
target->backingStore->path);
|
||||||
|
} else {
|
||||||
|
target->backingStore->format = rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
target->format = meta->format;
|
||||||
|
|
||||||
|
/* Default to success below this point */
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
if (meta->capacity)
|
||||||
|
target->capacity = meta->capacity;
|
||||||
|
|
||||||
|
if (encryption && meta->encryption) {
|
||||||
|
*encryption = meta->encryption;
|
||||||
|
meta->encryption = NULL;
|
||||||
|
|
||||||
|
/* XXX ideally we'd fill in secret UUID here
|
||||||
|
* but we cannot guarantee 'conn' is non-NULL
|
||||||
|
* at this point in time :-( So we only fill
|
||||||
|
* in secrets when someone first queries a vol
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
virBitmapFree(target->features);
|
||||||
|
target->features = meta->features;
|
||||||
|
meta->features = NULL;
|
||||||
|
|
||||||
|
if (meta->compat) {
|
||||||
|
VIR_FREE(target->compat);
|
||||||
|
target->compat = meta->compat;
|
||||||
|
meta->compat = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FORCE_CLOSE(fd);
|
||||||
|
virStorageSourceFree(meta);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate over the pool's directory and enumerate all disk images
|
||||||
|
* within it. This is non-recursive.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
virStorageBackendRefreshLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||||
|
virStoragePoolObjPtr pool)
|
||||||
|
{
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *ent;
|
||||||
|
struct statvfs sb;
|
||||||
|
struct stat statbuf;
|
||||||
|
virStorageVolDefPtr vol = NULL;
|
||||||
|
virStorageSourcePtr target = NULL;
|
||||||
|
int direrr;
|
||||||
|
int fd = -1, ret = -1;
|
||||||
|
|
||||||
|
if (virDirOpen(&dir, pool->def->target.path) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
while ((direrr = virDirRead(dir, &ent, pool->def->target.path)) > 0) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (virStringHasControlChars(ent->d_name)) {
|
||||||
|
VIR_WARN("Ignoring file with control characters under '%s'",
|
||||||
|
pool->def->target.path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VIR_ALLOC(vol) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (VIR_STRDUP(vol->name, ent->d_name) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
vol->type = VIR_STORAGE_VOL_FILE;
|
||||||
|
vol->target.format = VIR_STORAGE_FILE_RAW; /* Real value is filled in during probe */
|
||||||
|
if (virAsprintf(&vol->target.path, "%s/%s",
|
||||||
|
pool->def->target.path,
|
||||||
|
vol->name) == -1)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (VIR_STRDUP(vol->key, vol->target.path) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if ((err = storageBackendProbeTarget(&vol->target,
|
||||||
|
&vol->target.encryption)) < 0) {
|
||||||
|
if (err == -2) {
|
||||||
|
/* Silently ignore non-regular files,
|
||||||
|
* eg 'lost+found', dangling symbolic link */
|
||||||
|
virStorageVolDefFree(vol);
|
||||||
|
vol = NULL;
|
||||||
|
continue;
|
||||||
|
} else if (err == -3) {
|
||||||
|
/* The backing file is currently unavailable, its format is not
|
||||||
|
* explicitly specified, the probe to auto detect the format
|
||||||
|
* failed: continue with faked RAW format, since AUTO will
|
||||||
|
* break virStorageVolTargetDefFormat() generating the line
|
||||||
|
* <format type='...'/>. */
|
||||||
|
} else {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* directory based volume */
|
||||||
|
if (vol->target.format == VIR_STORAGE_FILE_DIR)
|
||||||
|
vol->type = VIR_STORAGE_VOL_DIR;
|
||||||
|
|
||||||
|
if (vol->target.format == VIR_STORAGE_FILE_PLOOP)
|
||||||
|
vol->type = VIR_STORAGE_VOL_PLOOP;
|
||||||
|
|
||||||
|
if (vol->target.backingStore) {
|
||||||
|
ignore_value(storageBackendUpdateVolTargetInfo(VIR_STORAGE_VOL_FILE,
|
||||||
|
vol->target.backingStore,
|
||||||
|
false,
|
||||||
|
VIR_STORAGE_VOL_OPEN_DEFAULT, 0));
|
||||||
|
/* If this failed, the backing file is currently unavailable,
|
||||||
|
* the capacity, allocation, owner, group and mode are unknown.
|
||||||
|
* An error message was raised, but we just continue. */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (direrr < 0)
|
||||||
|
goto cleanup;
|
||||||
|
VIR_DIR_CLOSE(dir);
|
||||||
|
vol = NULL;
|
||||||
|
|
||||||
|
if (VIR_ALLOC(target))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if ((fd = open(pool->def->target.path, O_RDONLY)) < 0) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("cannot open path '%s'"),
|
||||||
|
pool->def->target.path);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fstat(fd, &statbuf) < 0) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("cannot stat path '%s'"),
|
||||||
|
pool->def->target.path);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virStorageBackendUpdateVolTargetInfoFD(target, fd, &statbuf) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* VolTargetInfoFD doesn't update capacity correctly for the pool case */
|
||||||
|
if (statvfs(pool->def->target.path, &sb) < 0) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("cannot statvfs path '%s'"),
|
||||||
|
pool->def->target.path);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
pool->def->capacity = ((unsigned long long)sb.f_frsize *
|
||||||
|
(unsigned long long)sb.f_blocks);
|
||||||
|
pool->def->available = ((unsigned long long)sb.f_bfree *
|
||||||
|
(unsigned long long)sb.f_frsize);
|
||||||
|
pool->def->allocation = pool->def->capacity - pool->def->available;
|
||||||
|
|
||||||
|
pool->def->target.perms.mode = target->perms->mode;
|
||||||
|
pool->def->target.perms.uid = target->perms->uid;
|
||||||
|
pool->def->target.perms.gid = target->perms->gid;
|
||||||
|
VIR_FREE(pool->def->target.perms.label);
|
||||||
|
if (VIR_STRDUP(pool->def->target.perms.label, target->perms->label) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
cleanup:
|
||||||
|
VIR_DIR_CLOSE(dir);
|
||||||
|
VIR_FORCE_CLOSE(fd);
|
||||||
|
virStorageVolDefFree(vol);
|
||||||
|
virStorageSourceFree(target);
|
||||||
|
if (ret < 0)
|
||||||
|
virStoragePoolObjClearVols(pool);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
virStorageBackendSCSISerial(const char *dev)
|
virStorageBackendSCSISerial(const char *dev)
|
||||||
{
|
{
|
||||||
|
@ -49,20 +49,10 @@ int virStorageBackendCreatePloop(virConnectPtr conn,
|
|||||||
int virStoragePloopResize(virStorageVolDefPtr vol,
|
int virStoragePloopResize(virStorageVolDefPtr vol,
|
||||||
unsigned long long capacity);
|
unsigned long long capacity);
|
||||||
|
|
||||||
int virStorageBackendRedoPloopUpdate(virStorageSourcePtr target,
|
|
||||||
struct stat *sb, int *fd,
|
|
||||||
unsigned int flags);
|
|
||||||
bool virStorageBackendIsPloopDir(char *path);
|
|
||||||
|
|
||||||
virStorageBackendBuildVolFrom
|
virStorageBackendBuildVolFrom
|
||||||
virStorageBackendGetBuildVolFromFunction(virStorageVolDefPtr vol,
|
virStorageBackendGetBuildVolFromFunction(virStorageVolDefPtr vol,
|
||||||
virStorageVolDefPtr inputvol);
|
virStorageVolDefPtr inputvol);
|
||||||
|
|
||||||
int virStorageBackendFindGlusterPoolSources(const char *host,
|
|
||||||
int pooltype,
|
|
||||||
virStoragePoolSourceListPtr list,
|
|
||||||
bool report);
|
|
||||||
|
|
||||||
int virStorageBackendVolUploadLocal(virConnectPtr conn,
|
int virStorageBackendVolUploadLocal(virConnectPtr conn,
|
||||||
virStoragePoolObjPtr pool,
|
virStoragePoolObjPtr pool,
|
||||||
virStorageVolDefPtr vol,
|
virStorageVolDefPtr vol,
|
||||||
@ -84,6 +74,23 @@ int virStorageBackendVolWipeLocal(virConnectPtr conn,
|
|||||||
unsigned int algorithm,
|
unsigned int algorithm,
|
||||||
unsigned int flags);
|
unsigned int flags);
|
||||||
|
|
||||||
|
/* Local/Common Storage Pool Backend APIs */
|
||||||
|
int virStorageBackendBuildLocal(virStoragePoolObjPtr pool);
|
||||||
|
|
||||||
|
int virStorageBackendUmountLocal(virStoragePoolObjPtr pool);
|
||||||
|
|
||||||
|
int virStorageBackendDeleteLocal(virConnectPtr conn,
|
||||||
|
virStoragePoolObjPtr pool,
|
||||||
|
unsigned int flags);
|
||||||
|
|
||||||
|
int virStorageBackendRefreshLocal(virConnectPtr conn,
|
||||||
|
virStoragePoolObjPtr pool);
|
||||||
|
|
||||||
|
int virStorageBackendFindGlusterPoolSources(const char *host,
|
||||||
|
int pooltype,
|
||||||
|
virStoragePoolSourceListPtr list,
|
||||||
|
bool report);
|
||||||
|
|
||||||
bool virStorageBackendDeviceIsEmpty(const char *devpath,
|
bool virStorageBackendDeviceIsEmpty(const char *devpath,
|
||||||
const char *format,
|
const char *format,
|
||||||
bool writelabel);
|
bool writelabel);
|
||||||
@ -110,6 +117,11 @@ enum {
|
|||||||
# define VIR_STORAGE_VOL_OPEN_DEFAULT (VIR_STORAGE_VOL_OPEN_REG |\
|
# define VIR_STORAGE_VOL_OPEN_DEFAULT (VIR_STORAGE_VOL_OPEN_REG |\
|
||||||
VIR_STORAGE_VOL_OPEN_BLOCK)
|
VIR_STORAGE_VOL_OPEN_BLOCK)
|
||||||
|
|
||||||
|
# define VIR_STORAGE_VOL_FS_OPEN_FLAGS (VIR_STORAGE_VOL_OPEN_DEFAULT | \
|
||||||
|
VIR_STORAGE_VOL_OPEN_DIR)
|
||||||
|
# define VIR_STORAGE_VOL_FS_PROBE_FLAGS (VIR_STORAGE_VOL_FS_OPEN_FLAGS | \
|
||||||
|
VIR_STORAGE_VOL_OPEN_NOERROR)
|
||||||
|
|
||||||
int virStorageBackendVolOpen(const char *path, struct stat *sb,
|
int virStorageBackendVolOpen(const char *path, struct stat *sb,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
ATTRIBUTE_RETURN_CHECK
|
ATTRIBUTE_RETURN_CHECK
|
||||||
@ -122,11 +134,6 @@ int virStorageBackendUpdateVolInfo(virStorageVolDefPtr vol,
|
|||||||
bool withBlockVolFormat,
|
bool withBlockVolFormat,
|
||||||
unsigned int openflags,
|
unsigned int openflags,
|
||||||
unsigned int readflags);
|
unsigned int readflags);
|
||||||
int virStorageBackendUpdateVolTargetInfo(virStorageVolType voltype,
|
|
||||||
virStorageSourcePtr target,
|
|
||||||
bool withBlockVolFormat,
|
|
||||||
unsigned int openflags,
|
|
||||||
unsigned int readflags);
|
|
||||||
int virStorageBackendUpdateVolTargetInfoFD(virStorageSourcePtr target,
|
int virStorageBackendUpdateVolTargetInfoFD(virStorageSourcePtr target,
|
||||||
int fd,
|
int fd,
|
||||||
struct stat *sb);
|
struct stat *sb);
|
||||||
|
Loading…
Reference in New Issue
Block a user