]> xenbits.xensource.com Git - libvirt.git/commitdiff
move files: hypervisor/domain_job -> conf/virdomainjob
authorKristina Hanicova <khanicov@redhat.com>
Mon, 5 Sep 2022 13:57:01 +0000 (15:57 +0200)
committerJán Tomko <jtomko@redhat.com>
Wed, 7 Sep 2022 10:06:17 +0000 (12:06 +0200)
The following patches move job object as a member into the domain
object.  Because of this, domain_conf (where the domain object is
defined) needs to import the file with the job object.

It makes sense to move jobs to the same level as the domain_conf:
into src/conf/

Signed-off-by: Kristina Hanicova <khanicov@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
Signed-off-by: Ján Tomko <jtomko@redhat.com>
14 files changed:
po/POTFILES
src/ch/ch_domain.h
src/conf/meson.build
src/conf/virdomainjob.c [new file with mode: 0644]
src/conf/virdomainjob.h [new file with mode: 0644]
src/hypervisor/domain_job.c [deleted file]
src/hypervisor/domain_job.h [deleted file]
src/hypervisor/meson.build
src/libvirt_private.syms
src/libxl/libxl_domain.c
src/libxl/libxl_domain.h
src/lxc/lxc_domain.c
src/lxc/lxc_domain.h
src/qemu/qemu_domainjob.h

index b9577e840de478194c0aa580bd2a3197dc0db34c..169e2a41dc14eac661a3f8e90370e019c5c4c67c 100644 (file)
@@ -53,6 +53,7 @@ src/conf/storage_conf.c
 src/conf/storage_encryption_conf.c
 src/conf/storage_source_conf.c
 src/conf/virchrdev.c
+src/conf/virdomainjob.c
 src/conf/virdomainmomentobjlist.c
 src/conf/virdomainobjlist.c
 src/conf/virnetworkobj.c
@@ -90,7 +91,6 @@ src/hyperv/hyperv_util.c
 src/hyperv/hyperv_wmi.c
 src/hypervisor/domain_cgroup.c
 src/hypervisor/domain_driver.c
-src/hypervisor/domain_job.c
 src/hypervisor/virclosecallbacks.c
 src/hypervisor/virhostdev.c
 src/interface/interface_backend_netcf.c
index b3bebd6b9a9e4b7948cb8950934fb1f0456793fa..27efe2feed55af0fc2f341d2b5f441724e3faf93 100644 (file)
@@ -24,7 +24,7 @@
 #include "ch_monitor.h"
 #include "virchrdev.h"
 #include "vircgroup.h"
-#include "domain_job.h"
+#include "virdomainjob.h"
 
 /* Give up waiting for mutex after 30 seconds */
 #define CH_JOB_WAIT_TIME (1000ull * 30)
