]> git.proxmox.com Git - mirror_qemu.git/blame - block/monitor/block-hmp-cmds.c
monitor/hmp: move hmp_snapshot_* to block-hmp-cmds.c
[mirror_qemu.git] / block / monitor / block-hmp-cmds.c
CommitLineData
6f338c34 1/*
a2dde2f2 2 * Blockdev HMP commands
6f338c34 3 *
fce2b91f
ML
4 * Authors:
5 * Anthony Liguori <aliguori@us.ibm.com>
6 *
a1edae27
ML
7 * Copyright (c) 2003-2008 Fabrice Bellard
8 *
fce2b91f
ML
9 * This work is licensed under the terms of the GNU GPL, version 2.
10 * See the COPYING file in the top-level directory.
11 * Contributions after 2012-01-13 are licensed under the terms of the
12 * GNU GPL, version 2 or (at your option) any later version.
a1edae27
ML
13 *
14 * This file incorporates work covered by the following copyright and
15 * permission notice:
16 *
17 * Copyright (c) 2003-2008 Fabrice Bellard
6f338c34
AL
18 *
19 * Permission is hereby granted, free of charge, to any person obtaining a copy
20 * of this software and associated documentation files (the "Software"), to deal
21 * in the Software without restriction, including without limitation the rights
22 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23 * copies of the Software, and to permit persons to whom the Software is
24 * furnished to do so, subject to the following conditions:
25 *
26 * The above copyright notice and this permission notice shall be included in
27 * all copies or substantial portions of the Software.
28 *
29 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
32 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 * THE SOFTWARE.
36 */
37
d38ea87a 38#include "qemu/osdep.h"
1559e0d4 39#include "hw/boards.h"
b9fe8a7a 40#include "sysemu/block-backend.h"
9c17d615 41#include "sysemu/blockdev.h"
a1edae27 42#include "qapi/qapi-commands-block.h"
452fcdbc 43#include "qapi/qmp/qdict.h"
c4f26c9f 44#include "qapi/error.h"
0932e3f2 45#include "qapi/qmp/qerror.h"
1de7afc9 46#include "qemu/config-file.h"
922a01a0 47#include "qemu/option.h"
9c17d615 48#include "sysemu/sysemu.h"
83c9089e 49#include "monitor/monitor.h"
0932e3f2 50#include "monitor/hmp.h"
abb21ac3 51#include "block/block_int.h"
a2dde2f2 52#include "block/block-hmp-cmds.h"
6f338c34 53
6700d3d6 54void hmp_drive_add(Monitor *mon, const QDict *qdict)
6f338c34 55{
c4f26c9f 56 Error *err = NULL;
751c6a17 57 DriveInfo *dinfo;
9dfd7c7a 58 QemuOpts *opts;
0056ae24 59 MachineClass *mc;
6700d3d6
ML
60 const char *optstr = qdict_get_str(qdict, "opts");
61 bool node = qdict_get_try_bool(qdict, "node", false);
62
63 if (node) {
64 hmp_drive_add_node(mon, optstr);
65 return;
66 }
6f338c34 67
2292ddae 68 opts = drive_def(optstr);
9dfd7c7a 69 if (!opts)
6700d3d6 70 return;
6f338c34 71
0056ae24 72 mc = MACHINE_GET_CLASS(current_machine);
c4f26c9f 73 dinfo = drive_new(opts, mc->block_default_type, &err);
ab638171 74 if (err) {
c4f26c9f 75 error_report_err(err);
9dfd7c7a 76 qemu_opts_del(opts);
6700d3d6 77 goto err;
abb21ac3 78 }
dd97aa8a 79
dd97aa8a 80 if (!dinfo) {
6700d3d6 81 return;
dd97aa8a 82 }
dd97aa8a 83
4dbd84e2 84 switch (dinfo->type) {
dd97aa8a
AG
85 case IF_NONE:
86 monitor_printf(mon, "OK\n");
87 break;
88 default:
f51074cd
MA
89 monitor_printf(mon, "Can't hot-add drive to type %d\n", dinfo->type);
90 goto err;
dd97aa8a
AG
91 }
92 return;
93
94err:
95 if (dinfo) {
efaa7c4e
HR
96 BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
97 monitor_remove_blk(blk);
98 blk_unref(blk);
dd97aa8a 99 }
dd97aa8a 100}
a1edae27
ML
101
102void hmp_drive_del(Monitor *mon, const QDict *qdict)
103{
104 const char *id = qdict_get_str(qdict, "id");
105 BlockBackend *blk;
106 BlockDriverState *bs;
107 AioContext *aio_context;
108 Error *local_err = NULL;
109
110 bs = bdrv_find_node(id);
111 if (bs) {
112 qmp_blockdev_del(id, &local_err);
113 if (local_err) {
114 error_report_err(local_err);
115 }
116 return;
117 }
118
119 blk = blk_by_name(id);
120 if (!blk) {
121 error_report("Device '%s' not found", id);
122 return;
123 }
124
125 if (!blk_legacy_dinfo(blk)) {
126 error_report("Deleting device added with blockdev-add"
127 " is not supported");
128 return;
129 }
130
131 aio_context = blk_get_aio_context(blk);
132 aio_context_acquire(aio_context);
133
134 bs = blk_bs(blk);
135 if (bs) {
136 if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &local_err)) {
137 error_report_err(local_err);
138 aio_context_release(aio_context);
139 return;
140 }
141
142 blk_remove_bs(blk);
143 }
144
145 /* Make the BlockBackend and the attached BlockDriverState anonymous */
146 monitor_remove_blk(blk);
147
148 /*
149 * If this BlockBackend has a device attached to it, its refcount will be
150 * decremented when the device is removed; otherwise we have to do so here.
151 */
152 if (blk_get_attached_dev(blk)) {
153 /* Further I/O must not pause the guest */
154 blk_set_on_error(blk, BLOCKDEV_ON_ERROR_REPORT,
155 BLOCKDEV_ON_ERROR_REPORT);
156 } else {
157 blk_unref(blk);
158 }
159
160 aio_context_release(aio_context);
161}
162
163void hmp_commit(Monitor *mon, const QDict *qdict)
164{
165 const char *device = qdict_get_str(qdict, "device");
166 BlockBackend *blk;
167 int ret;
168
169 if (!strcmp(device, "all")) {
170 ret = blk_commit_all();
171 } else {
172 BlockDriverState *bs;
173 AioContext *aio_context;
174
175 blk = blk_by_name(device);
176 if (!blk) {
177 error_report("Device '%s' not found", device);
178 return;
179 }
180 if (!blk_is_available(blk)) {
181 error_report("Device '%s' has no medium", device);
182 return;
183 }
184
185 bs = blk_bs(blk);
186 aio_context = bdrv_get_aio_context(bs);
187 aio_context_acquire(aio_context);
188
189 ret = bdrv_commit(bs);
190
191 aio_context_release(aio_context);
192 }
193 if (ret < 0) {
194 error_report("'commit' error for '%s': %s", device, strerror(-ret));
195 }
196}
0932e3f2
ML
197
198void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
199{
200 const char *filename = qdict_get_str(qdict, "target");
201 const char *format = qdict_get_try_str(qdict, "format");
202 bool reuse = qdict_get_try_bool(qdict, "reuse", false);
203 bool full = qdict_get_try_bool(qdict, "full", false);
204 Error *err = NULL;
205 DriveMirror mirror = {
206 .device = (char *)qdict_get_str(qdict, "device"),
207 .target = (char *)filename,
208 .has_format = !!format,
209 .format = (char *)format,
210 .sync = full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
211 .has_mode = true,
212 .mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS,
213 .unmap = true,
214 };
215
216 if (!filename) {
217 error_setg(&err, QERR_MISSING_PARAMETER, "target");
218 hmp_handle_error(mon, err);
219 return;
220 }
221 qmp_drive_mirror(&mirror, &err);
222 hmp_handle_error(mon, err);
223}
224
225void hmp_drive_backup(Monitor *mon, const QDict *qdict)
226{
227 const char *device = qdict_get_str(qdict, "device");
228 const char *filename = qdict_get_str(qdict, "target");
229 const char *format = qdict_get_try_str(qdict, "format");
230 bool reuse = qdict_get_try_bool(qdict, "reuse", false);
231 bool full = qdict_get_try_bool(qdict, "full", false);
232 bool compress = qdict_get_try_bool(qdict, "compress", false);
233 Error *err = NULL;
234 DriveBackup backup = {
235 .device = (char *)device,
236 .target = (char *)filename,
237 .has_format = !!format,
238 .format = (char *)format,
239 .sync = full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
240 .has_mode = true,
241 .mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS,
242 .has_compress = !!compress,
243 .compress = compress,
244 };
245
246 if (!filename) {
247 error_setg(&err, QERR_MISSING_PARAMETER, "target");
248 hmp_handle_error(mon, err);
249 return;
250 }
251
252 qmp_drive_backup(&backup, &err);
253 hmp_handle_error(mon, err);
254}
6b7fbf61
ML
255
256void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict)
257{
258 Error *error = NULL;
259 const char *device = qdict_get_str(qdict, "device");
260 int64_t value = qdict_get_int(qdict, "speed");
261
262 qmp_block_job_set_speed(device, value, &error);
263
264 hmp_handle_error(mon, error);
265}
266
267void hmp_block_job_cancel(Monitor *mon, const QDict *qdict)
268{
269 Error *error = NULL;
270 const char *device = qdict_get_str(qdict, "device");
271 bool force = qdict_get_try_bool(qdict, "force", false);
272
273 qmp_block_job_cancel(device, true, force, &error);
274
275 hmp_handle_error(mon, error);
276}
277
278void hmp_block_job_pause(Monitor *mon, const QDict *qdict)
279{
280 Error *error = NULL;
281 const char *device = qdict_get_str(qdict, "device");
282
283 qmp_block_job_pause(device, &error);
284
285 hmp_handle_error(mon, error);
286}
287
288void hmp_block_job_resume(Monitor *mon, const QDict *qdict)
289{
290 Error *error = NULL;
291 const char *device = qdict_get_str(qdict, "device");
292
293 qmp_block_job_resume(device, &error);
294
295 hmp_handle_error(mon, error);
296}
297
298void hmp_block_job_complete(Monitor *mon, const QDict *qdict)
299{
300 Error *error = NULL;
301 const char *device = qdict_get_str(qdict, "device");
302
303 qmp_block_job_complete(device, &error);
304
305 hmp_handle_error(mon, error);
306}
fce2b91f
ML
307
308void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
309{
310 const char *device = qdict_get_str(qdict, "device");
311 const char *filename = qdict_get_try_str(qdict, "snapshot-file");
312 const char *format = qdict_get_try_str(qdict, "format");
313 bool reuse = qdict_get_try_bool(qdict, "reuse", false);
314 enum NewImageMode mode;
315 Error *err = NULL;
316
317 if (!filename) {
318 /*
319 * In the future, if 'snapshot-file' is not specified, the snapshot
320 * will be taken internally. Today it's actually required.
321 */
322 error_setg(&err, QERR_MISSING_PARAMETER, "snapshot-file");
323 hmp_handle_error(mon, err);
324 return;
325 }
326
327 mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS;
328 qmp_blockdev_snapshot_sync(true, device, false, NULL,
329 filename, false, NULL,
330 !!format, format,
331 true, mode, &err);
332 hmp_handle_error(mon, err);
333}
334
335void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict)
336{
337 const char *device = qdict_get_str(qdict, "device");
338 const char *name = qdict_get_str(qdict, "name");
339 Error *err = NULL;
340
341 qmp_blockdev_snapshot_internal_sync(device, name, &err);
342 hmp_handle_error(mon, err);
343}
344
345void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict)
346{
347 const char *device = qdict_get_str(qdict, "device");
348 const char *name = qdict_get_str(qdict, "name");
349 const char *id = qdict_get_try_str(qdict, "id");
350 Error *err = NULL;
351
352 qmp_blockdev_snapshot_delete_internal_sync(device, !!id, id,
353 true, name, &err);
354 hmp_handle_error(mon, err);
355}