xref: /openbmc/qemu/job-qmp.c (revision a00cfed0ed9c366a383fe39c2d283362ebaaefd3)
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 */
33  static 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  
51  void 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  
65  void 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  
79  void 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  
93  void 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  
107  void 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  
130  void 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  
144  static JobInfo *job_query_single(Job *job, Error **errp)
145  {
146      JobInfo *info;
147  
148      assert(!job_is_internal(job));
149  
150      info = g_new(JobInfo, 1);
151      *info = (JobInfo) {
152          .id                 = g_strdup(job->id),
153          .type               = job_type(job),
154          .status             = job->status,
155          .current_progress   = job->progress.current,
156          .total_progress     = job->progress.total,
157          .has_error          = !!job->err,
158          .error              = job->err ? \
159                                g_strdup(error_get_pretty(job->err)) : NULL,
160      };
161  
162      return info;
163  }
164  
165  JobInfoList *qmp_query_jobs(Error **errp)
166  {
167      JobInfoList *head = NULL, **tail = &head;
168      Job *job;
169  
170      for (job = job_next(NULL); job; job = job_next(job)) {
171          JobInfo *value;
172          AioContext *aio_context;
173  
174          if (job_is_internal(job)) {
175              continue;
176          }
177          aio_context = job->aio_context;
178          aio_context_acquire(aio_context);
179          value = job_query_single(job, errp);
180          aio_context_release(aio_context);
181          if (!value) {
182              qapi_free_JobInfoList(head);
183              return NULL;
184          }
185          QAPI_LIST_APPEND(tail, value);
186      }
187  
188      return head;
189  }
190