index 5ef494c3babc9ac558676d81a1b7c680ba4f7599..5116c23fe396fb320ae75a262c61244ad337d5da 100644 (file)
@@ -20,6 +20,7 @@ domain_conf_sources = [
   'numa_conf.c',
   'snapshot_conf.c',
   'virdomaincheckpointobjlist.c',
+  'virdomainjob.c',
   'virdomainmomentobjlist.c',
   'virdomainobjlist.c',
   'virdomainsnapshotobjlist.c',
diff --git a/src/conf/virdomainjob.c b/src/conf/virdomainjob.c
new file mode 100644 (file)
index 0000000..0515e1d
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+ * virdomainjob.c: job functions shared between hypervisor drivers
+ *
+ * Copyright (C) 2022 Red Hat, Inc.
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include <config.h>
+#include <string.h>
+
+#include "virdomainjob.h"
+#include "viralloc.h"
+#include "virthreadjob.h"
+#include "virlog.h"
+#include "virtime.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+VIR_LOG_INIT("conf.virdomainjob");
+
+
+VIR_ENUM_IMPL(virDomainJob,
+              VIR_JOB_LAST,
+              "none",
+              "query",
+              "destroy",
+              "suspend",
+              "modify",
+              "abort",
+              "migration operation",
+              "modify migration safe",
+              "none",   /* async job is never stored in job.active */
+              "async nested",
+);
+
+VIR_ENUM_IMPL(virDomainAgentJob,
+              VIR_AGENT_JOB_LAST,
+              "none",
+              "query",
+              "modify",
+);
+
+VIR_ENUM_IMPL(virDomainAsyncJob,
+              VIR_ASYNC_JOB_LAST,
+              "none",
+              "migration out",
+              "migration in",
+              "save",
+              "dump",
+              "snapshot",
+              "start",
+              "backup",
+);
+
+virDomainJobData *
+virDomainJobDataInit(virDomainJobDataPrivateDataCallbacks *cb)
+{
+    virDomainJobData *ret = g_new0(virDomainJobData, 1);
+
+    ret->privateDataCb = cb;
+
+    if (ret->privateDataCb)
+        ret->privateData = ret->privateDataCb->allocPrivateData();
+
+    return ret;
+}
+
+virDomainJobData *
+virDomainJobDataCopy(virDomainJobData *data)
+{
+    virDomainJobData *ret = g_new0(virDomainJobData, 1);
+
+    memcpy(ret, data, sizeof(*data));
+
+    if (ret->privateDataCb)
+        ret->privateData = data->privateDataCb->copyPrivateData(data->privateData);
+
+    ret->errmsg = g_strdup(data->errmsg);
+
+    return ret;
+}
+
+void
+virDomainJobDataFree(virDomainJobData *data)
+{
+    if (!data)
+        return;
+
+    if (data->privateDataCb)
+        data->privateDataCb->freePrivateData(data->privateData);
+
+    g_free(data->errmsg);
+    g_free(data);
+}
+
+virDomainJobType
+virDomainJobStatusToType(virDomainJobStatus status)
+{
+    switch (status) {
+    case VIR_DOMAIN_JOB_STATUS_NONE:
+        break;
+
+    case VIR_DOMAIN_JOB_STATUS_ACTIVE:
+    case VIR_DOMAIN_JOB_STATUS_MIGRATING:
+    case VIR_DOMAIN_JOB_STATUS_HYPERVISOR_COMPLETED:
+    case VIR_DOMAIN_JOB_STATUS_POSTCOPY:
+    case VIR_DOMAIN_JOB_STATUS_POSTCOPY_PAUSED:
+    case VIR_DOMAIN_JOB_STATUS_PAUSED:
+        return VIR_DOMAIN_JOB_UNBOUNDED;
+
+    case VIR_DOMAIN_JOB_STATUS_COMPLETED:
+        return VIR_DOMAIN_JOB_COMPLETED;
+
+    case VIR_DOMAIN_JOB_STATUS_FAILED:
+        return VIR_DOMAIN_JOB_FAILED;
+
+    case VIR_DOMAIN_JOB_STATUS_CANCELED:
+        return VIR_DOMAIN_JOB_CANCELLED;
+    }
+
+    return VIR_DOMAIN_JOB_NONE;
+}
+
+int
+virDomainObjInitJob(virDomainJobObj *job,
+                    virDomainObjPrivateJobCallbacks *cb,
+                    virDomainJobDataPrivateDataCallbacks *jobDataPrivateCb)
+{
+    memset(job, 0, sizeof(*job));
+    job->cb = cb;
+    job->jobDataPrivateCb = jobDataPrivateCb;
+
+    if (virCondInit(&job->cond) < 0)
+        return -1;
+
+    if (virCondInit(&job->asyncCond) < 0) {
+        virCondDestroy(&job->cond);
+        return -1;
+    }
+
+    if (job->cb &&
+        !(job->privateData = job->cb->allocJobPrivate())) {
+        virCondDestroy(&job->cond);
+        virCondDestroy(&job->asyncCond);
+        return -1;
+    }
+
+    return 0;
+}
+
+void
+virDomainObjResetJob(virDomainJobObj *job)
+{
+    job->active = VIR_JOB_NONE;
+    job->owner = 0;
+    g_clear_pointer(&job->ownerAPI, g_free);
+    job->started = 0;
+}
+
+void
+virDomainObjResetAgentJob(virDomainJobObj *job)
+{
+    job->agentActive = VIR_AGENT_JOB_NONE;
+    job->agentOwner = 0;
+    g_clear_pointer(&job->agentOwnerAPI, g_free);
+    job->agentStarted = 0;
+}
+
+void
+virDomainObjResetAsyncJob(virDomainJobObj *job)
+{
+    job->asyncJob = VIR_ASYNC_JOB_NONE;
+    job->asyncOwner = 0;
+    g_clear_pointer(&job->asyncOwnerAPI, g_free);
+    job->asyncStarted = 0;
+    job->phase = 0;
+    job->mask = VIR_JOB_DEFAULT_MASK;
+    job->abortJob = false;
+    VIR_FREE(job->error);
+    g_clear_pointer(&job->current, virDomainJobDataFree);
+    job->apiFlags = 0;
+
+    if (job->cb)
+        job->cb->resetJobPrivate(job->privateData);
+}
+
+/**
+ * virDomainObjPreserveJob
+ * @param currJob structure is a job that needs to be preserved
+ * @param job structure where to store job details from @currJob
+ *
+ * Saves the current job details from @currJob to @job and resets the job in @currJob.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+int
+virDomainObjPreserveJob(virDomainJobObj *currJob,
+                        virDomainJobObj *job)
+{
+    memset(job, 0, sizeof(*job));
+    job->active = currJob->active;
+    job->owner = currJob->owner;
+    job->asyncJob = currJob->asyncJob;
+    job->asyncOwner = currJob->asyncOwner;
+    job->phase = currJob->phase;
+    job->privateData = g_steal_pointer(&currJob->privateData);
+    job->apiFlags = currJob->apiFlags;
+
+    if (currJob->cb &&
+        !(currJob->privateData = currJob->cb->allocJobPrivate()))
+        return -1;
+    job->cb = currJob->cb;
+
+    virDomainObjResetJob(currJob);
+    virDomainObjResetAsyncJob(currJob);
+    return 0;
+}
+
+void
+virDomainObjClearJob(virDomainJobObj *job)
+{
+    virDomainObjResetJob(job);
+    virDomainObjResetAsyncJob(job);
+    g_clear_pointer(&job->current, virDomainJobDataFree);
+    g_clear_pointer(&job->completed, virDomainJobDataFree);
+    virCondDestroy(&job->cond);
+    virCondDestroy(&job->asyncCond);
+
+    if (job->cb)
+        g_clear_pointer(&job->privateData, job->cb->freeJobPrivate);
+}
+
+bool
+virDomainTrackJob(virDomainJob job)
+{
+    return (VIR_DOMAIN_TRACK_JOBS & JOB_MASK(job)) != 0;
+}
+
+bool
+virDomainNestedJobAllowed(virDomainJobObj *jobs, virDomainJob newJob)
+{
+    return !jobs->asyncJob ||
+           newJob == VIR_JOB_NONE ||
+           (jobs->mask & JOB_MASK(newJob));
+}
+
+bool
+virDomainObjCanSetJob(virDomainJobObj *job,
+                      virDomainJob newJob,
+                      virDomainAgentJob newAgentJob)
+{
+    return ((newJob == VIR_JOB_NONE ||
+             job->active == VIR_JOB_NONE) &&
+            (newAgentJob == VIR_AGENT_JOB_NONE ||
+             job->agentActive == VIR_AGENT_JOB_NONE));
+}
+
+/* Give up waiting for mutex after 30 seconds */
+#define VIR_JOB_WAIT_TIME (1000ull * 30)
+
+/**
+ * virDomainObjBeginJobInternal:
+ * @obj: virDomainObj = domain object
+ * @jobObj: virDomainJobObj = domain job object
+ * @job: virDomainJob to start
+ * @agentJob: virDomainAgentJob to start
+ * @asyncJob: virDomainAsyncJob to start
+ * @nowait: don't wait trying to acquire @job
+ *
+ * Acquires job for a domain object which must be locked before
+ * calling. If there's already a job running waits up to
+ * VIR_JOB_WAIT_TIME after which the functions fails reporting
+ * an error unless @nowait is set.
+ *
+ * If @nowait is true this function tries to acquire job and if
+ * it fails, then it returns immediately without waiting. No
+ * error is reported in this case.
+ *
+ * Returns: 0 on success,
+ *         -2 if unable to start job because of timeout or
+ *            maxQueuedJobs limit,
+ *         -1 otherwise.
+ */
+int
+virDomainObjBeginJobInternal(virDomainObj *obj,
+                             virDomainJobObj *jobObj,
+                             virDomainJob job,
+                             virDomainAgentJob agentJob,
+                             virDomainAsyncJob asyncJob,
+                             bool nowait)
+{
+    unsigned long long now = 0;
+    unsigned long long then = 0;
+    bool nested = job == VIR_JOB_ASYNC_NESTED;
+    const char *blocker = NULL;
+    const char *agentBlocker = NULL;
+    int ret = -1;
+    unsigned long long duration = 0;
+    unsigned long long agentDuration = 0;
+    unsigned long long asyncDuration = 0;
+    const char *currentAPI = virThreadJobGet();
+
+    VIR_DEBUG("Starting job: API=%s job=%s agentJob=%s asyncJob=%s "
+              "(vm=%p name=%s, current job=%s agentJob=%s async=%s)",
+              NULLSTR(currentAPI),
+              virDomainJobTypeToString(job),
+              virDomainAgentJobTypeToString(agentJob),
+              virDomainAsyncJobTypeToString(asyncJob),
+              obj, obj->def->name,
+              virDomainJobTypeToString(jobObj->active),
+              virDomainAgentJobTypeToString(jobObj->agentActive),
+              virDomainAsyncJobTypeToString(jobObj->asyncJob));
+
+    if (virTimeMillisNow(&now) < 0)
+        return -1;
+
+    jobObj->jobsQueued++;
+    then = now + VIR_JOB_WAIT_TIME;
+
+ retry:
+    if (job != VIR_JOB_ASYNC &&
+        job != VIR_JOB_DESTROY &&
+        jobObj->maxQueuedJobs &&
+        jobObj->jobsQueued > jobObj->maxQueuedJobs) {
+        goto error;
+    }
+
+    while (!nested && !virDomainNestedJobAllowed(jobObj, job)) {
+        if (nowait)
+            goto cleanup;
+
+        VIR_DEBUG("Waiting for async job (vm=%p name=%s)", obj, obj->def->name);
+        if (virCondWaitUntil(&jobObj->asyncCond, &obj->parent.lock, then) < 0)
+            goto error;
+    }
+
+    while (!virDomainObjCanSetJob(jobObj, job, agentJob)) {
+        if (nowait)
+            goto cleanup;
+
+        VIR_DEBUG("Waiting for job (vm=%p name=%s)", obj, obj->def->name);
+        if (virCondWaitUntil(&jobObj->cond, &obj->parent.lock, then) < 0)
+            goto error;
+    }
+
+    /* No job is active but a new async job could have been started while obj
+     * was unlocked, so we need to recheck it. */
+    if (!nested && !virDomainNestedJobAllowed(jobObj, job))
+        goto retry;
+
+    if (obj->removing) {
+        char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+        virUUIDFormat(obj->def->uuid, uuidstr);
+        virReportError(VIR_ERR_NO_DOMAIN,
+                       _("no domain with matching uuid '%s' (%s)"),
+                       uuidstr, obj->def->name);
+        goto cleanup;
+    }
+
+    ignore_value(virTimeMillisNow(&now));
+
+    if (job) {
+        virDomainObjResetJob(jobObj);
+
+        if (job != VIR_JOB_ASYNC) {
+            VIR_DEBUG("Started job: %s (async=%s vm=%p name=%s)",
+                      virDomainJobTypeToString(job),
+                      virDomainAsyncJobTypeToString(jobObj->asyncJob),
+                      obj, obj->def->name);
+            jobObj->active = job;
+            jobObj->owner = virThreadSelfID();
+            jobObj->ownerAPI = g_strdup(virThreadJobGet());
+            jobObj->started = now;
+        } else {
+            VIR_DEBUG("Started async job: %s (vm=%p name=%s)",
+                      virDomainAsyncJobTypeToString(asyncJob),
+                      obj, obj->def->name);
+            virDomainObjResetAsyncJob(jobObj);
+            jobObj->current = virDomainJobDataInit(jobObj->jobDataPrivateCb);
+            jobObj->current->status = VIR_DOMAIN_JOB_STATUS_ACTIVE;
+            jobObj->asyncJob = asyncJob;
+            jobObj->asyncOwner = virThreadSelfID();
+            jobObj->asyncOwnerAPI = g_strdup(virThreadJobGet());
+            jobObj->asyncStarted = now;
+            jobObj->current->started = now;
+        }
+    }
+
+    if (agentJob) {
+        virDomainObjResetAgentJob(jobObj);
+        VIR_DEBUG("Started agent job: %s (vm=%p name=%s job=%s async=%s)",
+                  virDomainAgentJobTypeToString(agentJob),
+                  obj, obj->def->name,
+                  virDomainJobTypeToString(jobObj->active),
+                  virDomainAsyncJobTypeToString(jobObj->asyncJob));
+        jobObj->agentActive = agentJob;
+        jobObj->agentOwner = virThreadSelfID();
+        jobObj->agentOwnerAPI = g_strdup(virThreadJobGet());
+        jobObj->agentStarted = now;
+    }
+
+    if (virDomainTrackJob(job) && jobObj->cb &&
+        jobObj->cb->saveStatusPrivate)
+        jobObj->cb->saveStatusPrivate(obj);
+
+    return 0;
+
+ error:
+    ignore_value(virTimeMillisNow(&now));
+    if (jobObj->active && jobObj->started)
+        duration = now - jobObj->started;
+    if (jobObj->agentActive && jobObj->agentStarted)
+        agentDuration = now - jobObj->agentStarted;
+    if (jobObj->asyncJob && jobObj->asyncStarted)
+        asyncDuration = now - jobObj->asyncStarted;
+
+    VIR_WARN("Cannot start job (%s, %s, %s) in API %s for domain %s; "
+             "current job is (%s, %s, %s) "
+             "owned by (%llu %s, %llu %s, %llu %s (flags=0x%lx)) "
+             "for (%llus, %llus, %llus)",
+             virDomainJobTypeToString(job),
+             virDomainAgentJobTypeToString(agentJob),
+             virDomainAsyncJobTypeToString(asyncJob),
+             NULLSTR(currentAPI),
+             obj->def->name,
+             virDomainJobTypeToString(jobObj->active),
+             virDomainAgentJobTypeToString(jobObj->agentActive),
+             virDomainAsyncJobTypeToString(jobObj->asyncJob),
+             jobObj->owner, NULLSTR(jobObj->ownerAPI),
+             jobObj->agentOwner, NULLSTR(jobObj->agentOwnerAPI),
+             jobObj->asyncOwner, NULLSTR(jobObj->asyncOwnerAPI),
+             jobObj->apiFlags,
+             duration / 1000, agentDuration / 1000, asyncDuration / 1000);
+
+    if (job) {
+        if (nested || virDomainNestedJobAllowed(jobObj, job))
+            blocker = jobObj->ownerAPI;
+        else
+            blocker = jobObj->asyncOwnerAPI;
+    }
+
+    if (agentJob)
+        agentBlocker = jobObj->agentOwnerAPI;
+
+    if (errno == ETIMEDOUT) {
+        if (blocker && agentBlocker) {
+            virReportError(VIR_ERR_OPERATION_TIMEOUT,
+                           _("cannot acquire state change "
+                             "lock (held by monitor=%s agent=%s)"),
+                           blocker, agentBlocker);
+        } else if (blocker) {
+            virReportError(VIR_ERR_OPERATION_TIMEOUT,
+                           _("cannot acquire state change "
+                             "lock (held by monitor=%s)"),
+                           blocker);
+        } else if (agentBlocker) {
+            virReportError(VIR_ERR_OPERATION_TIMEOUT,
+                           _("cannot acquire state change "
+                             "lock (held by agent=%s)"),
+                           agentBlocker);
+        } else {
+            virReportError(VIR_ERR_OPERATION_TIMEOUT, "%s",
+                           _("cannot acquire state change lock"));
+        }
+        ret = -2;
+    } else if (jobObj->maxQueuedJobs &&
+               jobObj->jobsQueued > jobObj->maxQueuedJobs) {
+        if (blocker && agentBlocker) {
+            virReportError(VIR_ERR_OPERATION_FAILED,
+                           _("cannot acquire state change "
+                             "lock (held by monitor=%s agent=%s) "
+                             "due to max_queued limit"),
+                           blocker, agentBlocker);
+        } else if (blocker) {
+            virReportError(VIR_ERR_OPERATION_FAILED,
+                           _("cannot acquire state change "
+                             "lock (held by monitor=%s) "
+                             "due to max_queued limit"),
+                           blocker);
+        } else if (agentBlocker) {
+            virReportError(VIR_ERR_OPERATION_FAILED,
+                           _("cannot acquire state change "
+                             "lock (held by agent=%s) "
+                             "due to max_queued limit"),
+                           agentBlocker);
+        } else {
+            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                           _("cannot acquire state change lock "
+                             "due to max_queued limit"));
+        }
+        ret = -2;
+    } else {
+        virReportSystemError(errno, "%s", _("cannot acquire job mutex"));
+    }
+
+ cleanup:
+    jobObj->jobsQueued--;
+    return ret;
+}
diff --git a/src/conf/virdomainjob.h b/src/conf/virdomainjob.h
new file mode 100644 (file)
index 0000000..bdfdc91
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * virdomainjob.h: job functions shared between hypervisor drivers
+ *
+ * Copyright (C) 2022 Red Hat, Inc.
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#pragma once
+
+#include "internal.h"
+#include "virenum.h"
+#include "virthread.h"
+#include "virbuffer.h"
+#include "domain_conf.h"
+
+#define JOB_MASK(job)                  (job == 0 ? 0 : 1 << (job - 1))
+#define VIR_JOB_DEFAULT_MASK \
+    (JOB_MASK(VIR_JOB_QUERY) | \
+     JOB_MASK(VIR_JOB_DESTROY) | \
+     JOB_MASK(VIR_JOB_ABORT))
+
+/* Jobs which have to be tracked in domain state XML. */
+#define VIR_DOMAIN_TRACK_JOBS \
+    (JOB_MASK(VIR_JOB_DESTROY) | \
+     JOB_MASK(VIR_JOB_ASYNC))
+
+
+/* Only 1 job is allowed at any time
+ * A job includes *all* monitor commands / hypervisor.so api,
+ * even those just querying information, not merely actions */
+typedef enum {
+    VIR_JOB_NONE = 0,  /* Always set to 0 for easy if (jobActive) conditions */
+    VIR_JOB_QUERY,         /* Doesn't change any state */
+    VIR_JOB_DESTROY,       /* Destroys the domain (cannot be masked out) */
+    VIR_JOB_SUSPEND,       /* Suspends (stops vCPUs) the domain */
+    VIR_JOB_MODIFY,        /* May change state */
+    VIR_JOB_ABORT,         /* Abort current async job */
+    VIR_JOB_MIGRATION_OP,  /* Operation influencing outgoing migration */
+    VIR_JOB_MODIFY_MIGRATION_SAFE, /* Internal only job for event handlers which
+                                      need to be processed even during migration.
+                                      The code may only change state in a way
+                                      that does not affect migration. */
+
+    /* The following two items must always be the last items before JOB_LAST */
+    VIR_JOB_ASYNC,         /* Asynchronous job */
+    VIR_JOB_ASYNC_NESTED,  /* Normal job within an async job */
+
+    VIR_JOB_LAST
+} virDomainJob;
+VIR_ENUM_DECL(virDomainJob);
+
+
+/* Currently only QEMU driver uses agent jobs */
+typedef enum {
+    VIR_AGENT_JOB_NONE = 0,    /* No agent job. */
+    VIR_AGENT_JOB_QUERY,       /* Does not change state of domain */
+    VIR_AGENT_JOB_MODIFY,      /* May change state of domain */
+
+    VIR_AGENT_JOB_LAST
+} virDomainAgentJob;
+VIR_ENUM_DECL(virDomainAgentJob);
+
+
+/* Async job consists of a series of jobs that may change state. Independent
+ * jobs that do not change state (and possibly others if explicitly allowed by
+ * current async job) are allowed to be run even if async job is active.
+ * Currently supported by QEMU only. */
+typedef enum {
+    VIR_ASYNC_JOB_NONE = 0,
+    VIR_ASYNC_JOB_MIGRATION_OUT,
+    VIR_ASYNC_JOB_MIGRATION_IN,
+    VIR_ASYNC_JOB_SAVE,
+    VIR_ASYNC_JOB_DUMP,
+    VIR_ASYNC_JOB_SNAPSHOT,
+    VIR_ASYNC_JOB_START,
+    VIR_ASYNC_JOB_BACKUP,
+
+    VIR_ASYNC_JOB_LAST
+} virDomainAsyncJob;
+VIR_ENUM_DECL(virDomainAsyncJob);
+
+
+typedef enum {
+    VIR_DOMAIN_JOB_STATUS_NONE = 0,
+    VIR_DOMAIN_JOB_STATUS_ACTIVE,
+    VIR_DOMAIN_JOB_STATUS_MIGRATING,
+    VIR_DOMAIN_JOB_STATUS_HYPERVISOR_COMPLETED,
+    VIR_DOMAIN_JOB_STATUS_PAUSED,
+    VIR_DOMAIN_JOB_STATUS_POSTCOPY,
+    VIR_DOMAIN_JOB_STATUS_POSTCOPY_PAUSED,
+    VIR_DOMAIN_JOB_STATUS_COMPLETED,
+    VIR_DOMAIN_JOB_STATUS_FAILED,
+    VIR_DOMAIN_JOB_STATUS_CANCELED,
+} virDomainJobStatus;
+
+typedef void *(*virDomainJobDataPrivateDataAlloc) (void);
+typedef void *(*virDomainJobDataPrivateDataCopy) (void *);
+typedef void (*virDomainJobDataPrivateDataFree) (void *);
+
+typedef struct _virDomainJobDataPrivateDataCallbacks virDomainJobDataPrivateDataCallbacks;
+struct _virDomainJobDataPrivateDataCallbacks {
+    virDomainJobDataPrivateDataAlloc allocPrivateData;
+    virDomainJobDataPrivateDataCopy copyPrivateData;
+    virDomainJobDataPrivateDataFree freePrivateData;
+};
+
+
+typedef struct _virDomainJobData virDomainJobData;
+struct _virDomainJobData {
+    virDomainJobType jobType;
+
+    virDomainJobStatus status;
+    virDomainJobOperation operation;
+    unsigned long long started; /* When the async job started */
+    unsigned long long stopped; /* When the domain's CPUs were stopped */
+    unsigned long long sent; /* When the source sent status info to the
+                                destination (only for migrations). */
+    unsigned long long received; /* When the destination host received status
+                                    info from the source (migrations only). */
+    /* Computed values */
+    unsigned long long timeElapsed;
+    long long timeDelta; /* delta = received - sent, i.e., the difference between
+                            the source and the destination time plus the time
+                            between the end of Perform phase on the source and
+                            the beginning of Finish phase on the destination. */
+    bool timeDeltaSet;
+
+    char *errmsg; /* optional error message for failed completed jobs */
+
+    void *privateData; /* private data of hypervisors */
+    virDomainJobDataPrivateDataCallbacks *privateDataCb; /* callbacks of private data,
+                                                            hypervisor based */
+};
+
+
+virDomainJobData *
+virDomainJobDataInit(virDomainJobDataPrivateDataCallbacks *cb);
+
+void
+virDomainJobDataFree(virDomainJobData *data);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainJobData, virDomainJobDataFree);
+
+virDomainJobData *
+virDomainJobDataCopy(virDomainJobData *data);
+
+virDomainJobType
+virDomainJobStatusToType(virDomainJobStatus status);
+
+
+typedef struct _virDomainObjPrivateJobCallbacks virDomainObjPrivateJobCallbacks;
+
+typedef struct _virDomainJobObj virDomainJobObj;
+struct _virDomainJobObj {
+    virCond cond;               /* Use to coordinate jobs */
+
+    int jobsQueued;
+    unsigned int maxQueuedJobs;
+
+    /* The following members are for VIR_JOB_* */
+    virDomainJob active;        /* currently running job */
+    unsigned long long owner;           /* Thread id which set current job */
+    char *ownerAPI;                     /* The API which owns the job */
+    unsigned long long started;         /* When the current job started */
+
+    /* The following members are for VIR_AGENT_JOB_* */
+    virDomainAgentJob agentActive;     /* Currently running agent job */
+    unsigned long long agentOwner;      /* Thread id which set current agent job */
+    char *agentOwnerAPI;                /* The API which owns the agent job */
+    unsigned long long agentStarted;    /* When the current agent job started */
+
+    /* The following members are for VIR_ASYNC_JOB_* */
+    virCond asyncCond;                  /* Use to coordinate with async jobs */
+    virDomainAsyncJob asyncJob;        /* Currently active async job */
+    unsigned long long asyncOwner;      /* Thread which set current async job */
+    char *asyncOwnerAPI;                /* The API which owns the async job */
+    unsigned long long asyncStarted;    /* When the current async job started */
+    int phase;                          /* Job phase (mainly for migrations) */
+    unsigned long long mask;            /* Jobs allowed during async job */
+    virDomainJobData *current;       /* async job progress data */
+    virDomainJobData *completed;     /* statistics data of a recently completed job */
+    bool abortJob;                      /* abort of the job requested */
+    char *error;                        /* job event completion error */
+    unsigned long apiFlags; /* flags passed to the API which started the async job */
+
+    void *privateData;                  /* job specific collection of data */
+    virDomainObjPrivateJobCallbacks *cb;
+    virDomainJobDataPrivateDataCallbacks *jobDataPrivateCb; /* callbacks for privateData of
+                                                               virDomainJobData, can be NULL */
+};
+
+
+typedef void *(*virDomainObjPrivateJobAlloc)(void);
+typedef void (*virDomainObjPrivateJobFree)(void *);
+typedef void (*virDomainObjPrivateJobReset)(void *);
+typedef int (*virDomainObjPrivateJobFormat)(virBuffer *,
+                                            virDomainJobObj *,
+                                            virDomainObj *);
+typedef int (*virDomainObjPrivateJobParse)(xmlXPathContextPtr,
+                                           virDomainJobObj *,
+                                           virDomainObj *);
+typedef void (*virDomainObjPrivateSaveStatus)(virDomainObj *obj);
+
+struct _virDomainObjPrivateJobCallbacks {
+   virDomainObjPrivateJobAlloc allocJobPrivate;
+   virDomainObjPrivateJobFree freeJobPrivate;
+   virDomainObjPrivateJobReset resetJobPrivate;
+   virDomainObjPrivateJobFormat formatJobPrivate;
+   virDomainObjPrivateJobParse parseJobPrivate;
+   virDomainObjPrivateSaveStatus saveStatusPrivate;
+};
+
+
+int virDomainObjInitJob(virDomainJobObj *job,
+                        virDomainObjPrivateJobCallbacks *cb,
+                        virDomainJobDataPrivateDataCallbacks *jobDataPrivateCb);
+
+void virDomainObjResetJob(virDomainJobObj *job);
+
+void virDomainObjResetAgentJob(virDomainJobObj *job);
+
+void virDomainObjResetAsyncJob(virDomainJobObj *job);
+
+int virDomainObjPreserveJob(virDomainJobObj *currJob,
+                            virDomainJobObj *job);
+
+void virDomainObjClearJob(virDomainJobObj *job);
+G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(virDomainJobObj, virDomainObjClearJob);
+
+bool virDomainTrackJob(virDomainJob job);
+
+bool virDomainNestedJobAllowed(virDomainJobObj *jobs, virDomainJob newJob);
+
+bool virDomainObjCanSetJob(virDomainJobObj *job,
+                           virDomainJob newJob,
+                           virDomainAgentJob newAgentJob);
+
+int virDomainObjBeginJobInternal(virDomainObj *obj,
+                                 virDomainJobObj *jobObj,
+                                 virDomainJob job,
+                                 virDomainAgentJob agentJob,
+                                 virDomainAsyncJob asyncJob,
+                                 bool nowait)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
diff --git a/src/hypervisor/domain_job.c b/src/hypervisor/domain_job.c
deleted file mode 100644 (file)
index 07ee5b4..0000000
+++ /dev/null
@@ -1,500 +0,0 @@
-/*
- * domain_job.c: job functions shared between hypervisor drivers
- *
- * Copyright (C) 2022 Red Hat, Inc.
- * SPDX-License-Identifier: LGPL-2.1-or-later
- */
-
-#include <config.h>
-#include <string.h>
-
-#include "domain_job.h"
-#include "viralloc.h"
-#include "virthreadjob.h"
-#include "virlog.h"
-#include "virtime.h"
-
-#define VIR_FROM_THIS VIR_FROM_NONE
-
-VIR_LOG_INIT("hypervisor.domain_job");
-
-
-VIR_ENUM_IMPL(virDomainJob,
-              VIR_JOB_LAST,
-              "none",
-              "query",
-              "destroy",
-              "suspend",
-              "modify",
-              "abort",
-              "migration operation",
-              "modify migration safe",
-              "none",   /* async job is never stored in job.active */
-              "async nested",
-);
-
-VIR_ENUM_IMPL(virDomainAgentJob,
-              VIR_AGENT_JOB_LAST,
-              "none",
-              "query",
-              "modify",
-);
-
-VIR_ENUM_IMPL(virDomainAsyncJob,
-              VIR_ASYNC_JOB_LAST,
-              "none",
-              "migration out",
-              "migration in",
-              "save",
-              "dump",
-              "snapshot",
-              "start",
-              "backup",
-);
-
-virDomainJobData *
-virDomainJobDataInit(virDomainJobDataPrivateDataCallbacks *cb)
-{
-    virDomainJobData *ret = g_new0(virDomainJobData, 1);
-
-    ret->privateDataCb = cb;
-
-    if (ret->privateDataCb)
-        ret->privateData = ret->privateDataCb->allocPrivateData();
-
-    return ret;
-}
-
-virDomainJobData *
-virDomainJobDataCopy(virDomainJobData *data)
-{
-    virDomainJobData *ret = g_new0(virDomainJobData, 1);
-
-    memcpy(ret, data, sizeof(*data));
-
-    if (ret->privateDataCb)
-        ret->privateData = data->privateDataCb->copyPrivateData(data->privateData);
-
-    ret->errmsg = g_strdup(data->errmsg);
-
-    return ret;
-}
-
-void
-virDomainJobDataFree(virDomainJobData *data)
-{
-    if (!data)
-        return;
-
-    if (data->privateDataCb)
-        data->privateDataCb->freePrivateData(data->privateData);
-
-    g_free(data->errmsg);
-    g_free(data);
-}
-
-virDomainJobType
-virDomainJobStatusToType(virDomainJobStatus status)
-{
-    switch (status) {
-    case VIR_DOMAIN_JOB_STATUS_NONE:
-        break;
-
-    case VIR_DOMAIN_JOB_STATUS_ACTIVE:
-    case VIR_DOMAIN_JOB_STATUS_MIGRATING:
-    case VIR_DOMAIN_JOB_STATUS_HYPERVISOR_COMPLETED:
-    case VIR_DOMAIN_JOB_STATUS_POSTCOPY:
-    case VIR_DOMAIN_JOB_STATUS_POSTCOPY_PAUSED:
-    case VIR_DOMAIN_JOB_STATUS_PAUSED:
-        return VIR_DOMAIN_JOB_UNBOUNDED;
-
-    case VIR_DOMAIN_JOB_STATUS_COMPLETED:
-        return VIR_DOMAIN_JOB_COMPLETED;
-
-    case VIR_DOMAIN_JOB_STATUS_FAILED:
-        return VIR_DOMAIN_JOB_FAILED;
-
-    case VIR_DOMAIN_JOB_STATUS_CANCELED:
-        return VIR_DOMAIN_JOB_CANCELLED;
-    }
-
-    return VIR_DOMAIN_JOB_NONE;
-}
-
-int
-virDomainObjInitJob(virDomainJobObj *job,
-                    virDomainObjPrivateJobCallbacks *cb,
-                    virDomainJobDataPrivateDataCallbacks *jobDataPrivateCb)
-{
-    memset(job, 0, sizeof(*job));
-    job->cb = cb;
-    job->jobDataPrivateCb = jobDataPrivateCb;
-
-    if (virCondInit(&job->cond) < 0)
-        return -1;
-
-    if (virCondInit(&job->asyncCond) < 0) {
-        virCondDestroy(&job->cond);
-        return -1;
-    }
-
-    if (job->cb &&
-        !(job->privateData = job->cb->allocJobPrivate())) {
-        virCondDestroy(&job->cond);
-        virCondDestroy(&job->asyncCond);
-        return -1;
-    }
-
-    return 0;
-}
-
-void
-virDomainObjResetJob(virDomainJobObj *job)
-{
-    job->active = VIR_JOB_NONE;
-    job->owner = 0;
-    g_clear_pointer(&job->ownerAPI, g_free);
-    job->started = 0;
-}
-
-void
-virDomainObjResetAgentJob(virDomainJobObj *job)
-{
-    job->agentActive = VIR_AGENT_JOB_NONE;
-    job->agentOwner = 0;
-    g_clear_pointer(&job->agentOwnerAPI, g_free);
-    job->agentStarted = 0;
-}
-
-void
-virDomainObjResetAsyncJob(virDomainJobObj *job)
-{
-    job->asyncJob = VIR_ASYNC_JOB_NONE;
-    job->asyncOwner = 0;
-    g_clear_pointer(&job->asyncOwnerAPI, g_free);
-    job->asyncStarted = 0;
-    job->phase = 0;
-    job->mask = VIR_JOB_DEFAULT_MASK;
-    job->abortJob = false;
-    VIR_FREE(job->error);
-    g_clear_pointer(&job->current, virDomainJobDataFree);
-    job->apiFlags = 0;
-
-    if (job->cb)
-        job->cb->resetJobPrivate(job->privateData);
-}
-
-/**
- * virDomainObjPreserveJob
- * @param currJob structure is a job that needs to be preserved
- * @param job structure where to store job details from @currJob
- *
- * Saves the current job details from @currJob to @job and resets the job in @currJob.
- *
- * Returns 0 on success, -1 on failure.
- */
-int
-virDomainObjPreserveJob(virDomainJobObj *currJob,
-                        virDomainJobObj *job)
-{
-    memset(job, 0, sizeof(*job));
-    job->active = currJob->active;
-    job->owner = currJob->owner;
-    job->asyncJob = currJob->asyncJob;
-    job->asyncOwner = currJob->asyncOwner;
-    job->phase = currJob->phase;
-    job->privateData = g_steal_pointer(&currJob->privateData);
-    job->apiFlags = currJob->apiFlags;
-
-    if (currJob->cb &&
-        !(currJob->privateData = currJob->cb->allocJobPrivate()))
-        return -1;
-    job->cb = currJob->cb;
-
-    virDomainObjResetJob(currJob);
-    virDomainObjResetAsyncJob(currJob);
-    return 0;
-}
-
-void
-virDomainObjClearJob(virDomainJobObj *job)
-{
-    virDomainObjResetJob(job);
-    virDomainObjResetAsyncJob(job);
-    g_clear_pointer(&job->current, virDomainJobDataFree);
-    g_clear_pointer(&job->completed, virDomainJobDataFree);
-    virCondDestroy(&job->cond);
-    virCondDestroy(&job->asyncCond);
-
-    if (job->cb)
-        g_clear_pointer(&job->privateData, job->cb->freeJobPrivate);
-}
-
-bool
-virDomainTrackJob(virDomainJob job)
-{
-    return (VIR_DOMAIN_TRACK_JOBS & JOB_MASK(job)) != 0;
-}
-
-bool
-virDomainNestedJobAllowed(virDomainJobObj *jobs, virDomainJob newJob)
-{
-    return !jobs->asyncJob ||
-           newJob == VIR_JOB_NONE ||
-           (jobs->mask & JOB_MASK(newJob));
-}
-
-bool
-virDomainObjCanSetJob(virDomainJobObj *job,
-                      virDomainJob newJob,
-                      virDomainAgentJob newAgentJob)
-{
-    return ((newJob == VIR_JOB_NONE ||
-             job->active == VIR_JOB_NONE) &&
-            (newAgentJob == VIR_AGENT_JOB_NONE ||
-             job->agentActive == VIR_AGENT_JOB_NONE));
-}
-
-/* Give up waiting for mutex after 30 seconds */
-#define VIR_JOB_WAIT_TIME (1000ull * 30)
-
-/**
- * virDomainObjBeginJobInternal:
- * @obj: virDomainObj = domain object
- * @jobObj: virDomainJobObj = domain job object
- * @job: virDomainJob to start
- * @agentJob: virDomainAgentJob to start
- * @asyncJob: virDomainAsyncJob to start
- * @nowait: don't wait trying to acquire @job
- *
- * Acquires job for a domain object which must be locked before
- * calling. If there's already a job running waits up to
- * VIR_JOB_WAIT_TIME after which the functions fails reporting
- * an error unless @nowait is set.
- *
- * If @nowait is true this function tries to acquire job and if
- * it fails, then it returns immediately without waiting. No
- * error is reported in this case.
- *
- * Returns: 0 on success,
- *         -2 if unable to start job because of timeout or
- *            maxQueuedJobs limit,
- *         -1 otherwise.
- */
-int
-virDomainObjBeginJobInternal(virDomainObj *obj,
-                             virDomainJobObj *jobObj,
-                             virDomainJob job,
-                             virDomainAgentJob agentJob,
-                             virDomainAsyncJob asyncJob,
-                             bool nowait)
-{
-    unsigned long long now = 0;
-    unsigned long long then = 0;
-    bool nested = job == VIR_JOB_ASYNC_NESTED;
-    const char *blocker = NULL;
-    const char *agentBlocker = NULL;
-    int ret = -1;
-    unsigned long long duration = 0;
-    unsigned long long agentDuration = 0;
-    unsigned long long asyncDuration = 0;
-    const char *currentAPI = virThreadJobGet();
-
-    VIR_DEBUG("Starting job: API=%s job=%s agentJob=%s asyncJob=%s "
-              "(vm=%p name=%s, current job=%s agentJob=%s async=%s)",
-              NULLSTR(currentAPI),
-              virDomainJobTypeToString(job),
-              virDomainAgentJobTypeToString(agentJob),
-              virDomainAsyncJobTypeToString(asyncJob),
-              obj, obj->def->name,
-              virDomainJobTypeToString(jobObj->active),
-              virDomainAgentJobTypeToString(jobObj->agentActive),
-              virDomainAsyncJobTypeToString(jobObj->asyncJob));
-
-    if (virTimeMillisNow(&now) < 0)
-        return -1;
-
-    jobObj->jobsQueued++;
-    then = now + VIR_JOB_WAIT_TIME;
-
- retry:
-    if (job != VIR_JOB_ASYNC &&
-        job != VIR_JOB_DESTROY &&
-        jobObj->maxQueuedJobs &&
-        jobObj->jobsQueued > jobObj->maxQueuedJobs) {
-        goto error;
-    }
-
-    while (!nested && !virDomainNestedJobAllowed(jobObj, job)) {
-        if (nowait)
-            goto cleanup;
-
-        VIR_DEBUG("Waiting for async job (vm=%p name=%s)", obj, obj->def->name);
-        if (virCondWaitUntil(&jobObj->asyncCond, &obj->parent.lock, then) < 0)
-            goto error;
-    }
-
-    while (!virDomainObjCanSetJob(jobObj, job, agentJob)) {
-        if (nowait)
-            goto cleanup;
-
-        VIR_DEBUG("Waiting for job (vm=%p name=%s)", obj, obj->def->name);
-        if (virCondWaitUntil(&jobObj->cond, &obj->parent.lock, then) < 0)
-            goto error;
-    }
-
-    /* No job is active but a new async job could have been started while obj
-     * was unlocked, so we need to recheck it. */
-    if (!nested && !virDomainNestedJobAllowed(jobObj, job))
-        goto retry;
-
-    if (obj->removing) {
-        char uuidstr[VIR_UUID_STRING_BUFLEN];
-
-        virUUIDFormat(obj->def->uuid, uuidstr);
-        virReportError(VIR_ERR_NO_DOMAIN,
-                       _("no domain with matching uuid '%s' (%s)"),
-                       uuidstr, obj->def->name);
-        goto cleanup;
-    }
-
-    ignore_value(virTimeMillisNow(&now));
-
-    if (job) {
-        virDomainObjResetJob(jobObj);
-
-        if (job != VIR_JOB_ASYNC) {
-            VIR_DEBUG("Started job: %s (async=%s vm=%p name=%s)",
-                      virDomainJobTypeToString(job),
-                      virDomainAsyncJobTypeToString(jobObj->asyncJob),
-                      obj, obj->def->name);
-            jobObj->active = job;
-            jobObj->owner = virThreadSelfID();
-            jobObj->ownerAPI = g_strdup(virThreadJobGet());
-            jobObj->started = now;
-        } else {
-            VIR_DEBUG("Started async job: %s (vm=%p name=%s)",
-                      virDomainAsyncJobTypeToString(asyncJob),
-                      obj, obj->def->name);
-            virDomainObjResetAsyncJob(jobObj);
-            jobObj->current = virDomainJobDataInit(jobObj->jobDataPrivateCb);
-            jobObj->current->status = VIR_DOMAIN_JOB_STATUS_ACTIVE;
-            jobObj->asyncJob = asyncJob;
-            jobObj->asyncOwner = virThreadSelfID();
-            jobObj->asyncOwnerAPI = g_strdup(virThreadJobGet());
-            jobObj->asyncStarted = now;
-            jobObj->current->started = now;
-        }
-    }
-
-    if (agentJob) {
-        virDomainObjResetAgentJob(jobObj);
-        VIR_DEBUG("Started agent job: %s (vm=%p name=%s job=%s async=%s)",
-                  virDomainAgentJobTypeToString(agentJob),
-                  obj, obj->def->name,
-                  virDomainJobTypeToString(jobObj->active),
-                  virDomainAsyncJobTypeToString(jobObj->asyncJob));
-        jobObj->agentActive = agentJob;
-        jobObj->agentOwner = virThreadSelfID();
-        jobObj->agentOwnerAPI = g_strdup(virThreadJobGet());
-        jobObj->agentStarted = now;
-    }
-
-    if (virDomainTrackJob(job) && jobObj->cb &&
-        jobObj->cb->saveStatusPrivate)
-        jobObj->cb->saveStatusPrivate(obj);
-
-    return 0;
-
- error:
-    ignore_value(virTimeMillisNow(&now));
-    if (jobObj->active && jobObj->started)
-        duration = now - jobObj->started;
-    if (jobObj->agentActive && jobObj->agentStarted)
-        agentDuration = now - jobObj->agentStarted;
-    if (jobObj->asyncJob && jobObj->asyncStarted)
-        asyncDuration = now - jobObj->asyncStarted;
-
-    VIR_WARN("Cannot start job (%s, %s, %s) in API %s for domain %s; "
-             "current job is (%s, %s, %s) "
-             "owned by (%llu %s, %llu %s, %llu %s (flags=0x%lx)) "
-             "for (%llus, %llus, %llus)",
-             virDomainJobTypeToString(job),
-             virDomainAgentJobTypeToString(agentJob),
-             virDomainAsyncJobTypeToString(asyncJob),
-             NULLSTR(currentAPI),
-             obj->def->name,
-             virDomainJobTypeToString(jobObj->active),
-             virDomainAgentJobTypeToString(jobObj->agentActive),
-             virDomainAsyncJobTypeToString(jobObj->asyncJob),
-             jobObj->owner, NULLSTR(jobObj->ownerAPI),
-             jobObj->agentOwner, NULLSTR(jobObj->agentOwnerAPI),
-             jobObj->asyncOwner, NULLSTR(jobObj->asyncOwnerAPI),
-             jobObj->apiFlags,
-             duration / 1000, agentDuration / 1000, asyncDuration / 1000);
-
-    if (job) {
-        if (nested || virDomainNestedJobAllowed(jobObj, job))
-            blocker = jobObj->ownerAPI;
-        else
-            blocker = jobObj->asyncOwnerAPI;
-    }
-
-    if (agentJob)
-        agentBlocker = jobObj->agentOwnerAPI;
-
-    if (errno == ETIMEDOUT) {
-        if (blocker && agentBlocker) {
-            virReportError(VIR_ERR_OPERATION_TIMEOUT,
-                           _("cannot acquire state change "
-                             "lock (held by monitor=%s agent=%s)"),
-                           blocker, agentBlocker);
-        } else if (blocker) {
-            virReportError(VIR_ERR_OPERATION_TIMEOUT,
-                           _("cannot acquire state change "
-                             "lock (held by monitor=%s)"),
-                           blocker);
-        } else if (agentBlocker) {
-            virReportError(VIR_ERR_OPERATION_TIMEOUT,
-                           _("cannot acquire state change "
-                             "lock (held by agent=%s)"),
-                           agentBlocker);
-        } else {
-            virReportError(VIR_ERR_OPERATION_TIMEOUT, "%s",
-                           _("cannot acquire state change lock"));
-        }
-        ret = -2;
-    } else if (jobObj->maxQueuedJobs &&
-               jobObj->jobsQueued > jobObj->maxQueuedJobs) {
-        if (blocker && agentBlocker) {
-            virReportError(VIR_ERR_OPERATION_FAILED,
-                           _("cannot acquire state change "
-                             "lock (held by monitor=%s agent=%s) "
-                             "due to max_queued limit"),
-                           blocker, agentBlocker);
-        } else if (blocker) {
-            virReportError(VIR_ERR_OPERATION_FAILED,
-                           _("cannot acquire state change "
-                             "lock (held by monitor=%s) "
-                             "due to max_queued limit"),
-                           blocker);
-        } else if (agentBlocker) {
-            virReportError(VIR_ERR_OPERATION_FAILED,
-                           _("cannot acquire state change "
-                             "lock (held by agent=%s) "
-                             "due to max_queued limit"),
-                           agentBlocker);
-        } else {
-            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
-                           _("cannot acquire state change lock "
-                             "due to max_queued limit"));
-        }
-        ret = -2;
-    } else {
-        virReportSystemError(errno, "%s", _("cannot acquire job mutex"));
-    }
-
- cleanup:
-    jobObj->jobsQueued--;
-    return ret;
-}
diff --git a/src/hypervisor/domain_job.h b/src/hypervisor/domain_job.h
deleted file mode 100644 (file)
index d7409c0..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * domain_job.h: job functions shared between hypervisor drivers
- *
- * Copyright (C) 2022 Red Hat, Inc.
- * SPDX-License-Identifier: LGPL-2.1-or-later
- */
-
-#pragma once
-
-#include "internal.h"
-#include "virenum.h"
-#include "virthread.h"
-#include "virbuffer.h"
-#include "domain_conf.h"
-
-#define JOB_MASK(job)                  (job == 0 ? 0 : 1 << (job - 1))
-#define VIR_JOB_DEFAULT_MASK \
-    (JOB_MASK(VIR_JOB_QUERY) | \
-     JOB_MASK(VIR_JOB_DESTROY) | \
-     JOB_MASK(VIR_JOB_ABORT))
-
-/* Jobs which have to be tracked in domain state XML. */
-#define VIR_DOMAIN_TRACK_JOBS \
-    (JOB_MASK(VIR_JOB_DESTROY) | \
-     JOB_MASK(VIR_JOB_ASYNC))
-
-
-/* Only 1 job is allowed at any time
- * A job includes *all* monitor commands / hypervisor.so api,
- * even those just querying information, not merely actions */
-typedef enum {
-    VIR_JOB_NONE = 0,  /* Always set to 0 for easy if (jobActive) conditions */
-    VIR_JOB_QUERY,         /* Doesn't change any state */
-    VIR_JOB_DESTROY,       /* Destroys the domain (cannot be masked out) */
-    VIR_JOB_SUSPEND,       /* Suspends (stops vCPUs) the domain */
-    VIR_JOB_MODIFY,        /* May change state */
-    VIR_JOB_ABORT,         /* Abort current async job */
-    VIR_JOB_MIGRATION_OP,  /* Operation influencing outgoing migration */
-    VIR_JOB_MODIFY_MIGRATION_SAFE, /* Internal only job for event handlers which
-                                      need to be processed even during migration.
-                                      The code may only change state in a way
-                                      that does not affect migration. */
-
-    /* The following two items must always be the last items before JOB_LAST */
-    VIR_JOB_ASYNC,         /* Asynchronous job */
-    VIR_JOB_ASYNC_NESTED,  /* Normal job within an async job */
-
-    VIR_JOB_LAST
-} virDomainJob;
-VIR_ENUM_DECL(virDomainJob);
-
-
-/* Currently only QEMU driver uses agent jobs */
-typedef enum {
-    VIR_AGENT_JOB_NONE = 0,    /* No agent job. */
-    VIR_AGENT_JOB_QUERY,       /* Does not change state of domain */
-    VIR_AGENT_JOB_MODIFY,      /* May change state of domain */
-
-    VIR_AGENT_JOB_LAST
-} virDomainAgentJob;
-VIR_ENUM_DECL(virDomainAgentJob);
-
-
-/* Async job consists of a series of jobs that may change state. Independent
- * jobs that do not change state (and possibly others if explicitly allowed by
- * current async job) are allowed to be run even if async job is active.
- * Currently supported by QEMU only. */
-typedef enum {
-    VIR_ASYNC_JOB_NONE = 0,
-    VIR_ASYNC_JOB_MIGRATION_OUT,
-    VIR_ASYNC_JOB_MIGRATION_IN,
-    VIR_ASYNC_JOB_SAVE,
-    VIR_ASYNC_JOB_DUMP,
-    VIR_ASYNC_JOB_SNAPSHOT,
-    VIR_ASYNC_JOB_START,
-    VIR_ASYNC_JOB_BACKUP,
-
-    VIR_ASYNC_JOB_LAST
-} virDomainAsyncJob;
-VIR_ENUM_DECL(virDomainAsyncJob);
-
-
-typedef enum {
-    VIR_DOMAIN_JOB_STATUS_NONE = 0,
-    VIR_DOMAIN_JOB_STATUS_ACTIVE,
-    VIR_DOMAIN_JOB_STATUS_MIGRATING,
-    VIR_DOMAIN_JOB_STATUS_HYPERVISOR_COMPLETED,
-    VIR_DOMAIN_JOB_STATUS_PAUSED,
-    VIR_DOMAIN_JOB_STATUS_POSTCOPY,
-    VIR_DOMAIN_JOB_STATUS_POSTCOPY_PAUSED,
-    VIR_DOMAIN_JOB_STATUS_COMPLETED,
-    VIR_DOMAIN_JOB_STATUS_FAILED,
-    VIR_DOMAIN_JOB_STATUS_CANCELED,
-} virDomainJobStatus;
-
-typedef void *(*virDomainJobDataPrivateDataAlloc) (void);
-typedef void *(*virDomainJobDataPrivateDataCopy) (void *);
-typedef void (*virDomainJobDataPrivateDataFree) (void *);
-
-typedef struct _virDomainJobDataPrivateDataCallbacks virDomainJobDataPrivateDataCallbacks;
-struct _virDomainJobDataPrivateDataCallbacks {
-    virDomainJobDataPrivateDataAlloc allocPrivateData;
-    virDomainJobDataPrivateDataCopy copyPrivateData;
-    virDomainJobDataPrivateDataFree freePrivateData;
-};
-
-
-typedef struct _virDomainJobData virDomainJobData;
-struct _virDomainJobData {
-    virDomainJobType jobType;
-
-    virDomainJobStatus status;
-    virDomainJobOperation operation;
-    unsigned long long started; /* When the async job started */
-    unsigned long long stopped; /* When the domain's CPUs were stopped */
-    unsigned long long sent; /* When the source sent status info to the
-                                destination (only for migrations). */
-    unsigned long long received; /* When the destination host received status
-                                    info from the source (migrations only). */
-    /* Computed values */
-    unsigned long long timeElapsed;
-    long long timeDelta; /* delta = received - sent, i.e., the difference between
-                            the source and the destination time plus the time
-                            between the end of Perform phase on the source and
-                            the beginning of Finish phase on the destination. */
-    bool timeDeltaSet;
-
-    char *errmsg; /* optional error message for failed completed jobs */
-
-    void *privateData; /* private data of hypervisors */
-    virDomainJobDataPrivateDataCallbacks *privateDataCb; /* callbacks of private data,
-                                                            hypervisor based */
-};
-
-
-virDomainJobData *
-virDomainJobDataInit(virDomainJobDataPrivateDataCallbacks *cb);
-
-void
-virDomainJobDataFree(virDomainJobData *data);
-
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainJobData, virDomainJobDataFree);
-
-virDomainJobData *
-virDomainJobDataCopy(virDomainJobData *data);
-
-virDomainJobType
-virDomainJobStatusToType(virDomainJobStatus status);
-
-
-typedef struct _virDomainObjPrivateJobCallbacks virDomainObjPrivateJobCallbacks;
-
-typedef struct _virDomainJobObj virDomainJobObj;
-struct _virDomainJobObj {
-    virCond cond;               /* Use to coordinate jobs */
-
-    int jobsQueued;
-    unsigned int maxQueuedJobs;
-
-    /* The following members are for VIR_JOB_* */
-    virDomainJob active;        /* currently running job */
-    unsigned long long owner;           /* Thread id which set current job */
-    char *ownerAPI;                     /* The API which owns the job */
-    unsigned long long started;         /* When the current job started */
-
-    /* The following members are for VIR_AGENT_JOB_* */
-    virDomainAgentJob agentActive;     /* Currently running agent job */
-    unsigned long long agentOwner;      /* Thread id which set current agent job */
-    char *agentOwnerAPI;                /* The API which owns the agent job */
-    unsigned long long agentStarted;    /* When the current agent job started */
-
-    /* The following members are for VIR_ASYNC_JOB_* */
-    virCond asyncCond;                  /* Use to coordinate with async jobs */
-    virDomainAsyncJob asyncJob;        /* Currently active async job */
-    unsigned long long asyncOwner;      /* Thread which set current async job */
-    char *asyncOwnerAPI;                /* The API which owns the async job */
-    unsigned long long asyncStarted;    /* When the current async job started */
-    int phase;                          /* Job phase (mainly for migrations) */
-    unsigned long long mask;            /* Jobs allowed during async job */
-    virDomainJobData *current;       /* async job progress data */
-    virDomainJobData *completed;     /* statistics data of a recently completed job */
-    bool abortJob;                      /* abort of the job requested */
-    char *error;                        /* job event completion error */
-    unsigned long apiFlags; /* flags passed to the API which started the async job */
-
-    void *privateData;                  /* job specific collection of data */
-    virDomainObjPrivateJobCallbacks *cb;
-    virDomainJobDataPrivateDataCallbacks *jobDataPrivateCb; /* callbacks for privateData of
-                                                               virDomainJobData, can be NULL */
-};
-
-
-typedef void *(*virDomainObjPrivateJobAlloc)(void);
-typedef void (*virDomainObjPrivateJobFree)(void *);
-typedef void (*virDomainObjPrivateJobReset)(void *);
-typedef int (*virDomainObjPrivateJobFormat)(virBuffer *,
-                                            virDomainJobObj *,
-                                            virDomainObj *);
-typedef int (*virDomainObjPrivateJobParse)(xmlXPathContextPtr,
-                                           virDomainJobObj *,
-                                           virDomainObj *);
-typedef void (*virDomainObjPrivateSaveStatus)(virDomainObj *obj);
-
-struct _virDomainObjPrivateJobCallbacks {
-   virDomainObjPrivateJobAlloc allocJobPrivate;
-   virDomainObjPrivateJobFree freeJobPrivate;
-   virDomainObjPrivateJobReset resetJobPrivate;
-   virDomainObjPrivateJobFormat formatJobPrivate;
-   virDomainObjPrivateJobParse parseJobPrivate;
-   virDomainObjPrivateSaveStatus saveStatusPrivate;
-};
-
-
-int virDomainObjInitJob(virDomainJobObj *job,
-                        virDomainObjPrivateJobCallbacks *cb,
-                        virDomainJobDataPrivateDataCallbacks *jobDataPrivateCb);
-
-void virDomainObjResetJob(virDomainJobObj *job);
-
-void virDomainObjResetAgentJob(virDomainJobObj *job);
-
-void virDomainObjResetAsyncJob(virDomainJobObj *job);
-
-int virDomainObjPreserveJob(virDomainJobObj *currJob,
-                            virDomainJobObj *job);
-
-void virDomainObjClearJob(virDomainJobObj *job);
-G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(virDomainJobObj, virDomainObjClearJob);
-
-bool virDomainTrackJob(virDomainJob job);
-
-bool virDomainNestedJobAllowed(virDomainJobObj *jobs, virDomainJob newJob);
-
-bool virDomainObjCanSetJob(virDomainJobObj *job,
-                           virDomainJob newJob,
-                           virDomainAgentJob newAgentJob);
-
-int virDomainObjBeginJobInternal(virDomainObj *obj,
-                                 virDomainJobObj *jobObj,
-                                 virDomainJob job,
-                                 virDomainAgentJob agentJob,
-                                 virDomainAsyncJob asyncJob,
-                                 bool nowait)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
index 7532f30ee28c32af78f3078d58d1cb33134ae29c..f35565b16b0b7b1315acec871b1bbf08b13f6c49 100644 (file)
@@ -3,7 +3,6 @@ hypervisor_sources = [
   'domain_driver.c',
   'virclosecallbacks.c',
   'virhostdev.c',
-  'domain_job.c',
 ]
 
 stateful_driver_source_files += files(hypervisor_sources)
