From becb383a63ee3edd40493491a585630f364107c9 Mon Sep 17 00:00:00 2001 From: John Ferlan Date: Fri, 6 Oct 2017 12:04:19 -0400 Subject: [PATCH] storage: Properly resize a local volume using LUKS https://bugzilla.redhat.com/show_bug.cgi?id=1490279 Turns out the virStorageBackendVolResizeLocal did not differentiate whether the target volume was a LUKS volume or not and just blindly did the ftruncate() on the target volume. Follow the volume creation logic (in general) and create a qemu-img resize command to resize the target volume for LUKS ensuring that the --object secret is provided as well as the '--image-opts' used by the qemu-img resize logic to describe the path and secret ensuring that it's using the luks driver on the volume of course. --- src/storage/storage_util.c | 98 ++++++++++++++++++++++++++++++++++---- 1 file changed, 90 insertions(+), 8 deletions(-) diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c index 33f91f0b15..4165178b2f 100644 --- a/src/storage/storage_util.c +++ b/src/storage/storage_util.c @@ -1143,6 +1143,37 @@ storageBackendCreateQemuImgSecretObject(virCommandPtr cmd, } +/* Add a --image-opts to the qemu-img resize command line: + * --image-opts driver=luks,file.filename=$volpath,key-secret=$secretAlias + * + * NB: format=raw is assumed + */ +static int +storageBackendResizeQemuImgImageOpts(virCommandPtr cmd, + const char *path, + const char *secretAlias) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + char *commandStr = NULL; + + virBufferAsprintf(&buf, "driver=luks,key-secret=%s,file.filename=", + secretAlias); + virQEMUBuildBufferEscapeComma(&buf, path); + + if (virBufferCheckError(&buf) < 0) { + virBufferFreeAndReset(&buf); + return -1; + } + + commandStr = virBufferContentAndReset(&buf); + + virCommandAddArgList(cmd, "--image-opts", commandStr, NULL); + + VIR_FREE(commandStr); + return 0; +} + + /* Create a qemu-img virCommand from the supplied binary path, * volume definitions and imgformat */ @@ -2286,12 +2317,17 @@ virStorageBackendVolRefreshLocal(virConnectPtr conn, static int -storageBackendResizeQemuImg(virStorageVolDefPtr vol, +storageBackendResizeQemuImg(virConnectPtr conn, + virStoragePoolObjPtr pool, + virStorageVolDefPtr vol, unsigned long long capacity) { int ret = -1; - char *img_tool; + char *img_tool = NULL; virCommandPtr cmd = NULL; + const char *type; + char *secretPath = NULL; + char *secretAlias = NULL; img_tool = virFindFileInPath("qemu-img"); if (!img_tool) { @@ -2300,19 +2336,56 @@ storageBackendResizeQemuImg(virStorageVolDefPtr vol, return -1; } + if (vol->target.encryption) { + if (vol->target.format == VIR_STORAGE_FILE_RAW) + type = "luks"; + else + type = virStorageFileFormatTypeToString(vol->target.format); + + storageBackendLoadDefaultSecrets(conn, vol); + + if (storageBackendCreateQemuImgCheckEncryption(vol->target.format, + type, NULL, vol) < 0) + goto cleanup; + + if (!(secretPath = + storageBackendCreateQemuImgSecretPath(conn, pool, vol))) + goto cleanup; + + if (virAsprintf(&secretAlias, "%s_luks0", vol->name) < 0) + goto cleanup; + } + /* 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", vol->target.path, NULL); + if (!vol->target.encryption) { + virCommandAddArgList(cmd, "resize", vol->target.path, NULL); + } else { + virCommandAddArg(cmd, "resize"); + + if (storageBackendCreateQemuImgSecretObject(cmd, secretPath, + secretAlias) < 0) + goto cleanup; + + if (storageBackendResizeQemuImgImageOpts(cmd, vol->target.path, + secretAlias) < 0) + goto cleanup; + } virCommandAddArgFormat(cmd, "%llu", capacity); ret = virCommandRun(cmd, NULL); + cleanup: VIR_FREE(img_tool); + if (secretPath) { + unlink(secretPath); + VIR_FREE(secretPath); + } + VIR_FREE(secretAlias); virCommandFree(cmd); - return ret; } @@ -2321,8 +2394,8 @@ storageBackendResizeQemuImg(virStorageVolDefPtr vol, * Resize a volume */ int -virStorageBackendVolResizeLocal(virConnectPtr conn ATTRIBUTE_UNUSED, - virStoragePoolObjPtr pool ATTRIBUTE_UNUSED, +virStorageBackendVolResizeLocal(virConnectPtr conn, + virStoragePoolObjPtr pool, virStorageVolDefPtr vol, unsigned long long capacity, unsigned int flags) @@ -2332,8 +2405,17 @@ virStorageBackendVolResizeLocal(virConnectPtr conn ATTRIBUTE_UNUSED, virCheckFlags(VIR_STORAGE_VOL_RESIZE_ALLOCATE | VIR_STORAGE_VOL_RESIZE_SHRINK, -1); - if (vol->target.format == VIR_STORAGE_FILE_RAW) { + if (vol->target.format == VIR_STORAGE_FILE_RAW && !vol->target.encryption) { return virStorageFileResize(vol->target.path, capacity, pre_allocate); + } else if (vol->target.format == VIR_STORAGE_FILE_RAW && vol->target.encryption) { + if (pre_allocate) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("preallocate is only supported for raw " + "type volume")); + return -1; + } + + return storageBackendResizeQemuImg(conn, pool, vol, capacity); } else if (vol->target.format == VIR_STORAGE_FILE_PLOOP) { return storagePloopResize(vol, capacity); } else { @@ -2344,7 +2426,7 @@ virStorageBackendVolResizeLocal(virConnectPtr conn ATTRIBUTE_UNUSED, return -1; } - return storageBackendResizeQemuImg(vol, capacity); + return storageBackendResizeQemuImg(conn, pool, vol, capacity); } }