+static int qemu_rbd_encryption_format(rbd_image_t image,
+ RbdEncryptionCreateOptions *encrypt,
+ Error **errp)
+{
+ int r = 0;
+ g_autofree char *passphrase = NULL;
+ rbd_encryption_format_t format;
+ rbd_encryption_options_t opts;
+ rbd_encryption_luks1_format_options_t luks_opts;
+ rbd_encryption_luks2_format_options_t luks2_opts;
+ size_t opts_size;
+ uint64_t raw_size, effective_size;
+
+ r = rbd_get_size(image, &raw_size);
+ if (r < 0) {
+ error_setg_errno(errp, -r, "cannot get raw image size");
+ return r;
+ }
+
+ switch (encrypt->format) {
+ case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS: {
+ memset(&luks_opts, 0, sizeof(luks_opts));
+ format = RBD_ENCRYPTION_FORMAT_LUKS1;
+ opts = &luks_opts;
+ opts_size = sizeof(luks_opts);
+ r = qemu_rbd_convert_luks_create_options(
+ qapi_RbdEncryptionCreateOptionsLUKS_base(&encrypt->u.luks),
+ &luks_opts.alg, &passphrase, &luks_opts.passphrase_size,
+ errp);
+ if (r < 0) {
+ return r;
+ }
+ luks_opts.passphrase = passphrase;
+ break;
+ }
+ case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
+ memset(&luks2_opts, 0, sizeof(luks2_opts));
+ format = RBD_ENCRYPTION_FORMAT_LUKS2;
+ opts = &luks2_opts;
+ opts_size = sizeof(luks2_opts);
+ r = qemu_rbd_convert_luks_create_options(
+ qapi_RbdEncryptionCreateOptionsLUKS2_base(
+ &encrypt->u.luks2),
+ &luks2_opts.alg, &passphrase, &luks2_opts.passphrase_size,
+ errp);
+ if (r < 0) {
+ return r;
+ }
+ luks2_opts.passphrase = passphrase;
+ break;
+ }
+ default: {
+ r = -ENOTSUP;
+ error_setg_errno(
+ errp, -r, "unknown image encryption format: %u",
+ encrypt->format);
+ return r;
+ }
+ }
+
+ r = rbd_encryption_format(image, format, opts, opts_size);
+ if (r < 0) {
+ error_setg_errno(errp, -r, "encryption format fail");
+ return r;
+ }
+
+ r = rbd_get_size(image, &effective_size);
+ if (r < 0) {
+ error_setg_errno(errp, -r, "cannot get effective image size");
+ return r;
+ }
+
+ r = rbd_resize(image, raw_size + (raw_size - effective_size));
+ if (r < 0) {
+ error_setg_errno(errp, -r, "cannot resize image after format");
+ return r;
+ }
+
+ return 0;
+}
+
+static int qemu_rbd_encryption_load(rbd_image_t image,
+ RbdEncryptionOptions *encrypt,
+ Error **errp)
+{
+ int r = 0;
+ g_autofree char *passphrase = NULL;
+ rbd_encryption_luks1_format_options_t luks_opts;
+ rbd_encryption_luks2_format_options_t luks2_opts;
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
+ rbd_encryption_luks_format_options_t luks_any_opts;
+#endif
+ rbd_encryption_format_t format;
+ rbd_encryption_options_t opts;
+ size_t opts_size;
+
+ switch (encrypt->format) {
+ case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS: {
+ memset(&luks_opts, 0, sizeof(luks_opts));
+ format = RBD_ENCRYPTION_FORMAT_LUKS1;
+ opts = &luks_opts;
+ opts_size = sizeof(luks_opts);
+ r = qemu_rbd_convert_luks_options(
+ qapi_RbdEncryptionOptionsLUKS_base(&encrypt->u.luks),
+ &passphrase, &luks_opts.passphrase_size, errp);
+ if (r < 0) {
+ return r;
+ }
+ luks_opts.passphrase = passphrase;
+ break;
+ }
+ case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
+ memset(&luks2_opts, 0, sizeof(luks2_opts));
+ format = RBD_ENCRYPTION_FORMAT_LUKS2;
+ opts = &luks2_opts;
+ opts_size = sizeof(luks2_opts);
+ r = qemu_rbd_convert_luks_options(
+ qapi_RbdEncryptionOptionsLUKS2_base(&encrypt->u.luks2),
+ &passphrase, &luks2_opts.passphrase_size, errp);
+ if (r < 0) {
+ return r;
+ }
+ luks2_opts.passphrase = passphrase;
+ break;
+ }
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
+ case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS_ANY: {
+ memset(&luks_any_opts, 0, sizeof(luks_any_opts));
+ format = RBD_ENCRYPTION_FORMAT_LUKS;
+ opts = &luks_any_opts;
+ opts_size = sizeof(luks_any_opts);
+ r = qemu_rbd_convert_luks_options(
+ qapi_RbdEncryptionOptionsLUKSAny_base(&encrypt->u.luks_any),
+ &passphrase, &luks_any_opts.passphrase_size, errp);
+ if (r < 0) {
+ return r;
+ }
+ luks_any_opts.passphrase = passphrase;
+ break;
+ }
+#endif
+ default: {
+ r = -ENOTSUP;
+ error_setg_errno(
+ errp, -r, "unknown image encryption format: %u",
+ encrypt->format);
+ return r;
+ }
+ }
+
+ r = rbd_encryption_load(image, format, opts, opts_size);
+ if (r < 0) {
+ error_setg_errno(errp, -r, "encryption load fail");
+ return r;
+ }
+
+ return 0;
+}
+
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
+static int qemu_rbd_encryption_load2(rbd_image_t image,
+ RbdEncryptionOptions *encrypt,
+ Error **errp)
+{
+ int r = 0;
+ int encrypt_count = 1;
+ int i;
+ RbdEncryptionOptions *curr_encrypt;
+ rbd_encryption_spec_t *specs;
+ rbd_encryption_luks1_format_options_t *luks_opts;
+ rbd_encryption_luks2_format_options_t *luks2_opts;
+ rbd_encryption_luks_format_options_t *luks_any_opts;
+
+ /* count encryption options */
+ for (curr_encrypt = encrypt->parent; curr_encrypt;
+ curr_encrypt = curr_encrypt->parent) {
+ ++encrypt_count;
+ }
+
+ specs = g_new0(rbd_encryption_spec_t, encrypt_count);
+
+ curr_encrypt = encrypt;
+ for (i = 0; i < encrypt_count; ++i) {
+ switch (curr_encrypt->format) {
+ case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS: {
+ specs[i].format = RBD_ENCRYPTION_FORMAT_LUKS1;
+
+ luks_opts = g_new0(rbd_encryption_luks1_format_options_t, 1);
+ specs[i].opts = luks_opts;
+ specs[i].opts_size = sizeof(*luks_opts);
+
+ r = qemu_rbd_convert_luks_options(
+ qapi_RbdEncryptionOptionsLUKS_base(
+ &curr_encrypt->u.luks),
+ (char **)&luks_opts->passphrase,
+ &luks_opts->passphrase_size,
+ errp);
+ break;
+ }
+ case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
+ specs[i].format = RBD_ENCRYPTION_FORMAT_LUKS2;
+
+ luks2_opts = g_new0(rbd_encryption_luks2_format_options_t, 1);
+ specs[i].opts = luks2_opts;
+ specs[i].opts_size = sizeof(*luks2_opts);
+
+ r = qemu_rbd_convert_luks_options(
+ qapi_RbdEncryptionOptionsLUKS2_base(
+ &curr_encrypt->u.luks2),
+ (char **)&luks2_opts->passphrase,
+ &luks2_opts->passphrase_size,
+ errp);
+ break;
+ }
+ case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS_ANY: {
+ specs[i].format = RBD_ENCRYPTION_FORMAT_LUKS;
+
+ luks_any_opts = g_new0(rbd_encryption_luks_format_options_t, 1);
+ specs[i].opts = luks_any_opts;
+ specs[i].opts_size = sizeof(*luks_any_opts);
+
+ r = qemu_rbd_convert_luks_options(
+ qapi_RbdEncryptionOptionsLUKSAny_base(
+ &curr_encrypt->u.luks_any),
+ (char **)&luks_any_opts->passphrase,
+ &luks_any_opts->passphrase_size,
+ errp);
+ break;
+ }
+ default: {
+ r = -ENOTSUP;
+ error_setg_errno(
+ errp, -r, "unknown image encryption format: %u",
+ curr_encrypt->format);
+ }
+ }
+
+ if (r < 0) {
+ goto exit;
+ }
+
+ curr_encrypt = curr_encrypt->parent;
+ }
+
+ r = rbd_encryption_load2(image, specs, encrypt_count);
+ if (r < 0) {
+ error_setg_errno(errp, -r, "layered encryption load fail");
+ goto exit;
+ }
+
+exit:
+ for (i = 0; i < encrypt_count; ++i) {
+ if (!specs[i].opts) {
+ break;
+ }
+
+ switch (specs[i].format) {
+ case RBD_ENCRYPTION_FORMAT_LUKS1: {
+ luks_opts = specs[i].opts;
+ g_free((void *)luks_opts->passphrase);
+ break;
+ }
+ case RBD_ENCRYPTION_FORMAT_LUKS2: {
+ luks2_opts = specs[i].opts;
+ g_free((void *)luks2_opts->passphrase);
+ break;
+ }
+ case RBD_ENCRYPTION_FORMAT_LUKS: {
+ luks_any_opts = specs[i].opts;
+ g_free((void *)luks_any_opts->passphrase);
+ break;
+ }
+ }
+
+ g_free(specs[i].opts);
+ }
+ g_free(specs);
+ return r;
+}
+#endif
+#endif
+