index 08571cd4b4dcca4a5bb4352e1f4f0c9dea4fe56f..5077db9c6b0c48abd83bbfeb03c66410ad1fbab1 100644 (file)
@@ -1175,6 +1175,28 @@ virDomainCheckpointUpdateRelations;
 virDomainListCheckpoints;
 
 
+#conf/virdomainjob.h
+virDomainAgentJobTypeToString;
+virDomainAsyncJobTypeFromString;
+virDomainAsyncJobTypeToString;
+virDomainJobDataCopy;
+virDomainJobDataFree;
+virDomainJobDataInit;
+virDomainJobStatusToType;
+virDomainJobTypeFromString;
+virDomainJobTypeToString;
+virDomainNestedJobAllowed;
+virDomainObjBeginJobInternal;
+virDomainObjCanSetJob;
+virDomainObjClearJob;
+virDomainObjInitJob;
+virDomainObjPreserveJob;
+virDomainObjResetAgentJob;
+virDomainObjResetAsyncJob;
+virDomainObjResetJob;
+virDomainTrackJob;
+
+
 # conf/virdomainmomentobjlist.h
 virDomainMomentDropChildren;
 virDomainMomentDropParent;
@@ -1585,28 +1607,6 @@ virDomainDriverParseBlkioDeviceStr;
 virDomainDriverSetupPersistentDefBlkioParams;
 
 
