qemu/job-qmp.c
<<
>>
Prefs
   1/*
   2 * QMP interface for background jobs
   3 *
   4 * Copyright (c) 2011 IBM Corp.
   5 * Copyright (c) 2012, 2018 Red Hat, Inc.
   6 *
   7 * Permission is hereby granted, free of charge, to any person obtaining a copy
   8 * of this software and associated documentation files (the "Software"), to deal
   9 * in the Software without restriction, including without limitation the rights
  10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11 * copies of the Software, and to permit persons to whom the Software is
  12 * furnished to do so, subject to the following conditions:
  13 *
  14 * The above copyright notice and this permission notice shall be included in
  15 * all copies or substantial portions of the Software.
  16 *
  17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23 * THE SOFTWARE.
  24 */
  25
  26#include "qemu/osdep.h"
  27#include "qemu/job.h"
  28#include "qapi/qapi-commands-job.h"
  29#include "qapi/error.h"
  30#include "trace/trace-root.h"
  31
  32/* Get a job using its ID and acquire its AioContext */
  33static Job *find_job(const char *id, AioContext **aio_context, Error **errp)
  34{
  35    Job *job;
  36
  37    *aio_context = NULL;
  38
  39    job = job_get(id);
  40    if (!job) {
  41        error_setg(errp, "Job not found");
  42        return NULL;
  43    }
  44
  45    *aio_context = job->aio_context;
  46    aio_context_acquire(*aio_context);
  47
  48    return job;
  49}
  50
  51void qmp_job_cancel(const char *id, Error **errp)
  52{
  53    AioContext *aio_context;
  54    Job *job = find_job(id, &aio_context, errp);
  55
  56    if (!job) {
  57        return;
  58    }
  59
  60    trace_qmp_job_cancel(job);
  61    job_user_cancel(job, true, errp);
  62    aio_context_release(aio_context);
  63}
  64
  65void qmp_job_pause(const char *id, Error **errp)
  66{
  67    AioContext *aio_context;
  68    Job *job = find_job(id, &aio_context, errp);
  69
  70    if (!job) {
  71        return;
  72    }
  73
  74    trace_qmp_job_pause(job);
  75    job_user_pause(job, errp);
  76    aio_context_release(aio_context);
  77}
  78
  79void qmp_job_resume(const char *id, Error **errp)
  80{
  81    AioContext *aio_context;
  82    Job *job = find_job(id, &aio_context, errp);
  83
  84    if (!job) {
  85        return;
  86    }
  87
  88    trace_qmp_job_resume(job);
  89    job_user_resume(job, errp);
  90    aio_context_release(aio_context);
  91}
  92
  93void qmp_job_complete(const char *id, Error **errp)
  94{
  95    AioContext *aio_context;
  96    Job *job = find_job(id, &aio_context, errp);
  97
  98    if (!job) {
  99        return;
 100    }
 101
 102    trace_qmp_job_complete(job);
 103    job_complete(job, errp);
 104    aio_context_release(aio_context);
 105}
 106
 107void qmp_job_finalize(const char *id, Error **errp)
 108{
 109    AioContext *aio_context;
 110    Job *job = find_job(id, &aio_context, errp);
 111
 112    if (!job) {
 113        return;
 114    }
 115
 116    trace_qmp_job_finalize(job);
 117    job_ref(job);
 118    job_finalize(job, errp);
 119
 120    /*
 121     * Job's context might have changed via job_finalize (and job_txn_apply
 122     * automatically acquires the new one), so make sure we release the correct
 123     * one.
 124     */
 125    aio_context = job->aio_context;
 126    job_unref(job);
 127    aio_context_release(aio_context);
 128}
 129
 130void qmp_job_dismiss(const char *id, Error **errp)
 131{
 132    AioContext *aio_context;
 133    Job *job = find_job(id, &aio_context, errp);
 134
 135    if (!job) {
 136        return;
 137    }
 138
 139    trace_qmp_job_dismiss(job);
 140    job_dismiss(&job, errp);
 141    aio_context_release(aio_context);
 142}
 143
 144static JobInfo *job_query_single(Job *job, Error **errp)
 145{
 146    JobInfo *info;
 147    uint64_t progress_current;
 148    uint64_t progress_total;
 149
 150    assert(!job_is_internal(job));
 151    progress_get_snapshot(&job->progress, &progress_current,
 152                          &progress_total);
 153
 154    info = g_new(JobInfo, 1);
 155    *info = (JobInfo) {
 156        .id                 = g_strdup(job->id),
 157        .type               = job_type(job),
 158        .status             = job->status,
 159        .current_progress   = progress_current,
 160        .total_progress     = progress_total,
 161        .has_error          = !!job->err,
 162        .error              = job->err ? \
 163                              g_strdup(error_get_pretty(job->err)) : NULL,
 164    };
 165
 166    return info;
 167}
 168
 169JobInfoList *qmp_query_jobs(Error **errp)
 170{
 171    JobInfoList *head = NULL, **tail = &head;
 172    Job *job;
 173
 174    for (job = job_next(NULL); job; job = job_next(job)) {
 175        JobInfo *value;
 176        AioContext *aio_context;
 177
 178        if (job_is_internal(job)) {
 179            continue;
 180        }
 181        aio_context = job->aio_context;
 182        aio_context_acquire(aio_context);
 183        value = job_query_single(job, errp);
 184        aio_context_release(aio_context);
 185        if (!value) {
 186            qapi_free_JobInfoList(head);
 187            return NULL;
 188        }
 189        QAPI_LIST_APPEND(tail, value);
 190    }
 191
 192    return head;
 193}
 194