[PATCH v2 4/8] migration/migration-pin: Implement qemuDomainPinMigrationThread

Jiang Jiacheng jiangjiacheng at huawei.com
Tue Mar 7 14:52:16 UTC 2023


Add cgroup for migation thread and implement
qemuDomainPinMigrationThread to pin migraiton thread to
given cpumap.

Signed-off-by: zhengchuan<zhengchuan at huawei.com>
Signed-off-by: Jiang Jiacheng <jiangjiacheng at huawei.com>
---
 src/conf/domain_conf.c   |  9 ++++++
 src/conf/domain_conf.h   | 10 +++++++
 src/conf/virconftypes.h  |  2 ++
 src/libvirt_private.syms |  1 +
 src/qemu/qemu_domain.c   |  1 +
 src/qemu/qemu_domain.h   |  1 +
 src/qemu/qemu_driver.c   | 56 ++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_process.c  | 61 ++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_process.h  | 10 +++++++
 src/util/vircgroup.c     |  3 ++
 src/util/vircgroup.h     |  1 +
 11 files changed, 155 insertions(+)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index f7f9ec3c0a..68200dbbab 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -30883,3 +30883,12 @@ virDomainWatchdogDefFind(const virDomainDef *def,
 
     return -1;
 }
+
+void
+virDomainMigrationIDDefFree(virDomainMigrationIDDef *def)
+{
+    if (!def)
+        return;
+    virBitmapFree(def->cpumask);
+    VIR_FREE(def);
+}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 21ea4a48b3..fff846f26f 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -4469,3 +4469,13 @@ virDomainObjGetMessages(virDomainObj *vm,
 
 bool
 virDomainDefHasSpiceGraphics(const virDomainDef *def);
+
+struct _virDomainMigrationIDDef {
+    bool autofill;
+    int thread_id;
+    virBitmap *cpumask;
+    virDomainThreadSchedParam sched;
+};
+
+void
+virDomainMigrationIDDefFree(virDomainMigrationIDDef *def);
diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h
index e07f967814..84a28a08b8 100644
--- a/src/conf/virconftypes.h
+++ b/src/conf/virconftypes.h
@@ -261,3 +261,5 @@ typedef struct _virDomainXMLOption virDomainXMLOption;
 typedef struct _virDomainXMLPrivateDataCallbacks virDomainXMLPrivateDataCallbacks;
 
 typedef struct _virDomainXenbusControllerOpts virDomainXenbusControllerOpts;
+
+typedef struct _virDomainMigrationIDDef virDomainMigrationIDDef;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d5b1b9cb72..b5d9aa62ae 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -525,6 +525,7 @@ virDomainMemoryModelTypeToString;
 virDomainMemoryRemove;
 virDomainMemorySourceTypeFromString;
 virDomainMemorySourceTypeToString;
+virDomainMigrationIDDefFree;
 virDomainMouseModeTypeFromString;
 virDomainMouseModeTypeToString;
 virDomainNetAllocateActualDevice;
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index ba8d1055ae..3d497dd5d0 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -1853,6 +1853,7 @@ qemuDomainObjPrivateDataClear(qemuDomainObjPrivate *priv)
     /* remove automatic pinning data */
     g_clear_pointer(&priv->autoNodeset, virBitmapFree);
     g_clear_pointer(&priv->autoCpuset, virBitmapFree);
+    g_clear_pointer(&priv->pcpumap, virBitmapFree);
     g_clear_pointer(&priv->pciaddrs, virDomainPCIAddressSetFree);
     g_clear_pointer(&priv->usbaddrs, virDomainUSBAddressSetFree);
     g_clear_pointer(&priv->origCPU, virCPUDefFree);
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 42115a20ef..af986b5423 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -171,6 +171,7 @@ struct _qemuDomainObjPrivate {
     /* Bitmaps below hold data from the auto NUMA feature */
     virBitmap *autoNodeset;
     virBitmap *autoCpuset;
+    virBitmap *pcpumap;
 
     bool signalIOError; /* true if the domain condition should be signalled on
                            I/O error */
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index c546e35953..2b9a952c85 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -20581,6 +20581,61 @@ qemuDomainFDAssociate(virDomainPtr domain,
     return ret;
 }
 
+static int
+qemuDomainPinMigrationThread(virDomainPtr dom,
+                             unsigned char *cpumap,
+                             int maplen)
+{
+    int ret = -1;
+    virQEMUDriver *driver = dom->conn->privateData;
+    g_autoptr(virQEMUDriverConfig) cfg = NULL;
+    virDomainObj *vm = NULL;
+    g_autoptr(virBitmap) pcpumap = NULL;
+    qemuDomainObjPrivate *priv = NULL;
+    qemuDomainMigThreadInfo **migthreads = NULL;
+    size_t i;
+
+    cfg = virQEMUDriverGetConfig(driver);
+
+    if (!(vm = qemuDomainObjFromDomain(dom)))
+        goto cleanup;
+
+    priv = vm->privateData;
+
+    if (virDomainPinMigrationThreadEnsureACL(dom->conn, vm->def) < 0)
+        goto cleanup;
+
+    if (virDomainObjBeginJob(vm, VIR_JOB_QUERY) < 0)
+        goto cleanup;
+
+    if (!(pcpumap = virBitmapNewData(cpumap, maplen)))
+        goto endjob;
+
+    if (virBitmapIsAllClear(pcpumap)) {
+        virReportError(VIR_ERR_INVALID_ARG, "%s",
+                       _("Empty migration thread cpumap list for pinning"));
+        goto endjob;
+    }
+
+    virBitmapFree(priv->pcpumap);
+    priv->pcpumap = virBitmapNewCopy(pcpumap);
+    migthreads = priv->migThreadsInfo;
+
+    if (migthreads && pcpumap) {
+        for (i = 0; i < priv->migThreadCount; i++) {
+            qemuProcessSetMigThreadAffinity(priv, vm, migthreads[i]->thread_id, pcpumap);
+        }
+    }
+
+    ret = 0;
+
+ endjob:
+    virDomainObjEndJob(vm);
+
+ cleanup:
+    virDomainObjEndAPI(&vm);
+    return ret;
+}
 
 static virHypervisorDriver qemuHypervisorDriver = {
     .name = QEMU_DRIVER_NAME,
@@ -20831,6 +20886,7 @@ static virHypervisorDriver qemuHypervisorDriver = {
     .domainStartDirtyRateCalc = qemuDomainStartDirtyRateCalc, /* 7.2.0 */
     .domainSetLaunchSecurityState = qemuDomainSetLaunchSecurityState, /* 8.0.0 */
     .domainFDAssociate = qemuDomainFDAssociate, /* 9.0.0 */
+    .domainPinMigrationThread = qemuDomainPinMigrationThread, /* 9.1.0 */
 };
 
 
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 9a612ca443..946aeb81b1 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -9547,3 +9547,64 @@ qemuProcessQMPStart(qemuProcessQMP *proc)
 
     return 0;
 }
+
+int
+qemuProcessSetupMigration(virDomainObj *vm,
+                          virDomainMigrationIDDef *migration)
+{
+    return qemuProcessSetupPid(vm, migration->thread_id,
+                               VIR_CGROUP_THREAD_MIGRATION_THREAD,
+                               0,
+                               vm->def->cputune.emulatorpin,
+                               vm->def->cputune.emulator_period,
+                               vm->def->cputune.emulator_quota,
+                               &migration->sched);
+}
+
+/*
+ * In order to set migration thread affinity when vm is migrating,
+ * we should create the cgroup for migration thread.
+ */
+void
+qemuProcessSetMigThreadAffinity(qemuDomainObjPrivate *priv,
+                                virDomainObj *vm,
+                                int mpid,
+                                virBitmap *pcpumap)
+{
+    virDomainMigrationIDDef *migration = NULL;
+    int migration_id = 0;
+    virCgroup *cgroup_migthread = NULL;
+
+    if (!pcpumap)
+        return;
+
+    migration = g_new0(virDomainMigrationIDDef, 1);
+    migration->thread_id = mpid;
+    if (qemuProcessSetupMigration(vm, migration) < 0) {
+        VIR_ERROR(_("fail to setup migration cgroup"));
+        goto cleanup;
+    }
+
+    if (virCgroupHasController(priv->cgroup,
+                               VIR_CGROUP_CONTROLLER_CPUSET)) {
+        if (virCgroupNewThread(priv->cgroup, VIR_CGROUP_THREAD_MIGRATION_THREAD,
+                               migration_id, false, &cgroup_migthread) < 0)
+            goto cleanup;
+
+        if (virDomainCgroupSetupCpusetCpus(cgroup_migthread, pcpumap) < 0) {
+            virReportError(VIR_ERR_OPERATION_INVALID,
+                           _("failed to set cpuset.cpus in cgroup"
+                             " for migration%d thread"), migration_id);
+            goto cleanup;
+        }
+    }
+
+    if (virProcessSetAffinity(mpid, pcpumap, false) < 0)
+        VIR_WARN("failed to set affinity in migration");
+
+ cleanup:
+    if (cgroup_migthread)
+        virCgroupFree(cgroup_migthread);
+    virDomainMigrationIDDefFree(migration);
+    return;
+}
diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h
index b171f0464c..2af1e2ee87 100644
--- a/src/qemu/qemu_process.h
+++ b/src/qemu/qemu_process.h
@@ -235,3 +235,13 @@ bool qemuProcessRebootAllowed(const virDomainDef *def);
 
 void qemuProcessCleanupMigrationJob(virQEMUDriver *driver,
                                     virDomainObj *vm);
+
+int
+qemuProcessSetupMigration(virDomainObj *vm,
+                          virDomainMigrationIDDef *migration);
+
+void
+qemuProcessSetMigThreadAffinity(qemuDomainObjPrivate *priv,
+                                virDomainObj *vm,
+                                int mpid,
+                                virBitmap *pcpumap);
diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c
index 73675b4478..d4307c0d72 100644
--- a/src/util/vircgroup.c
+++ b/src/util/vircgroup.c
@@ -1123,6 +1123,9 @@ virCgroupNewThread(virCgroup *domain,
     case VIR_CGROUP_THREAD_IOTHREAD:
         name = g_strdup_printf("iothread%d", id);
         break;
+    case VIR_CGROUP_THREAD_MIGRATION_THREAD:
+        name = g_strdup_printf("migthread%d", id);
+        break;
     case VIR_CGROUP_THREAD_LAST:
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("unexpected name value %d"), nameval);
diff --git a/src/util/vircgroup.h b/src/util/vircgroup.h
index adf3850b22..c5f6ddd7a6 100644
--- a/src/util/vircgroup.h
+++ b/src/util/vircgroup.h
@@ -53,6 +53,7 @@ typedef enum {
     VIR_CGROUP_THREAD_VCPU = 0,
     VIR_CGROUP_THREAD_EMULATOR,
     VIR_CGROUP_THREAD_IOTHREAD,
+    VIR_CGROUP_THREAD_MIGRATION_THREAD,
 
     VIR_CGROUP_THREAD_LAST
 } virCgroupThreadName;
-- 
2.33.0



More information about the libvir-list mailing list