From 661298572a5499ccfafcd36d30d66d091a5be9b6 Mon Sep 17 00:00:00 2001
From: Jim Fehlig <jfehlig@suse.com>
Date: Fri, 23 Mar 2018 17:41:51 -0600
Subject: [PATCH] libxl: add support for BlockResize API

Add support in the libxl driver for the BlockResize API. Use libxl's
libxl_qemu_monitor_command API to issue the block_resize command to qemu.

Signed-off-by: Jim Fehlig <jfehlig@suse.com>

Note: In its current form, this patch is not upstream material IMO. It uses
the unsupported libxl_qemu_monitor_command() API. Before it can be considered
upstream, we need an upstream solution in qemu and Xen. Bruce will work on
the qemu part. Once done we can consider how to do the Xen part. And only
after we have a supported blockresize API in Xen (libxl) can we consider
reworking this patch and submitting it to upstream libvirt.

---
 src/libxl/libxl_driver.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 91 insertions(+)

Index: libvirt-6.0.0/src/libxl/libxl_driver.c
===================================================================
--- libvirt-6.0.0.orig/src/libxl/libxl_driver.c
+++ libvirt-6.0.0/src/libxl/libxl_driver.c
@@ -5342,6 +5342,96 @@ libxlDomainMemoryStats(virDomainPtr dom,
 
 #undef LIBXL_SET_MEMSTAT
 
+/**
+ * Resize a block device while a guest is running. Resize to a lower size
+ * is supported, but should be used with extreme caution.  Note that it
+ * only supports to resize image files, it can't resize block devices
+ * like LVM volumes.
+ */
+static int
+libxlDomainBlockResize(virDomainPtr dom,
+                       const char *path,
+                       unsigned long long size,
+                       unsigned int flags)
+{
+    libxlDriverPrivatePtr driver = dom->conn->privateData;
+    libxlDriverConfigPtr cfg;
+    virDomainObjPtr vm;
+    int ret = -1;
+    virDomainDiskDefPtr disk = NULL;
+    char *moncmd = NULL;
+    char *monreply = NULL;
+
+    virCheckFlags(VIR_DOMAIN_BLOCK_RESIZE_BYTES, -1);
+
+    if (path[0] == '\0') {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       "%s", _("empty path"));
+        return -1;
+    }
+
+    /* We prefer operating on bytes.  */
+    if ((flags & VIR_DOMAIN_BLOCK_RESIZE_BYTES) == 0) {
+        if (size > ULLONG_MAX / 1024) {
+            virReportError(VIR_ERR_OVERFLOW,
+                           _("size must be less than %llu"),
+                           ULLONG_MAX / 1024);
+            return -1;
+        }
+        size *= 1024;
+    }
+
+    cfg = libxlDriverConfigGet(driver);
+    if (!(vm = libxlDomObjFromDomain(dom)))
+        goto cleanup;
+
+    if (virDomainBlockResizeEnsureACL(dom->conn, vm->def) < 0)
+        goto cleanup;
+
+    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
+        goto cleanup;
+
+    if (!virDomainObjIsActive(vm)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       "%s", _("domain is not running"));
+        goto endjob;
+    }
+
+    if (!(disk = virDomainDiskByName(vm->def, path, false))) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("invalid path: %s"), path);
+        goto endjob;
+    }
+
+    /* qcow2 and qed must be sized on 512 byte blocks/sectors,
+     * so adjust size if necessary to round up.
+     */
+    if (disk->src->format == VIR_STORAGE_FILE_QCOW2 ||
+        disk->src->format == VIR_STORAGE_FILE_QED)
+        size = VIR_ROUND_UP(size, 512);
+
+    moncmd = g_strdup_printf("block_resize %s %lluB", disk->dst, size);
+
+    if (libxl_qemu_monitor_command(cfg->ctx, vm->def->id, moncmd, &monreply) != 0) {
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       _("block_resize command failed for device '%s' on domain '%d'"),
+                       disk->dst, vm->def->id);
+        goto endjob;
+    }
+
+    ret = 0;
+
+ endjob:
+    libxlDomainObjEndJob(driver, vm);
+
+ cleanup:
+    VIR_FREE(moncmd);
+    VIR_FREE(monreply);
+    virDomainObjEndAPI(&vm);
+    virObjectUnref(cfg);
+    return ret;
+}
+
 static int
 libxlDomainGetJobInfo(virDomainPtr dom,
                       virDomainJobInfoPtr info)
@@ -6760,6 +6850,7 @@ static virHypervisorDriver libxlHypervis
 #endif
     .nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */
     .nodeGetCellsFreeMemory = libxlNodeGetCellsFreeMemory, /* 1.1.1 */
+    .domainBlockResize = libxlDomainBlockResize, /* 4.2.0 */
     .domainGetJobInfo = libxlDomainGetJobInfo, /* 1.3.1 */
     .domainGetJobStats = libxlDomainGetJobStats, /* 1.3.1 */
     .domainMemoryStats = libxlDomainMemoryStats, /* 1.3.0 */