-# hypervisor/domain_job.h
-virDomainAgentJobTypeToString;
-virDomainAsyncJobTypeFromString;
-virDomainAsyncJobTypeToString;
-virDomainJobDataCopy;
-virDomainJobDataFree;
-virDomainJobDataInit;
-virDomainJobStatusToType;
-virDomainJobTypeFromString;
-virDomainJobTypeToString;
-virDomainNestedJobAllowed;
-virDomainObjBeginJobInternal;
-virDomainObjCanSetJob;
-virDomainObjClearJob;
-virDomainObjInitJob;
-virDomainObjPreserveJob;
-virDomainObjResetAgentJob;
-virDomainObjResetAsyncJob;
-virDomainObjResetJob;
-virDomainTrackJob;
-
-
 # hypervisor/virclosecallbacks.h
 virCloseCallbacksGet;
 virCloseCallbacksNew;
index 6695ec670efd6a4edd120925d9a6f9d8c381a802..aadb13f461de40c85ea80bb61d38e61c14c697bc 100644 (file)
@@ -37,7 +37,6 @@
 #include "xen_common.h"
 #include "driver.h"
 #include "domain_validate.h"
-#include "domain_job.h"
 
 #define VIR_FROM_THIS VIR_FROM_LIBXL
 
index 8ad56f1e88a633248687bb797ce9bbf118bd9571..451e76e311b7801e53cd636b0bc465c0552f5ab6 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "libxl_conf.h"
 #include "virchrdev.h"
