storage: Create common file/dir volume backend helpers

Move all the volume 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 more 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:
John Ferlan 2017-01-21 09:05:41 -05:00
parent 5f07c3c079
commit 1452c85fb7
3 changed files with 469 additions and 466 deletions

View File

@ -625,342 +625,6 @@ virStorageBackendFileSystemBuild(virConnectPtr conn ATTRIBUTE_UNUSED,
} }
/**
* Set up a volume definition to be added to a pool's volume list, but
* don't do any file creation or allocation. By separating the two processes,
* we allow allocation progress reporting (by polling the volume's 'info'
* function), and can drop the parent pool lock during the (slow) allocation.
*/
static int
virStorageBackendFileSystemVolCreate(virConnectPtr conn ATTRIBUTE_UNUSED,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol)
{
if (vol->target.format == VIR_STORAGE_FILE_DIR)
vol->type = VIR_STORAGE_VOL_DIR;
else if (vol->target.format == VIR_STORAGE_FILE_PLOOP)
vol->type = VIR_STORAGE_VOL_PLOOP;
else
vol->type = VIR_STORAGE_VOL_FILE;
/* Volumes within a directory pools are not recursive; do not
* allow escape to ../ or a subdir */
if (strchr(vol->name, '/')) {
virReportError(VIR_ERR_OPERATION_INVALID,
_("volume name '%s' cannot contain '/'"), vol->name);
return -1;
}
VIR_FREE(vol->target.path);
if (virAsprintf(&vol->target.path, "%s/%s",
pool->def->target.path,
vol->name) == -1)
return -1;
if (virFileExists(vol->target.path)) {
virReportError(VIR_ERR_OPERATION_INVALID,
_("volume target path '%s' already exists"),
vol->target.path);
return -1;
}
VIR_FREE(vol->key);
return VIR_STRDUP(vol->key, vol->target.path);
}
static int createFileDir(virConnectPtr conn ATTRIBUTE_UNUSED,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol,
unsigned int flags)
{
int err;
virCheckFlags(0, -1);
if (inputvol) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s",
_("cannot copy from volume to a directory volume"));
return -1;
}
if (vol->target.backingStore) {
virReportError(VIR_ERR_NO_SUPPORT, "%s",
_("backing storage not supported for directories volumes"));
return -1;
}
if ((err = virDirCreate(vol->target.path,
(vol->target.perms->mode == (mode_t) -1 ?
VIR_STORAGE_DEFAULT_VOL_PERM_MODE :
vol->target.perms->mode),
vol->target.perms->uid,
vol->target.perms->gid,
(pool->def->type == VIR_STORAGE_POOL_NETFS
? VIR_DIR_CREATE_AS_UID : 0))) < 0) {
return -1;
}
return 0;
}
static int
_virStorageBackendFileSystemVolBuild(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol,
unsigned int flags)
{
virStorageBackendBuildVolFrom create_func;
if (inputvol) {
if (vol->target.encryption != NULL) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
"%s", _("storage pool does not support "
"building encrypted volumes from "
"other volumes"));
return -1;
}
create_func = virStorageBackendGetBuildVolFromFunction(vol,
inputvol);
if (!create_func)
return -1;
} else if (vol->target.format == VIR_STORAGE_FILE_RAW &&
vol->target.encryption == NULL) {
create_func = virStorageBackendCreateRaw;
} else if (vol->target.format == VIR_STORAGE_FILE_DIR) {
create_func = createFileDir;
} else if (vol->target.format == VIR_STORAGE_FILE_PLOOP) {
create_func = virStorageBackendCreatePloop;
} else {
create_func = virStorageBackendCreateQemuImg;
}
if (create_func(conn, pool, vol, inputvol, flags) < 0)
return -1;
return 0;
}
/**
* Allocate a new file as a volume. This is either done directly
* for raw/sparse files, or by calling qemu-img for
* special kinds of files
*/
static int
virStorageBackendFileSystemVolBuild(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol,
unsigned int flags)
{
virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA |
VIR_STORAGE_VOL_CREATE_REFLINK,
-1);
return _virStorageBackendFileSystemVolBuild(conn, pool, vol, NULL, flags);
}
/*
* Create a storage vol using 'inputvol' as input
*/
static int
virStorageBackendFileSystemVolBuildFrom(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol,
unsigned int flags)
{
virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA |
VIR_STORAGE_VOL_CREATE_REFLINK,
-1);
return _virStorageBackendFileSystemVolBuild(conn, pool, vol, inputvol, flags);
}
/**
* Remove a volume - no support for BLOCK and NETWORK yet
*/
static int
virStorageBackendFileSystemVolDelete(virConnectPtr conn ATTRIBUTE_UNUSED,
virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
virStorageVolDefPtr vol,
unsigned int flags)
{
virCheckFlags(0, -1);
switch ((virStorageVolType) vol->type) {
case VIR_STORAGE_VOL_FILE:
case VIR_STORAGE_VOL_DIR:
if (virFileRemove(vol->target.path, vol->target.perms->uid,
vol->target.perms->gid) < 0) {
/* Silently ignore failures where the vol has already gone away */
if (errno != ENOENT) {
if (vol->type == VIR_STORAGE_VOL_FILE)
virReportSystemError(errno,
_("cannot unlink file '%s'"),
vol->target.path);
else
virReportSystemError(errno,
_("cannot remove directory '%s'"),
vol->target.path);
return -1;
}
}
break;
case VIR_STORAGE_VOL_PLOOP:
if (virFileDeleteTree(vol->target.path) < 0)
return -1;
break;
case VIR_STORAGE_VOL_BLOCK:
case VIR_STORAGE_VOL_NETWORK:
case VIR_STORAGE_VOL_NETDIR:
case VIR_STORAGE_VOL_LAST:
virReportError(VIR_ERR_NO_SUPPORT,
_("removing block or network volumes is not supported: %s"),
vol->target.path);
return -1;
}
return 0;
}
/* virStorageBackendFileSystemLoadDefaultSecrets:
* @conn: Connection pointer to fetch secret
* @vol: volume being refreshed
*
* If the volume had a secret generated, we need to regenerate the
* encryption secret information
*
* Returns 0 if no secret or secret setup was successful,
* -1 on failures w/ error message set
*/
static int
virStorageBackendFileSystemLoadDefaultSecrets(virConnectPtr conn,
virStorageVolDefPtr vol)
{
virSecretPtr sec;
virStorageEncryptionSecretPtr encsec = NULL;
if (!vol->target.encryption || vol->target.encryption->nsecrets != 0)
return 0;
/* The encryption secret for qcow2 and luks volumes use the path
* to the volume, so look for a secret with the path. If not found,
* then we cannot generate the secret after a refresh (or restart).
* This may be the case if someone didn't follow instructions and created
* a usage string that although matched with the secret usage string,
* didn't contain the path to the volume. We won't error in that case,
* but we also cannot find the secret. */
if (!(sec = virSecretLookupByUsage(conn, VIR_SECRET_USAGE_TYPE_VOLUME,
vol->target.path)))
return 0;
if (VIR_ALLOC_N(vol->target.encryption->secrets, 1) < 0 ||
VIR_ALLOC(encsec) < 0) {
VIR_FREE(vol->target.encryption->secrets);
virObjectUnref(sec);
return -1;
}
vol->target.encryption->nsecrets = 1;
vol->target.encryption->secrets[0] = encsec;
encsec->type = VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE;
encsec->seclookupdef.type = VIR_SECRET_LOOKUP_TYPE_UUID;
virSecretGetUUID(sec, encsec->seclookupdef.u.uuid);
virObjectUnref(sec);
return 0;
}
/**
* Update info about a volume's capacity/allocation
*/
static int
virStorageBackendFileSystemVolRefresh(virConnectPtr conn,
virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
virStorageVolDefPtr vol)
{
int ret;
/* Refresh allocation / capacity / permissions info in case its changed */
if ((ret = virStorageBackendUpdateVolInfo(vol, false,
VIR_STORAGE_VOL_FS_OPEN_FLAGS,
0)) < 0)
return ret;
/* Load any secrets if possible */
return virStorageBackendFileSystemLoadDefaultSecrets(conn, vol);
}
static int
virStorageBackendFilesystemResizeQemuImg(const char *path,
unsigned long long capacity)
{
int ret = -1;
char *img_tool;
virCommandPtr cmd = NULL;
img_tool = virFindFileInPath("qemu-img");
if (!img_tool) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("unable to find qemu-img"));
return -1;
}
/* Round capacity as qemu-img resize errors out on sizes which are not
* a multiple of 512 */
capacity = VIR_ROUND_UP(capacity, 512);
cmd = virCommandNew(img_tool);
virCommandAddArgList(cmd, "resize", path, NULL);
virCommandAddArgFormat(cmd, "%llu", capacity);
ret = virCommandRun(cmd, NULL);
VIR_FREE(img_tool);
virCommandFree(cmd);
return ret;
}
/**
* Resize a volume
*/
static int
virStorageBackendFileSystemVolResize(virConnectPtr conn ATTRIBUTE_UNUSED,
virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
virStorageVolDefPtr vol,
unsigned long long capacity,
unsigned int flags)
{
virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE |
VIR_STORAGE_VOL_RESIZE_SHRINK, -1);
bool pre_allocate = flags & VIR_STORAGE_VOL_RESIZE_ALLOCATE;
if (vol->target.format == VIR_STORAGE_FILE_RAW) {
return virStorageFileResize(vol->target.path, capacity,
vol->target.allocation, pre_allocate);
} else if (vol->target.format == VIR_STORAGE_FILE_PLOOP) {
return virStoragePloopResize(vol, capacity);
} else {
if (pre_allocate) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("preallocate is only supported for raw "
"type volume"));
return -1;
}
return virStorageBackendFilesystemResizeQemuImg(vol->target.path,
capacity);
}
}
virStorageBackend virStorageBackendDirectory = { virStorageBackend virStorageBackendDirectory = {
.type = VIR_STORAGE_POOL_DIR, .type = VIR_STORAGE_POOL_DIR,
@ -968,12 +632,12 @@ virStorageBackend virStorageBackendDirectory = {
.checkPool = virStorageBackendFileSystemCheck, .checkPool = virStorageBackendFileSystemCheck,
.refreshPool = virStorageBackendRefreshLocal, .refreshPool = virStorageBackendRefreshLocal,
.deletePool = virStorageBackendDeleteLocal, .deletePool = virStorageBackendDeleteLocal,
.buildVol = virStorageBackendFileSystemVolBuild, .buildVol = virStorageBackendVolBuildLocal,
.buildVolFrom = virStorageBackendFileSystemVolBuildFrom, .buildVolFrom = virStorageBackendVolBuildFromLocal,
.createVol = virStorageBackendFileSystemVolCreate, .createVol = virStorageBackendVolCreateLocal,
.refreshVol = virStorageBackendFileSystemVolRefresh, .refreshVol = virStorageBackendVolRefreshLocal,
.deleteVol = virStorageBackendFileSystemVolDelete, .deleteVol = virStorageBackendVolDeleteLocal,
.resizeVol = virStorageBackendFileSystemVolResize, .resizeVol = virStorageBackendVolResizeLocal,
.uploadVol = virStorageBackendVolUploadLocal, .uploadVol = virStorageBackendVolUploadLocal,
.downloadVol = virStorageBackendVolDownloadLocal, .downloadVol = virStorageBackendVolDownloadLocal,
.wipeVol = virStorageBackendVolWipeLocal, .wipeVol = virStorageBackendVolWipeLocal,
@ -989,12 +653,12 @@ virStorageBackend virStorageBackendFileSystem = {
.refreshPool = virStorageBackendRefreshLocal, .refreshPool = virStorageBackendRefreshLocal,
.stopPool = virStorageBackendFileSystemStop, .stopPool = virStorageBackendFileSystemStop,
.deletePool = virStorageBackendDeleteLocal, .deletePool = virStorageBackendDeleteLocal,
.buildVol = virStorageBackendFileSystemVolBuild, .buildVol = virStorageBackendVolBuildLocal,
.buildVolFrom = virStorageBackendFileSystemVolBuildFrom, .buildVolFrom = virStorageBackendVolBuildFromLocal,
.createVol = virStorageBackendFileSystemVolCreate, .createVol = virStorageBackendVolCreateLocal,
.refreshVol = virStorageBackendFileSystemVolRefresh, .refreshVol = virStorageBackendVolRefreshLocal,
.deleteVol = virStorageBackendFileSystemVolDelete, .deleteVol = virStorageBackendVolDeleteLocal,
.resizeVol = virStorageBackendFileSystemVolResize, .resizeVol = virStorageBackendVolResizeLocal,
.uploadVol = virStorageBackendVolUploadLocal, .uploadVol = virStorageBackendVolUploadLocal,
.downloadVol = virStorageBackendVolDownloadLocal, .downloadVol = virStorageBackendVolDownloadLocal,
.wipeVol = virStorageBackendVolWipeLocal, .wipeVol = virStorageBackendVolWipeLocal,
@ -1009,12 +673,12 @@ virStorageBackend virStorageBackendNetFileSystem = {
.refreshPool = virStorageBackendRefreshLocal, .refreshPool = virStorageBackendRefreshLocal,
.stopPool = virStorageBackendFileSystemStop, .stopPool = virStorageBackendFileSystemStop,
.deletePool = virStorageBackendDeleteLocal, .deletePool = virStorageBackendDeleteLocal,
.buildVol = virStorageBackendFileSystemVolBuild, .buildVol = virStorageBackendVolBuildLocal,
.buildVolFrom = virStorageBackendFileSystemVolBuildFrom, .buildVolFrom = virStorageBackendVolBuildFromLocal,
.createVol = virStorageBackendFileSystemVolCreate, .createVol = virStorageBackendVolCreateLocal,
.refreshVol = virStorageBackendFileSystemVolRefresh, .refreshVol = virStorageBackendVolRefreshLocal,
.deleteVol = virStorageBackendFileSystemVolDelete, .deleteVol = virStorageBackendVolDeleteLocal,
.resizeVol = virStorageBackendFileSystemVolResize, .resizeVol = virStorageBackendVolResizeLocal,
.uploadVol = virStorageBackendVolUploadLocal, .uploadVol = virStorageBackendVolUploadLocal,
.downloadVol = virStorageBackendVolDownloadLocal, .downloadVol = virStorageBackendVolDownloadLocal,
.wipeVol = virStorageBackendVolWipeLocal, .wipeVol = virStorageBackendVolWipeLocal,

View File

@ -222,7 +222,7 @@ virStorageBackendCopyToFD(virStorageVolDefPtr vol,
} }
static int static int
virStorageBackendCreateBlockFrom(virConnectPtr conn ATTRIBUTE_UNUSED, storageBackendCreateBlockFrom(virConnectPtr conn ATTRIBUTE_UNUSED,
virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
virStorageVolDefPtr vol, virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol, virStorageVolDefPtr inputvol,
@ -389,8 +389,8 @@ createRawFile(int fd, virStorageVolDefPtr vol,
return ret; return ret;
} }
int static int
virStorageBackendCreateRaw(virConnectPtr conn ATTRIBUTE_UNUSED, storageBackendCreateRaw(virConnectPtr conn ATTRIBUTE_UNUSED,
virStoragePoolObjPtr pool, virStoragePoolObjPtr pool,
virStorageVolDefPtr vol, virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol, virStorageVolDefPtr inputvol,
@ -692,8 +692,8 @@ virStorageBackendCreateExecCommand(virStoragePoolObjPtr pool,
/* Create ploop directory with ploop image and DiskDescriptor.xml /* Create ploop directory with ploop image and DiskDescriptor.xml
* if function fails to create image file the directory will be deleted.*/ * if function fails to create image file the directory will be deleted.*/
int static int
virStorageBackendCreatePloop(virConnectPtr conn ATTRIBUTE_UNUSED, storageBackendCreatePloop(virConnectPtr conn ATTRIBUTE_UNUSED,
virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
virStorageVolDefPtr vol, virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol, virStorageVolDefPtr inputvol,
@ -767,8 +767,9 @@ virStorageBackendCreatePloop(virConnectPtr conn ATTRIBUTE_UNUSED,
return ret; return ret;
} }
int
virStoragePloopResize(virStorageVolDefPtr vol, static int
storagePloopResize(virStorageVolDefPtr vol,
unsigned long long capacity) unsigned long long capacity)
{ {
int ret = -1; int ret = -1;
@ -875,7 +876,7 @@ struct _virStorageBackendQemuImgInfo {
static int static int
virStorageBackendCreateQemuImgOpts(virStorageEncryptionInfoDefPtr enc, storageBackendCreateQemuImgOpts(virStorageEncryptionInfoDefPtr enc,
char **opts, char **opts,
struct _virStorageBackendQemuImgInfo info) struct _virStorageBackendQemuImgInfo info)
{ {
@ -927,7 +928,7 @@ virStorageBackendCreateQemuImgOpts(virStorageEncryptionInfoDefPtr enc,
} }
/* virStorageBackendCreateQemuImgCheckEncryption: /* storageBackendCreateQemuImgCheckEncryption:
* @format: format of file found * @format: format of file found
* @conn: pointer to connection * @conn: pointer to connection
* @vol: pointer to volume def * @vol: pointer to volume def
@ -937,7 +938,7 @@ virStorageBackendCreateQemuImgOpts(virStorageEncryptionInfoDefPtr enc,
* Returns 0 on success, -1 on failure w/ error set * Returns 0 on success, -1 on failure w/ error set
*/ */
static int static int
virStorageBackendCreateQemuImgCheckEncryption(int format, storageBackendCreateQemuImgCheckEncryption(int format,
const char *type, const char *type,
virConnectPtr conn, virConnectPtr conn,
virStorageVolDefPtr vol) virStorageVolDefPtr vol)
@ -996,7 +997,7 @@ virStorageBackendCreateQemuImgCheckEncryption(int format,
static int static int
virStorageBackendCreateQemuImgSetInput(virStorageVolDefPtr inputvol, storageBackendCreateQemuImgSetInput(virStorageVolDefPtr inputvol,
struct _virStorageBackendQemuImgInfo *info) struct _virStorageBackendQemuImgInfo *info)
{ {
if (!(info->inputPath = inputvol->target.path)) { if (!(info->inputPath = inputvol->target.path)) {
@ -1021,7 +1022,7 @@ virStorageBackendCreateQemuImgSetInput(virStorageVolDefPtr inputvol,
static int static int
virStorageBackendCreateQemuImgSetBacking(virStoragePoolObjPtr pool, storageBackendCreateQemuImgSetBacking(virStoragePoolObjPtr pool,
virStorageVolDefPtr vol, virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol, virStorageVolDefPtr inputvol,
struct _virStorageBackendQemuImgInfo *info) struct _virStorageBackendQemuImgInfo *info)
@ -1086,7 +1087,7 @@ virStorageBackendCreateQemuImgSetBacking(virStoragePoolObjPtr pool,
static int static int
virStorageBackendCreateQemuImgSetOptions(virCommandPtr cmd, storageBackendCreateQemuImgSetOptions(virCommandPtr cmd,
int imgformat, int imgformat,
virStorageEncryptionInfoDefPtr enc, virStorageEncryptionInfoDefPtr enc,
struct _virStorageBackendQemuImgInfo info) struct _virStorageBackendQemuImgInfo info)
@ -1097,7 +1098,7 @@ virStorageBackendCreateQemuImgSetOptions(virCommandPtr cmd,
imgformat >= QEMU_IMG_BACKING_FORMAT_OPTIONS_COMPAT) imgformat >= QEMU_IMG_BACKING_FORMAT_OPTIONS_COMPAT)
info.compat = "0.10"; info.compat = "0.10";
if (virStorageBackendCreateQemuImgOpts(enc, &opts, info) < 0) if (storageBackendCreateQemuImgOpts(enc, &opts, info) < 0)
return -1; return -1;
if (opts) if (opts)
virCommandAddArgList(cmd, "-o", opts, NULL); virCommandAddArgList(cmd, "-o", opts, NULL);
@ -1113,7 +1114,7 @@ virStorageBackendCreateQemuImgSetOptions(virCommandPtr cmd,
* NB: format=raw is assumed * NB: format=raw is assumed
*/ */
static int static int
virStorageBackendCreateQemuImgSecretObject(virCommandPtr cmd, storageBackendCreateQemuImgSecretObject(virCommandPtr cmd,
virStorageVolDefPtr vol, virStorageVolDefPtr vol,
struct _virStorageBackendQemuImgInfo *info) struct _virStorageBackendQemuImgInfo *info)
{ {
@ -1218,16 +1219,15 @@ virStorageBackendCreateQemuImgCmdFromVol(virConnectPtr conn,
} }
if (inputvol && if (inputvol &&
virStorageBackendCreateQemuImgSetInput(inputvol, &info) < 0) storageBackendCreateQemuImgSetInput(inputvol, &info) < 0)
return NULL; return NULL;
if (vol->target.backingStore && if (vol->target.backingStore &&
virStorageBackendCreateQemuImgSetBacking(pool, vol, inputvol, storageBackendCreateQemuImgSetBacking(pool, vol, inputvol, &info) < 0)
&info) < 0)
return NULL; return NULL;
if (info.encryption && if (info.encryption &&
virStorageBackendCreateQemuImgCheckEncryption(info.format, type, storageBackendCreateQemuImgCheckEncryption(info.format, type,
conn, vol) < 0) conn, vol) < 0)
return NULL; return NULL;
@ -1253,7 +1253,7 @@ virStorageBackendCreateQemuImgCmdFromVol(virConnectPtr conn,
if (info.format == VIR_STORAGE_FILE_RAW && if (info.format == VIR_STORAGE_FILE_RAW &&
vol->target.encryption != NULL && vol->target.encryption != NULL &&
vol->target.encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) { vol->target.encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) {
if (virStorageBackendCreateQemuImgSecretObject(cmd, vol, &info) < 0) { if (storageBackendCreateQemuImgSecretObject(cmd, vol, &info) < 0) {
VIR_FREE(info.secretAlias); VIR_FREE(info.secretAlias);
virCommandFree(cmd); virCommandFree(cmd);
return NULL; return NULL;
@ -1261,8 +1261,7 @@ virStorageBackendCreateQemuImgCmdFromVol(virConnectPtr conn,
enc = &vol->target.encryption->encinfo; enc = &vol->target.encryption->encinfo;
} }
if (virStorageBackendCreateQemuImgSetOptions(cmd, imgformat, if (storageBackendCreateQemuImgSetOptions(cmd, imgformat, enc, info) < 0) {
enc, info) < 0) {
VIR_FREE(info.secretAlias); VIR_FREE(info.secretAlias);
virCommandFree(cmd); virCommandFree(cmd);
return NULL; return NULL;
@ -1280,7 +1279,7 @@ virStorageBackendCreateQemuImgCmdFromVol(virConnectPtr conn,
static char * static char *
virStorageBackendCreateQemuImgSecretPath(virConnectPtr conn, storageBackendCreateQemuImgSecretPath(virConnectPtr conn,
virStoragePoolObjPtr pool, virStoragePoolObjPtr pool,
virStorageVolDefPtr vol) virStorageVolDefPtr vol)
{ {
@ -1349,8 +1348,8 @@ virStorageBackendCreateQemuImgSecretPath(virConnectPtr conn,
} }
int static int
virStorageBackendCreateQemuImg(virConnectPtr conn, storageBackendCreateQemuImg(virConnectPtr conn,
virStoragePoolObjPtr pool, virStoragePoolObjPtr pool,
virStorageVolDefPtr vol, virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol, virStorageVolDefPtr inputvol,
@ -1380,7 +1379,7 @@ virStorageBackendCreateQemuImg(virConnectPtr conn,
vol->target.encryption && vol->target.encryption &&
vol->target.encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) { vol->target.encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) {
if (!(secretPath = if (!(secretPath =
virStorageBackendCreateQemuImgSecretPath(conn, pool, vol))) storageBackendCreateQemuImgSecretPath(conn, pool, vol)))
goto cleanup; goto cleanup;
} }
@ -1418,15 +1417,15 @@ virStorageBackendGetBuildVolFromFunction(virStorageVolDefPtr vol,
(inputvol->type == VIR_STORAGE_VOL_FILE && (inputvol->type == VIR_STORAGE_VOL_FILE &&
(inputvol->target.format != VIR_STORAGE_FILE_RAW || (inputvol->target.format != VIR_STORAGE_FILE_RAW ||
inputvol->target.encryption != NULL))) { inputvol->target.encryption != NULL))) {
return virStorageBackendCreateQemuImg; return storageBackendCreateQemuImg;
} }
if (vol->type == VIR_STORAGE_VOL_PLOOP) if (vol->type == VIR_STORAGE_VOL_PLOOP)
return virStorageBackendCreatePloop; return storageBackendCreatePloop;
if (vol->type == VIR_STORAGE_VOL_BLOCK) if (vol->type == VIR_STORAGE_VOL_BLOCK)
return virStorageBackendCreateBlockFrom; return storageBackendCreateBlockFrom;
else else
return virStorageBackendCreateRaw; return storageBackendCreateRaw;
} }
@ -2008,6 +2007,340 @@ virStorageBackendStablePath(virStoragePoolObjPtr pool,
return stablepath; return stablepath;
} }
/* Common/Local File System/Directory Volume API's */
static int
createFileDir(virConnectPtr conn ATTRIBUTE_UNUSED,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol,
unsigned int flags)
{
int err;
virCheckFlags(0, -1);
if (inputvol) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s",
_("cannot copy from volume to a directory volume"));
return -1;
}
if (vol->target.backingStore) {
virReportError(VIR_ERR_NO_SUPPORT, "%s",
_("backing storage not supported for directories volumes"));
return -1;
}
if ((err = virDirCreate(vol->target.path,
(vol->target.perms->mode == (mode_t) -1 ?
VIR_STORAGE_DEFAULT_VOL_PERM_MODE :
vol->target.perms->mode),
vol->target.perms->uid,
vol->target.perms->gid,
(pool->def->type == VIR_STORAGE_POOL_NETFS
? VIR_DIR_CREATE_AS_UID : 0))) < 0) {
return -1;
}
return 0;
}
/**
* Set up a volume definition to be added to a pool's volume list, but
* don't do any file creation or allocation. By separating the two processes,
* we allow allocation progress reporting (by polling the volume's 'info'
* function), and can drop the parent pool lock during the (slow) allocation.
*/
int
virStorageBackendVolCreateLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol)
{
if (vol->target.format == VIR_STORAGE_FILE_DIR)
vol->type = VIR_STORAGE_VOL_DIR;
else if (vol->target.format == VIR_STORAGE_FILE_PLOOP)
vol->type = VIR_STORAGE_VOL_PLOOP;
else
vol->type = VIR_STORAGE_VOL_FILE;
/* Volumes within a directory pools are not recursive; do not
* allow escape to ../ or a subdir */
if (strchr(vol->name, '/')) {
virReportError(VIR_ERR_OPERATION_INVALID,
_("volume name '%s' cannot contain '/'"), vol->name);
return -1;
}
VIR_FREE(vol->target.path);
if (virAsprintf(&vol->target.path, "%s/%s",
pool->def->target.path,
vol->name) == -1)
return -1;
if (virFileExists(vol->target.path)) {
virReportError(VIR_ERR_OPERATION_INVALID,
_("volume target path '%s' already exists"),
vol->target.path);
return -1;
}
VIR_FREE(vol->key);
return VIR_STRDUP(vol->key, vol->target.path);
}
static int
storageBackendVolBuildLocal(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol,
unsigned int flags)
{
virStorageBackendBuildVolFrom create_func;
if (inputvol) {
if (vol->target.encryption != NULL) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
"%s", _("storage pool does not support "
"building encrypted volumes from "
"other volumes"));
return -1;
}
if (!(create_func =
virStorageBackendGetBuildVolFromFunction(vol, inputvol)))
return -1;
} else if (vol->target.format == VIR_STORAGE_FILE_RAW &&
vol->target.encryption == NULL) {
create_func = storageBackendCreateRaw;
} else if (vol->target.format == VIR_STORAGE_FILE_DIR) {
create_func = createFileDir;
} else if (vol->target.format == VIR_STORAGE_FILE_PLOOP) {
create_func = storageBackendCreatePloop;
} else {
create_func = storageBackendCreateQemuImg;
}
if (create_func(conn, pool, vol, inputvol, flags) < 0)
return -1;
return 0;
}
/**
* Allocate a new file as a volume. This is either done directly
* for raw/sparse files, or by calling qemu-img for
* special kinds of files
*/
int
virStorageBackendVolBuildLocal(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol,
unsigned int flags)
{
return storageBackendVolBuildLocal(conn, pool, vol, NULL, flags);
}
/*
* Create a storage vol using 'inputvol' as input
*/
int
virStorageBackendVolBuildFromLocal(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol,
unsigned int flags)
{
return storageBackendVolBuildLocal(conn, pool, vol, inputvol, flags);
}
/**
* Remove a volume - no support for BLOCK and NETWORK yet
*/
int
virStorageBackendVolDeleteLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
virStorageVolDefPtr vol,
unsigned int flags)
{
virCheckFlags(0, -1);
switch ((virStorageVolType) vol->type) {
case VIR_STORAGE_VOL_FILE:
case VIR_STORAGE_VOL_DIR:
if (virFileRemove(vol->target.path, vol->target.perms->uid,
vol->target.perms->gid) < 0) {
/* Silently ignore failures where the vol has already gone away */
if (errno != ENOENT) {
if (vol->type == VIR_STORAGE_VOL_FILE)
virReportSystemError(errno,
_("cannot unlink file '%s'"),
vol->target.path);
else
virReportSystemError(errno,
_("cannot remove directory '%s'"),
vol->target.path);
return -1;
}
}
break;
case VIR_STORAGE_VOL_PLOOP:
if (virFileDeleteTree(vol->target.path) < 0)
return -1;
break;
case VIR_STORAGE_VOL_BLOCK:
case VIR_STORAGE_VOL_NETWORK:
case VIR_STORAGE_VOL_NETDIR:
case VIR_STORAGE_VOL_LAST:
virReportError(VIR_ERR_NO_SUPPORT,
_("removing block or network volumes is not supported: %s"),
vol->target.path);
return -1;
}
return 0;
}
/* storageBackendLoadDefaultSecrets:
* @conn: Connection pointer to fetch secret
* @vol: volume being refreshed
*
* If the volume had a secret generated, we need to regenerate the
* encryption secret information
*
* Returns 0 if no secret or secret setup was successful,
* -1 on failures w/ error message set
*/
static int
storageBackendLoadDefaultSecrets(virConnectPtr conn,
virStorageVolDefPtr vol)
{
virSecretPtr sec;
virStorageEncryptionSecretPtr encsec = NULL;
if (!vol->target.encryption || vol->target.encryption->nsecrets != 0)
return 0;
/* The encryption secret for qcow2 and luks volumes use the path
* to the volume, so look for a secret with the path. If not found,
* then we cannot generate the secret after a refresh (or restart).
* This may be the case if someone didn't follow instructions and created
* a usage string that although matched with the secret usage string,
* didn't contain the path to the volume. We won't error in that case,
* but we also cannot find the secret. */
if (!(sec = virSecretLookupByUsage(conn, VIR_SECRET_USAGE_TYPE_VOLUME,
vol->target.path)))
return 0;
if (VIR_ALLOC_N(vol->target.encryption->secrets, 1) < 0 ||
VIR_ALLOC(encsec) < 0) {
VIR_FREE(vol->target.encryption->secrets);
virObjectUnref(sec);
return -1;
}
vol->target.encryption->nsecrets = 1;
vol->target.encryption->secrets[0] = encsec;
encsec->type = VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE;
encsec->seclookupdef.type = VIR_SECRET_LOOKUP_TYPE_UUID;
virSecretGetUUID(sec, encsec->seclookupdef.u.uuid);
virObjectUnref(sec);
return 0;
}
/**
* Update info about a volume's capacity/allocation
*/
int
virStorageBackendVolRefreshLocal(virConnectPtr conn,
virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
virStorageVolDefPtr vol)
{
int ret;
/* Refresh allocation / capacity / permissions info in case its changed */
if ((ret = virStorageBackendUpdateVolInfo(vol, false,
VIR_STORAGE_VOL_FS_OPEN_FLAGS,
0)) < 0)
return ret;
/* Load any secrets if possible */
return storageBackendLoadDefaultSecrets(conn, vol);
}
static int
storageBackendResizeQemuImg(const char *path,
unsigned long long capacity)
{
int ret = -1;
char *img_tool;
virCommandPtr cmd = NULL;
img_tool = virFindFileInPath("qemu-img");
if (!img_tool) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("unable to find qemu-img"));
return -1;
}
/* Round capacity as qemu-img resize errors out on sizes which are not
* a multiple of 512 */
capacity = VIR_ROUND_UP(capacity, 512);
cmd = virCommandNew(img_tool);
virCommandAddArgList(cmd, "resize", path, NULL);
virCommandAddArgFormat(cmd, "%llu", capacity);
ret = virCommandRun(cmd, NULL);
VIR_FREE(img_tool);
virCommandFree(cmd);
return ret;
}
/**
* Resize a volume
*/
int
virStorageBackendVolResizeLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
virStorageVolDefPtr vol,
unsigned long long capacity,
unsigned int flags)
{
virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE |
VIR_STORAGE_VOL_RESIZE_SHRINK, -1);
bool pre_allocate = flags & VIR_STORAGE_VOL_RESIZE_ALLOCATE;
if (vol->target.format == VIR_STORAGE_FILE_RAW) {
return virStorageFileResize(vol->target.path, capacity,
vol->target.allocation, pre_allocate);
} else if (vol->target.format == VIR_STORAGE_FILE_PLOOP) {
return storagePloopResize(vol, capacity);
} else {
if (pre_allocate) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("preallocate is only supported for raw "
"type volume"));
return -1;
}
return storageBackendResizeQemuImg(vol->target.path, capacity);
}
}
/* /*
* Check whether the ploop image has snapshots. * Check whether the ploop image has snapshots.
* return: -1 - failed to check * return: -1 - failed to check
@ -2015,7 +2348,7 @@ virStorageBackendStablePath(virStoragePoolObjPtr pool,
* 1 - at least one snapshot * 1 - at least one snapshot
*/ */
static int static int
virStorageBackendPloopHasSnapshots(char *path) storageBackendPloopHasSnapshots(char *path)
{ {
virCommandPtr cmd = NULL; virCommandPtr cmd = NULL;
char *output = NULL; char *output = NULL;
@ -2049,6 +2382,7 @@ virStorageBackendPloopHasSnapshots(char *path)
return ret; return ret;
} }
int int
virStorageBackendVolUploadLocal(virConnectPtr conn ATTRIBUTE_UNUSED, virStorageBackendVolUploadLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
@ -2070,7 +2404,7 @@ virStorageBackendVolUploadLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
* when volUpload is fully finished. */ * when volUpload is fully finished. */
if (vol->target.format == VIR_STORAGE_FILE_PLOOP) { if (vol->target.format == VIR_STORAGE_FILE_PLOOP) {
/* Fail if the volume contains snapshots or we failed to check it.*/ /* Fail if the volume contains snapshots or we failed to check it.*/
has_snap = virStorageBackendPloopHasSnapshots(vol->target.path); has_snap = storageBackendPloopHasSnapshots(vol->target.path);
if (has_snap < 0) { if (has_snap < 0) {
goto cleanup; goto cleanup;
} else if (!has_snap) { } else if (!has_snap) {
@ -2111,7 +2445,7 @@ virStorageBackendVolDownloadLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
virCheckFlags(0, -1); virCheckFlags(0, -1);
if (vol->target.format == VIR_STORAGE_FILE_PLOOP) { if (vol->target.format == VIR_STORAGE_FILE_PLOOP) {
has_snap = virStorageBackendPloopHasSnapshots(vol->target.path); has_snap = storageBackendPloopHasSnapshots(vol->target.path);
if (has_snap < 0) { if (has_snap < 0) {
goto cleanup; goto cleanup;
} else if (!has_snap) { } else if (!has_snap) {
@ -2149,7 +2483,7 @@ virStorageBackendVolDownloadLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
* appear as if it were zero-filled. * appear as if it were zero-filled.
*/ */
static int static int
virStorageBackendVolZeroSparseFileLocal(const char *path, storageBackendVolZeroSparseFileLocal(const char *path,
off_t size, off_t size,
int fd) int fd)
{ {
@ -2174,7 +2508,7 @@ virStorageBackendVolZeroSparseFileLocal(const char *path,
static int static int
virStorageBackendWipeLocal(const char *path, storageBackendWipeLocal(const char *path,
int fd, int fd,
unsigned long long wipe_len, unsigned long long wipe_len,
size_t writebuf_length) size_t writebuf_length)
@ -2232,7 +2566,7 @@ virStorageBackendWipeLocal(const char *path,
static int static int
virStorageBackendVolWipeLocalFile(const char *path, storageBackendVolWipeLocalFile(const char *path,
unsigned int algorithm, unsigned int algorithm,
unsigned long long allocation) unsigned long long allocation)
{ {
@ -2307,12 +2641,9 @@ virStorageBackendVolWipeLocalFile(const char *path,
ret = 0; ret = 0;
} else { } else {
if (S_ISREG(st.st_mode) && st.st_blocks < (st.st_size / DEV_BSIZE)) { if (S_ISREG(st.st_mode) && st.st_blocks < (st.st_size / DEV_BSIZE)) {
ret = virStorageBackendVolZeroSparseFileLocal(path, st.st_size, fd); ret = storageBackendVolZeroSparseFileLocal(path, st.st_size, fd);
} else { } else {
ret = virStorageBackendWipeLocal(path, ret = storageBackendWipeLocal(path, fd, allocation, st.st_blksize);
fd,
allocation,
st.st_blksize);
} }
if (ret < 0) if (ret < 0)
goto cleanup; goto cleanup;
@ -2326,7 +2657,7 @@ virStorageBackendVolWipeLocalFile(const char *path,
static int static int
virStorageBackendVolWipePloop(virStorageVolDefPtr vol, storageBackendVolWipePloop(virStorageVolDefPtr vol,
unsigned int algorithm) unsigned int algorithm)
{ {
virCommandPtr cmd = NULL; virCommandPtr cmd = NULL;
@ -2349,8 +2680,7 @@ virStorageBackendVolWipePloop(virStorageVolDefPtr vol,
if (virAsprintf(&disk_desc, "%s/DiskDescriptor.xml", vol->target.path) < 0) if (virAsprintf(&disk_desc, "%s/DiskDescriptor.xml", vol->target.path) < 0)
goto cleanup; goto cleanup;
if (virStorageBackendVolWipeLocalFile(target_path, if (storageBackendVolWipeLocalFile(target_path, algorithm,
algorithm,
vol->target.allocation) < 0) vol->target.allocation) < 0)
goto cleanup; goto cleanup;
@ -2397,10 +2727,9 @@ virStorageBackendVolWipeLocal(virConnectPtr conn ATTRIBUTE_UNUSED,
vol->target.path, algorithm); vol->target.path, algorithm);
if (vol->target.format == VIR_STORAGE_FILE_PLOOP) { if (vol->target.format == VIR_STORAGE_FILE_PLOOP) {
ret = virStorageBackendVolWipePloop(vol, algorithm); ret = storageBackendVolWipePloop(vol, algorithm);
} else { } else {
ret = virStorageBackendVolWipeLocalFile(vol->target.path, ret = storageBackendVolWipeLocalFile(vol->target.path, algorithm,
algorithm,
vol->target.allocation); vol->target.allocation);
} }

View File

@ -28,31 +28,40 @@
# include "storage_backend.h" # include "storage_backend.h"
/* File creation/cloning functions used for cloning between backends */ /* File creation/cloning functions used for cloning between backends */
int virStorageBackendCreateRaw(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol,
unsigned int flags);
int virStorageBackendCreateQemuImg(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol,
unsigned int flags);
int virStorageBackendCreatePloop(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol,
unsigned int flags);
int virStoragePloopResize(virStorageVolDefPtr vol,
unsigned long long capacity);
virStorageBackendBuildVolFrom virStorageBackendBuildVolFrom
virStorageBackendGetBuildVolFromFunction(virStorageVolDefPtr vol, virStorageBackendGetBuildVolFromFunction(virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol); virStorageVolDefPtr inputvol);
int virStorageBackendVolCreateLocal(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol);
int virStorageBackendVolBuildLocal(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol,
unsigned int flags);
int virStorageBackendVolBuildFromLocal(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol,
virStorageVolDefPtr inputvol,
unsigned int flags);
int virStorageBackendVolDeleteLocal(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol,
unsigned int flags);
int virStorageBackendVolRefreshLocal(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol);
int virStorageBackendVolResizeLocal(virConnectPtr conn,
virStoragePoolObjPtr pool,
virStorageVolDefPtr vol,
unsigned long long capacity,
unsigned int flags);
int virStorageBackendVolUploadLocal(virConnectPtr conn, int virStorageBackendVolUploadLocal(virConnectPtr conn,
virStoragePoolObjPtr pool, virStoragePoolObjPtr pool,
virStorageVolDefPtr vol, virStorageVolDefPtr vol,
@ -60,6 +69,7 @@ int virStorageBackendVolUploadLocal(virConnectPtr conn,
unsigned long long offset, unsigned long long offset,
unsigned long long len, unsigned long long len,
unsigned int flags); unsigned int flags);
int virStorageBackendVolDownloadLocal(virConnectPtr conn, int virStorageBackendVolDownloadLocal(virConnectPtr conn,
virStoragePoolObjPtr pool, virStoragePoolObjPtr pool,
virStorageVolDefPtr vol, virStorageVolDefPtr vol,