-#include "domain_job.h"
+#include "virdomainjob.h"
 
 
 typedef struct _libxlDomainObjPrivate libxlDomainObjPrivate;
index 61e59ec726a202902ded28b497fa849a0c27364a..f234aaf39ca7625cb9c07455d9fa1b5d0b138c98 100644 (file)
@@ -29,7 +29,6 @@
 #include "virsystemd.h"
 #include "virinitctl.h"
 #include "domain_driver.h"
-#include "domain_job.h"
 
 #define VIR_FROM_THIS VIR_FROM_LXC
 
index 82c36eb94021e57d90a0a8f7248a040fa170de1f..db622acc86288374e90d861e6f9afeab5d593b45 100644 (file)
@@ -25,7 +25,7 @@
 #include "lxc_conf.h"
 #include "lxc_monitor.h"
 #include "virenum.h"
-#include "domain_job.h"
+#include "virdomainjob.h"
 
 
 typedef enum {
index bb3c7ede1468a7a2085602d06a1a50b8aef88e86..23eadc26a715af615f8120bff8c48953be953bc0 100644 (file)
@@ -20,7 +20,7 @@
 
 #include <glib-object.h>
 #include "qemu_monitor.h"
-#include "domain_job.h"
+#include "virdomainjob.h"
 
 
 typedef enum {