root / blockdev.c @ 95b5edcd
History | View | Annotate | Download (21 kB)
1 | 666daa68 | Markus Armbruster | /*
|
---|---|---|---|
2 | 666daa68 | Markus Armbruster | * QEMU host block devices
|
3 | 666daa68 | Markus Armbruster | *
|
4 | 666daa68 | Markus Armbruster | * Copyright (c) 2003-2008 Fabrice Bellard
|
5 | 666daa68 | Markus Armbruster | *
|
6 | 666daa68 | Markus Armbruster | * This work is licensed under the terms of the GNU GPL, version 2 or
|
7 | 666daa68 | Markus Armbruster | * later. See the COPYING file in the top-level directory.
|
8 | 666daa68 | Markus Armbruster | */
|
9 | 666daa68 | Markus Armbruster | |
10 | 666daa68 | Markus Armbruster | #include "block.h" |
11 | 666daa68 | Markus Armbruster | #include "blockdev.h" |
12 | 666daa68 | Markus Armbruster | #include "monitor.h" |
13 | 666daa68 | Markus Armbruster | #include "qerror.h" |
14 | 666daa68 | Markus Armbruster | #include "qemu-option.h" |
15 | 666daa68 | Markus Armbruster | #include "qemu-config.h" |
16 | 666daa68 | Markus Armbruster | #include "sysemu.h" |
17 | 9063f814 | Ryan Harper | #include "hw/qdev.h" |
18 | 9063f814 | Ryan Harper | #include "block_int.h" |
19 | 666daa68 | Markus Armbruster | |
20 | c9b62a7e | Markus Armbruster | static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
|
21 | 666daa68 | Markus Armbruster | |
22 | 1960966d | Markus Armbruster | static const char *const if_name[IF_COUNT] = { |
23 | 1960966d | Markus Armbruster | [IF_NONE] = "none",
|
24 | 1960966d | Markus Armbruster | [IF_IDE] = "ide",
|
25 | 1960966d | Markus Armbruster | [IF_SCSI] = "scsi",
|
26 | 1960966d | Markus Armbruster | [IF_FLOPPY] = "floppy",
|
27 | 1960966d | Markus Armbruster | [IF_PFLASH] = "pflash",
|
28 | 1960966d | Markus Armbruster | [IF_MTD] = "mtd",
|
29 | 1960966d | Markus Armbruster | [IF_SD] = "sd",
|
30 | 1960966d | Markus Armbruster | [IF_VIRTIO] = "virtio",
|
31 | 1960966d | Markus Armbruster | [IF_XEN] = "xen",
|
32 | 1960966d | Markus Armbruster | }; |
33 | 1960966d | Markus Armbruster | |
34 | 1960966d | Markus Armbruster | static const int if_max_devs[IF_COUNT] = { |
35 | 27d6bf40 | Markus Armbruster | /*
|
36 | 27d6bf40 | Markus Armbruster | * Do not change these numbers! They govern how drive option
|
37 | 27d6bf40 | Markus Armbruster | * index maps to unit and bus. That mapping is ABI.
|
38 | 27d6bf40 | Markus Armbruster | *
|
39 | 27d6bf40 | Markus Armbruster | * All controllers used to imlement if=T drives need to support
|
40 | 27d6bf40 | Markus Armbruster | * if_max_devs[T] units, for any T with if_max_devs[T] != 0.
|
41 | 27d6bf40 | Markus Armbruster | * Otherwise, some index values map to "impossible" bus, unit
|
42 | 27d6bf40 | Markus Armbruster | * values.
|
43 | 27d6bf40 | Markus Armbruster | *
|
44 | 27d6bf40 | Markus Armbruster | * For instance, if you change [IF_SCSI] to 255, -drive
|
45 | 27d6bf40 | Markus Armbruster | * if=scsi,index=12 no longer means bus=1,unit=5, but
|
46 | 27d6bf40 | Markus Armbruster | * bus=0,unit=12. With an lsi53c895a controller (7 units max),
|
47 | 27d6bf40 | Markus Armbruster | * the drive can't be set up. Regression.
|
48 | 27d6bf40 | Markus Armbruster | */
|
49 | 27d6bf40 | Markus Armbruster | [IF_IDE] = 2,
|
50 | 27d6bf40 | Markus Armbruster | [IF_SCSI] = 7,
|
51 | 1960966d | Markus Armbruster | }; |
52 | 1960966d | Markus Armbruster | |
53 | 14bafc54 | Markus Armbruster | /*
|
54 | 14bafc54 | Markus Armbruster | * We automatically delete the drive when a device using it gets
|
55 | 14bafc54 | Markus Armbruster | * unplugged. Questionable feature, but we can't just drop it.
|
56 | 14bafc54 | Markus Armbruster | * Device models call blockdev_mark_auto_del() to schedule the
|
57 | 14bafc54 | Markus Armbruster | * automatic deletion, and generic qdev code calls blockdev_auto_del()
|
58 | 14bafc54 | Markus Armbruster | * when deletion is actually safe.
|
59 | 14bafc54 | Markus Armbruster | */
|
60 | 14bafc54 | Markus Armbruster | void blockdev_mark_auto_del(BlockDriverState *bs)
|
61 | 14bafc54 | Markus Armbruster | { |
62 | 14bafc54 | Markus Armbruster | DriveInfo *dinfo = drive_get_by_blockdev(bs); |
63 | 14bafc54 | Markus Armbruster | |
64 | 0fc0f1fa | Ryan Harper | if (dinfo) {
|
65 | 0fc0f1fa | Ryan Harper | dinfo->auto_del = 1;
|
66 | 0fc0f1fa | Ryan Harper | } |
67 | 14bafc54 | Markus Armbruster | } |
68 | 14bafc54 | Markus Armbruster | |
69 | 14bafc54 | Markus Armbruster | void blockdev_auto_del(BlockDriverState *bs)
|
70 | 14bafc54 | Markus Armbruster | { |
71 | 14bafc54 | Markus Armbruster | DriveInfo *dinfo = drive_get_by_blockdev(bs); |
72 | 14bafc54 | Markus Armbruster | |
73 | 0fc0f1fa | Ryan Harper | if (dinfo && dinfo->auto_del) {
|
74 | 84fb3925 | Marcelo Tosatti | drive_put_ref(dinfo); |
75 | 14bafc54 | Markus Armbruster | } |
76 | 14bafc54 | Markus Armbruster | } |
77 | 14bafc54 | Markus Armbruster | |
78 | 505a7fb1 | Markus Armbruster | static int drive_index_to_bus_id(BlockInterfaceType type, int index) |
79 | 505a7fb1 | Markus Armbruster | { |
80 | 505a7fb1 | Markus Armbruster | int max_devs = if_max_devs[type];
|
81 | 505a7fb1 | Markus Armbruster | return max_devs ? index / max_devs : 0; |
82 | 505a7fb1 | Markus Armbruster | } |
83 | 505a7fb1 | Markus Armbruster | |
84 | 505a7fb1 | Markus Armbruster | static int drive_index_to_unit_id(BlockInterfaceType type, int index) |
85 | 505a7fb1 | Markus Armbruster | { |
86 | 505a7fb1 | Markus Armbruster | int max_devs = if_max_devs[type];
|
87 | 505a7fb1 | Markus Armbruster | return max_devs ? index % max_devs : index;
|
88 | 505a7fb1 | Markus Armbruster | } |
89 | 505a7fb1 | Markus Armbruster | |
90 | 2292ddae | Markus Armbruster | QemuOpts *drive_def(const char *optstr) |
91 | 2292ddae | Markus Armbruster | { |
92 | 2292ddae | Markus Armbruster | return qemu_opts_parse(qemu_find_opts("drive"), optstr, 0); |
93 | 2292ddae | Markus Armbruster | } |
94 | 2292ddae | Markus Armbruster | |
95 | 2292ddae | Markus Armbruster | QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file, |
96 | 5645b0f4 | Markus Armbruster | const char *optstr) |
97 | 666daa68 | Markus Armbruster | { |
98 | 666daa68 | Markus Armbruster | QemuOpts *opts; |
99 | 2292ddae | Markus Armbruster | char buf[32]; |
100 | 666daa68 | Markus Armbruster | |
101 | 2292ddae | Markus Armbruster | opts = drive_def(optstr); |
102 | 666daa68 | Markus Armbruster | if (!opts) {
|
103 | 666daa68 | Markus Armbruster | return NULL; |
104 | 666daa68 | Markus Armbruster | } |
105 | 2292ddae | Markus Armbruster | if (type != IF_DEFAULT) {
|
106 | 2292ddae | Markus Armbruster | qemu_opt_set(opts, "if", if_name[type]);
|
107 | 2292ddae | Markus Armbruster | } |
108 | 2292ddae | Markus Armbruster | if (index >= 0) { |
109 | 2292ddae | Markus Armbruster | snprintf(buf, sizeof(buf), "%d", index); |
110 | 2292ddae | Markus Armbruster | qemu_opt_set(opts, "index", buf);
|
111 | 2292ddae | Markus Armbruster | } |
112 | 666daa68 | Markus Armbruster | if (file)
|
113 | 666daa68 | Markus Armbruster | qemu_opt_set(opts, "file", file);
|
114 | 666daa68 | Markus Armbruster | return opts;
|
115 | 666daa68 | Markus Armbruster | } |
116 | 666daa68 | Markus Armbruster | |
117 | 666daa68 | Markus Armbruster | DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit) |
118 | 666daa68 | Markus Armbruster | { |
119 | 666daa68 | Markus Armbruster | DriveInfo *dinfo; |
120 | 666daa68 | Markus Armbruster | |
121 | 666daa68 | Markus Armbruster | /* seek interface, bus and unit */
|
122 | 666daa68 | Markus Armbruster | |
123 | 666daa68 | Markus Armbruster | QTAILQ_FOREACH(dinfo, &drives, next) { |
124 | 666daa68 | Markus Armbruster | if (dinfo->type == type &&
|
125 | 666daa68 | Markus Armbruster | dinfo->bus == bus && |
126 | 666daa68 | Markus Armbruster | dinfo->unit == unit) |
127 | 666daa68 | Markus Armbruster | return dinfo;
|
128 | 666daa68 | Markus Armbruster | } |
129 | 666daa68 | Markus Armbruster | |
130 | 666daa68 | Markus Armbruster | return NULL; |
131 | 666daa68 | Markus Armbruster | } |
132 | 666daa68 | Markus Armbruster | |
133 | f1bd51ac | Markus Armbruster | DriveInfo *drive_get_by_index(BlockInterfaceType type, int index)
|
134 | f1bd51ac | Markus Armbruster | { |
135 | f1bd51ac | Markus Armbruster | return drive_get(type,
|
136 | f1bd51ac | Markus Armbruster | drive_index_to_bus_id(type, index), |
137 | f1bd51ac | Markus Armbruster | drive_index_to_unit_id(type, index)); |
138 | f1bd51ac | Markus Armbruster | } |
139 | f1bd51ac | Markus Armbruster | |
140 | 666daa68 | Markus Armbruster | int drive_get_max_bus(BlockInterfaceType type)
|
141 | 666daa68 | Markus Armbruster | { |
142 | 666daa68 | Markus Armbruster | int max_bus;
|
143 | 666daa68 | Markus Armbruster | DriveInfo *dinfo; |
144 | 666daa68 | Markus Armbruster | |
145 | 666daa68 | Markus Armbruster | max_bus = -1;
|
146 | 666daa68 | Markus Armbruster | QTAILQ_FOREACH(dinfo, &drives, next) { |
147 | 666daa68 | Markus Armbruster | if(dinfo->type == type &&
|
148 | 666daa68 | Markus Armbruster | dinfo->bus > max_bus) |
149 | 666daa68 | Markus Armbruster | max_bus = dinfo->bus; |
150 | 666daa68 | Markus Armbruster | } |
151 | 666daa68 | Markus Armbruster | return max_bus;
|
152 | 666daa68 | Markus Armbruster | } |
153 | 666daa68 | Markus Armbruster | |
154 | 13839974 | Markus Armbruster | /* Get a block device. This should only be used for single-drive devices
|
155 | 13839974 | Markus Armbruster | (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
|
156 | 13839974 | Markus Armbruster | appropriate bus. */
|
157 | 13839974 | Markus Armbruster | DriveInfo *drive_get_next(BlockInterfaceType type) |
158 | 13839974 | Markus Armbruster | { |
159 | 13839974 | Markus Armbruster | static int next_block_unit[IF_COUNT]; |
160 | 13839974 | Markus Armbruster | |
161 | 13839974 | Markus Armbruster | return drive_get(type, 0, next_block_unit[type]++); |
162 | 13839974 | Markus Armbruster | } |
163 | 13839974 | Markus Armbruster | |
164 | e4700e59 | Markus Armbruster | DriveInfo *drive_get_by_blockdev(BlockDriverState *bs) |
165 | 666daa68 | Markus Armbruster | { |
166 | 666daa68 | Markus Armbruster | DriveInfo *dinfo; |
167 | 666daa68 | Markus Armbruster | |
168 | 666daa68 | Markus Armbruster | QTAILQ_FOREACH(dinfo, &drives, next) { |
169 | e4700e59 | Markus Armbruster | if (dinfo->bdrv == bs) {
|
170 | e4700e59 | Markus Armbruster | return dinfo;
|
171 | e4700e59 | Markus Armbruster | } |
172 | 666daa68 | Markus Armbruster | } |
173 | e4700e59 | Markus Armbruster | return NULL; |
174 | 666daa68 | Markus Armbruster | } |
175 | 666daa68 | Markus Armbruster | |
176 | 666daa68 | Markus Armbruster | static void bdrv_format_print(void *opaque, const char *name) |
177 | 666daa68 | Markus Armbruster | { |
178 | 807105a7 | Markus Armbruster | error_printf(" %s", name);
|
179 | 666daa68 | Markus Armbruster | } |
180 | 666daa68 | Markus Armbruster | |
181 | 84fb3925 | Marcelo Tosatti | static void drive_uninit(DriveInfo *dinfo) |
182 | 666daa68 | Markus Armbruster | { |
183 | 666daa68 | Markus Armbruster | qemu_opts_del(dinfo->opts); |
184 | 666daa68 | Markus Armbruster | bdrv_delete(dinfo->bdrv); |
185 | 2753d4a5 | Markus Armbruster | qemu_free(dinfo->id); |
186 | 666daa68 | Markus Armbruster | QTAILQ_REMOVE(&drives, dinfo, next); |
187 | 666daa68 | Markus Armbruster | qemu_free(dinfo); |
188 | 666daa68 | Markus Armbruster | } |
189 | 666daa68 | Markus Armbruster | |
190 | 84fb3925 | Marcelo Tosatti | void drive_put_ref(DriveInfo *dinfo)
|
191 | 84fb3925 | Marcelo Tosatti | { |
192 | 84fb3925 | Marcelo Tosatti | assert(dinfo->refcount); |
193 | 84fb3925 | Marcelo Tosatti | if (--dinfo->refcount == 0) { |
194 | 84fb3925 | Marcelo Tosatti | drive_uninit(dinfo); |
195 | 84fb3925 | Marcelo Tosatti | } |
196 | 84fb3925 | Marcelo Tosatti | } |
197 | 84fb3925 | Marcelo Tosatti | |
198 | 84fb3925 | Marcelo Tosatti | void drive_get_ref(DriveInfo *dinfo)
|
199 | 84fb3925 | Marcelo Tosatti | { |
200 | 84fb3925 | Marcelo Tosatti | dinfo->refcount++; |
201 | 84fb3925 | Marcelo Tosatti | } |
202 | 84fb3925 | Marcelo Tosatti | |
203 | 666daa68 | Markus Armbruster | static int parse_block_error_action(const char *buf, int is_read) |
204 | 666daa68 | Markus Armbruster | { |
205 | 666daa68 | Markus Armbruster | if (!strcmp(buf, "ignore")) { |
206 | 666daa68 | Markus Armbruster | return BLOCK_ERR_IGNORE;
|
207 | 666daa68 | Markus Armbruster | } else if (!is_read && !strcmp(buf, "enospc")) { |
208 | 666daa68 | Markus Armbruster | return BLOCK_ERR_STOP_ENOSPC;
|
209 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "stop")) { |
210 | 666daa68 | Markus Armbruster | return BLOCK_ERR_STOP_ANY;
|
211 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "report")) { |
212 | 666daa68 | Markus Armbruster | return BLOCK_ERR_REPORT;
|
213 | 666daa68 | Markus Armbruster | } else {
|
214 | 807105a7 | Markus Armbruster | error_report("'%s' invalid %s error action",
|
215 | 807105a7 | Markus Armbruster | buf, is_read ? "read" : "write"); |
216 | 666daa68 | Markus Armbruster | return -1; |
217 | 666daa68 | Markus Armbruster | } |
218 | 666daa68 | Markus Armbruster | } |
219 | 666daa68 | Markus Armbruster | |
220 | 319ae529 | Markus Armbruster | DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
|
221 | 666daa68 | Markus Armbruster | { |
222 | 666daa68 | Markus Armbruster | const char *buf; |
223 | 666daa68 | Markus Armbruster | const char *file = NULL; |
224 | 666daa68 | Markus Armbruster | char devname[128]; |
225 | 666daa68 | Markus Armbruster | const char *serial; |
226 | 666daa68 | Markus Armbruster | const char *mediastr = ""; |
227 | 666daa68 | Markus Armbruster | BlockInterfaceType type; |
228 | 666daa68 | Markus Armbruster | enum { MEDIA_DISK, MEDIA_CDROM } media;
|
229 | 666daa68 | Markus Armbruster | int bus_id, unit_id;
|
230 | 666daa68 | Markus Armbruster | int cyls, heads, secs, translation;
|
231 | 666daa68 | Markus Armbruster | BlockDriver *drv = NULL;
|
232 | 666daa68 | Markus Armbruster | int max_devs;
|
233 | 666daa68 | Markus Armbruster | int index;
|
234 | 666daa68 | Markus Armbruster | int ro = 0; |
235 | 666daa68 | Markus Armbruster | int bdrv_flags = 0; |
236 | 666daa68 | Markus Armbruster | int on_read_error, on_write_error;
|
237 | 666daa68 | Markus Armbruster | const char *devaddr; |
238 | 666daa68 | Markus Armbruster | DriveInfo *dinfo; |
239 | 666daa68 | Markus Armbruster | int snapshot = 0; |
240 | 666daa68 | Markus Armbruster | int ret;
|
241 | 666daa68 | Markus Armbruster | |
242 | 666daa68 | Markus Armbruster | translation = BIOS_ATA_TRANSLATION_AUTO; |
243 | 666daa68 | Markus Armbruster | |
244 | 666daa68 | Markus Armbruster | if (default_to_scsi) {
|
245 | 666daa68 | Markus Armbruster | type = IF_SCSI; |
246 | 666daa68 | Markus Armbruster | pstrcpy(devname, sizeof(devname), "scsi"); |
247 | 666daa68 | Markus Armbruster | } else {
|
248 | 666daa68 | Markus Armbruster | type = IF_IDE; |
249 | 666daa68 | Markus Armbruster | pstrcpy(devname, sizeof(devname), "ide"); |
250 | 666daa68 | Markus Armbruster | } |
251 | 666daa68 | Markus Armbruster | media = MEDIA_DISK; |
252 | 666daa68 | Markus Armbruster | |
253 | 666daa68 | Markus Armbruster | /* extract parameters */
|
254 | 666daa68 | Markus Armbruster | bus_id = qemu_opt_get_number(opts, "bus", 0); |
255 | 666daa68 | Markus Armbruster | unit_id = qemu_opt_get_number(opts, "unit", -1); |
256 | 666daa68 | Markus Armbruster | index = qemu_opt_get_number(opts, "index", -1); |
257 | 666daa68 | Markus Armbruster | |
258 | 666daa68 | Markus Armbruster | cyls = qemu_opt_get_number(opts, "cyls", 0); |
259 | 666daa68 | Markus Armbruster | heads = qemu_opt_get_number(opts, "heads", 0); |
260 | 666daa68 | Markus Armbruster | secs = qemu_opt_get_number(opts, "secs", 0); |
261 | 666daa68 | Markus Armbruster | |
262 | 666daa68 | Markus Armbruster | snapshot = qemu_opt_get_bool(opts, "snapshot", 0); |
263 | 666daa68 | Markus Armbruster | ro = qemu_opt_get_bool(opts, "readonly", 0); |
264 | 666daa68 | Markus Armbruster | |
265 | 666daa68 | Markus Armbruster | file = qemu_opt_get(opts, "file");
|
266 | 666daa68 | Markus Armbruster | serial = qemu_opt_get(opts, "serial");
|
267 | 666daa68 | Markus Armbruster | |
268 | 666daa68 | Markus Armbruster | if ((buf = qemu_opt_get(opts, "if")) != NULL) { |
269 | 666daa68 | Markus Armbruster | pstrcpy(devname, sizeof(devname), buf);
|
270 | 1960966d | Markus Armbruster | for (type = 0; type < IF_COUNT && strcmp(buf, if_name[type]); type++) |
271 | 1960966d | Markus Armbruster | ; |
272 | 1960966d | Markus Armbruster | if (type == IF_COUNT) {
|
273 | 807105a7 | Markus Armbruster | error_report("unsupported bus type '%s'", buf);
|
274 | 666daa68 | Markus Armbruster | return NULL; |
275 | 666daa68 | Markus Armbruster | } |
276 | 666daa68 | Markus Armbruster | } |
277 | 1960966d | Markus Armbruster | max_devs = if_max_devs[type]; |
278 | 666daa68 | Markus Armbruster | |
279 | 666daa68 | Markus Armbruster | if (cyls || heads || secs) {
|
280 | 666daa68 | Markus Armbruster | if (cyls < 1 || (type == IF_IDE && cyls > 16383)) { |
281 | 807105a7 | Markus Armbruster | error_report("invalid physical cyls number");
|
282 | 666daa68 | Markus Armbruster | return NULL; |
283 | 666daa68 | Markus Armbruster | } |
284 | 666daa68 | Markus Armbruster | if (heads < 1 || (type == IF_IDE && heads > 16)) { |
285 | 807105a7 | Markus Armbruster | error_report("invalid physical heads number");
|
286 | 666daa68 | Markus Armbruster | return NULL; |
287 | 666daa68 | Markus Armbruster | } |
288 | 666daa68 | Markus Armbruster | if (secs < 1 || (type == IF_IDE && secs > 63)) { |
289 | 807105a7 | Markus Armbruster | error_report("invalid physical secs number");
|
290 | 666daa68 | Markus Armbruster | return NULL; |
291 | 666daa68 | Markus Armbruster | } |
292 | 666daa68 | Markus Armbruster | } |
293 | 666daa68 | Markus Armbruster | |
294 | 666daa68 | Markus Armbruster | if ((buf = qemu_opt_get(opts, "trans")) != NULL) { |
295 | 666daa68 | Markus Armbruster | if (!cyls) {
|
296 | 807105a7 | Markus Armbruster | error_report("'%s' trans must be used with cyls,heads and secs",
|
297 | 807105a7 | Markus Armbruster | buf); |
298 | 666daa68 | Markus Armbruster | return NULL; |
299 | 666daa68 | Markus Armbruster | } |
300 | 666daa68 | Markus Armbruster | if (!strcmp(buf, "none")) |
301 | 666daa68 | Markus Armbruster | translation = BIOS_ATA_TRANSLATION_NONE; |
302 | 666daa68 | Markus Armbruster | else if (!strcmp(buf, "lba")) |
303 | 666daa68 | Markus Armbruster | translation = BIOS_ATA_TRANSLATION_LBA; |
304 | 666daa68 | Markus Armbruster | else if (!strcmp(buf, "auto")) |
305 | 666daa68 | Markus Armbruster | translation = BIOS_ATA_TRANSLATION_AUTO; |
306 | 666daa68 | Markus Armbruster | else {
|
307 | 807105a7 | Markus Armbruster | error_report("'%s' invalid translation type", buf);
|
308 | 666daa68 | Markus Armbruster | return NULL; |
309 | 666daa68 | Markus Armbruster | } |
310 | 666daa68 | Markus Armbruster | } |
311 | 666daa68 | Markus Armbruster | |
312 | 666daa68 | Markus Armbruster | if ((buf = qemu_opt_get(opts, "media")) != NULL) { |
313 | 666daa68 | Markus Armbruster | if (!strcmp(buf, "disk")) { |
314 | 666daa68 | Markus Armbruster | media = MEDIA_DISK; |
315 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "cdrom")) { |
316 | 666daa68 | Markus Armbruster | if (cyls || secs || heads) {
|
317 | 807105a7 | Markus Armbruster | error_report("'%s' invalid physical CHS format", buf);
|
318 | 666daa68 | Markus Armbruster | return NULL; |
319 | 666daa68 | Markus Armbruster | } |
320 | 666daa68 | Markus Armbruster | media = MEDIA_CDROM; |
321 | 666daa68 | Markus Armbruster | } else {
|
322 | 807105a7 | Markus Armbruster | error_report("'%s' invalid media", buf);
|
323 | 666daa68 | Markus Armbruster | return NULL; |
324 | 666daa68 | Markus Armbruster | } |
325 | 666daa68 | Markus Armbruster | } |
326 | 666daa68 | Markus Armbruster | |
327 | 666daa68 | Markus Armbruster | if ((buf = qemu_opt_get(opts, "cache")) != NULL) { |
328 | 666daa68 | Markus Armbruster | if (!strcmp(buf, "off") || !strcmp(buf, "none")) { |
329 | 666daa68 | Markus Armbruster | bdrv_flags |= BDRV_O_NOCACHE; |
330 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "writeback")) { |
331 | 666daa68 | Markus Armbruster | bdrv_flags |= BDRV_O_CACHE_WB; |
332 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "unsafe")) { |
333 | 666daa68 | Markus Armbruster | bdrv_flags |= BDRV_O_CACHE_WB; |
334 | 666daa68 | Markus Armbruster | bdrv_flags |= BDRV_O_NO_FLUSH; |
335 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "writethrough")) { |
336 | 666daa68 | Markus Armbruster | /* this is the default */
|
337 | 666daa68 | Markus Armbruster | } else {
|
338 | 807105a7 | Markus Armbruster | error_report("invalid cache option");
|
339 | 666daa68 | Markus Armbruster | return NULL; |
340 | 666daa68 | Markus Armbruster | } |
341 | 666daa68 | Markus Armbruster | } |
342 | 666daa68 | Markus Armbruster | |
343 | 666daa68 | Markus Armbruster | #ifdef CONFIG_LINUX_AIO
|
344 | 666daa68 | Markus Armbruster | if ((buf = qemu_opt_get(opts, "aio")) != NULL) { |
345 | 666daa68 | Markus Armbruster | if (!strcmp(buf, "native")) { |
346 | 666daa68 | Markus Armbruster | bdrv_flags |= BDRV_O_NATIVE_AIO; |
347 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "threads")) { |
348 | 666daa68 | Markus Armbruster | /* this is the default */
|
349 | 666daa68 | Markus Armbruster | } else {
|
350 | 807105a7 | Markus Armbruster | error_report("invalid aio option");
|
351 | 666daa68 | Markus Armbruster | return NULL; |
352 | 666daa68 | Markus Armbruster | } |
353 | 666daa68 | Markus Armbruster | } |
354 | 666daa68 | Markus Armbruster | #endif
|
355 | 666daa68 | Markus Armbruster | |
356 | 666daa68 | Markus Armbruster | if ((buf = qemu_opt_get(opts, "format")) != NULL) { |
357 | 666daa68 | Markus Armbruster | if (strcmp(buf, "?") == 0) { |
358 | 807105a7 | Markus Armbruster | error_printf("Supported formats:");
|
359 | 807105a7 | Markus Armbruster | bdrv_iterate_format(bdrv_format_print, NULL);
|
360 | 807105a7 | Markus Armbruster | error_printf("\n");
|
361 | 807105a7 | Markus Armbruster | return NULL; |
362 | 666daa68 | Markus Armbruster | } |
363 | 666daa68 | Markus Armbruster | drv = bdrv_find_whitelisted_format(buf); |
364 | 666daa68 | Markus Armbruster | if (!drv) {
|
365 | 807105a7 | Markus Armbruster | error_report("'%s' invalid format", buf);
|
366 | 666daa68 | Markus Armbruster | return NULL; |
367 | 666daa68 | Markus Armbruster | } |
368 | 666daa68 | Markus Armbruster | } |
369 | 666daa68 | Markus Armbruster | |
370 | 666daa68 | Markus Armbruster | on_write_error = BLOCK_ERR_STOP_ENOSPC; |
371 | 666daa68 | Markus Armbruster | if ((buf = qemu_opt_get(opts, "werror")) != NULL) { |
372 | 666daa68 | Markus Armbruster | if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
|
373 | 807105a7 | Markus Armbruster | error_report("werror is not supported by this bus type");
|
374 | 666daa68 | Markus Armbruster | return NULL; |
375 | 666daa68 | Markus Armbruster | } |
376 | 666daa68 | Markus Armbruster | |
377 | 666daa68 | Markus Armbruster | on_write_error = parse_block_error_action(buf, 0);
|
378 | 666daa68 | Markus Armbruster | if (on_write_error < 0) { |
379 | 666daa68 | Markus Armbruster | return NULL; |
380 | 666daa68 | Markus Armbruster | } |
381 | 666daa68 | Markus Armbruster | } |
382 | 666daa68 | Markus Armbruster | |
383 | 666daa68 | Markus Armbruster | on_read_error = BLOCK_ERR_REPORT; |
384 | 666daa68 | Markus Armbruster | if ((buf = qemu_opt_get(opts, "rerror")) != NULL) { |
385 | 5dba48a8 | Kevin Wolf | if (type != IF_IDE && type != IF_VIRTIO && type != IF_SCSI && type != IF_NONE) {
|
386 | 807105a7 | Markus Armbruster | error_report("rerror is not supported by this bus type");
|
387 | 666daa68 | Markus Armbruster | return NULL; |
388 | 666daa68 | Markus Armbruster | } |
389 | 666daa68 | Markus Armbruster | |
390 | 666daa68 | Markus Armbruster | on_read_error = parse_block_error_action(buf, 1);
|
391 | 666daa68 | Markus Armbruster | if (on_read_error < 0) { |
392 | 666daa68 | Markus Armbruster | return NULL; |
393 | 666daa68 | Markus Armbruster | } |
394 | 666daa68 | Markus Armbruster | } |
395 | 666daa68 | Markus Armbruster | |
396 | 666daa68 | Markus Armbruster | if ((devaddr = qemu_opt_get(opts, "addr")) != NULL) { |
397 | 666daa68 | Markus Armbruster | if (type != IF_VIRTIO) {
|
398 | 807105a7 | Markus Armbruster | error_report("addr is not supported by this bus type");
|
399 | 666daa68 | Markus Armbruster | return NULL; |
400 | 666daa68 | Markus Armbruster | } |
401 | 666daa68 | Markus Armbruster | } |
402 | 666daa68 | Markus Armbruster | |
403 | 666daa68 | Markus Armbruster | /* compute bus and unit according index */
|
404 | 666daa68 | Markus Armbruster | |
405 | 666daa68 | Markus Armbruster | if (index != -1) { |
406 | 666daa68 | Markus Armbruster | if (bus_id != 0 || unit_id != -1) { |
407 | 807105a7 | Markus Armbruster | error_report("index cannot be used with bus and unit");
|
408 | 666daa68 | Markus Armbruster | return NULL; |
409 | 666daa68 | Markus Armbruster | } |
410 | 505a7fb1 | Markus Armbruster | bus_id = drive_index_to_bus_id(type, index); |
411 | 505a7fb1 | Markus Armbruster | unit_id = drive_index_to_unit_id(type, index); |
412 | 666daa68 | Markus Armbruster | } |
413 | 666daa68 | Markus Armbruster | |
414 | 666daa68 | Markus Armbruster | /* if user doesn't specify a unit_id,
|
415 | 666daa68 | Markus Armbruster | * try to find the first free
|
416 | 666daa68 | Markus Armbruster | */
|
417 | 666daa68 | Markus Armbruster | |
418 | 666daa68 | Markus Armbruster | if (unit_id == -1) { |
419 | 666daa68 | Markus Armbruster | unit_id = 0;
|
420 | 666daa68 | Markus Armbruster | while (drive_get(type, bus_id, unit_id) != NULL) { |
421 | 666daa68 | Markus Armbruster | unit_id++; |
422 | 666daa68 | Markus Armbruster | if (max_devs && unit_id >= max_devs) {
|
423 | 666daa68 | Markus Armbruster | unit_id -= max_devs; |
424 | 666daa68 | Markus Armbruster | bus_id++; |
425 | 666daa68 | Markus Armbruster | } |
426 | 666daa68 | Markus Armbruster | } |
427 | 666daa68 | Markus Armbruster | } |
428 | 666daa68 | Markus Armbruster | |
429 | 666daa68 | Markus Armbruster | /* check unit id */
|
430 | 666daa68 | Markus Armbruster | |
431 | 666daa68 | Markus Armbruster | if (max_devs && unit_id >= max_devs) {
|
432 | 807105a7 | Markus Armbruster | error_report("unit %d too big (max is %d)",
|
433 | 807105a7 | Markus Armbruster | unit_id, max_devs - 1);
|
434 | 666daa68 | Markus Armbruster | return NULL; |
435 | 666daa68 | Markus Armbruster | } |
436 | 666daa68 | Markus Armbruster | |
437 | 666daa68 | Markus Armbruster | /*
|
438 | 4e5d9b57 | Markus Armbruster | * catch multiple definitions
|
439 | 666daa68 | Markus Armbruster | */
|
440 | 666daa68 | Markus Armbruster | |
441 | 666daa68 | Markus Armbruster | if (drive_get(type, bus_id, unit_id) != NULL) { |
442 | 4e5d9b57 | Markus Armbruster | error_report("drive with bus=%d, unit=%d (index=%d) exists",
|
443 | 4e5d9b57 | Markus Armbruster | bus_id, unit_id, index); |
444 | 666daa68 | Markus Armbruster | return NULL; |
445 | 666daa68 | Markus Armbruster | } |
446 | 666daa68 | Markus Armbruster | |
447 | 666daa68 | Markus Armbruster | /* init */
|
448 | 666daa68 | Markus Armbruster | |
449 | 666daa68 | Markus Armbruster | dinfo = qemu_mallocz(sizeof(*dinfo));
|
450 | 666daa68 | Markus Armbruster | if ((buf = qemu_opts_id(opts)) != NULL) { |
451 | 666daa68 | Markus Armbruster | dinfo->id = qemu_strdup(buf); |
452 | 666daa68 | Markus Armbruster | } else {
|
453 | 666daa68 | Markus Armbruster | /* no id supplied -> create one */
|
454 | 666daa68 | Markus Armbruster | dinfo->id = qemu_mallocz(32);
|
455 | 666daa68 | Markus Armbruster | if (type == IF_IDE || type == IF_SCSI)
|
456 | 666daa68 | Markus Armbruster | mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd"; |
457 | 666daa68 | Markus Armbruster | if (max_devs)
|
458 | 666daa68 | Markus Armbruster | snprintf(dinfo->id, 32, "%s%i%s%i", |
459 | 666daa68 | Markus Armbruster | devname, bus_id, mediastr, unit_id); |
460 | 666daa68 | Markus Armbruster | else
|
461 | 666daa68 | Markus Armbruster | snprintf(dinfo->id, 32, "%s%s%i", |
462 | 666daa68 | Markus Armbruster | devname, mediastr, unit_id); |
463 | 666daa68 | Markus Armbruster | } |
464 | 666daa68 | Markus Armbruster | dinfo->bdrv = bdrv_new(dinfo->id); |
465 | 666daa68 | Markus Armbruster | dinfo->devaddr = devaddr; |
466 | 666daa68 | Markus Armbruster | dinfo->type = type; |
467 | 666daa68 | Markus Armbruster | dinfo->bus = bus_id; |
468 | 666daa68 | Markus Armbruster | dinfo->unit = unit_id; |
469 | 666daa68 | Markus Armbruster | dinfo->opts = opts; |
470 | 84fb3925 | Marcelo Tosatti | dinfo->refcount = 1;
|
471 | 666daa68 | Markus Armbruster | if (serial)
|
472 | 653dbec7 | Luiz Capitulino | strncpy(dinfo->serial, serial, sizeof(dinfo->serial) - 1); |
473 | 666daa68 | Markus Armbruster | QTAILQ_INSERT_TAIL(&drives, dinfo, next); |
474 | 666daa68 | Markus Armbruster | |
475 | abd7f68d | Markus Armbruster | bdrv_set_on_error(dinfo->bdrv, on_read_error, on_write_error); |
476 | abd7f68d | Markus Armbruster | |
477 | 666daa68 | Markus Armbruster | switch(type) {
|
478 | 666daa68 | Markus Armbruster | case IF_IDE:
|
479 | 666daa68 | Markus Armbruster | case IF_SCSI:
|
480 | 666daa68 | Markus Armbruster | case IF_XEN:
|
481 | 666daa68 | Markus Armbruster | case IF_NONE:
|
482 | 666daa68 | Markus Armbruster | switch(media) {
|
483 | 666daa68 | Markus Armbruster | case MEDIA_DISK:
|
484 | 666daa68 | Markus Armbruster | if (cyls != 0) { |
485 | 666daa68 | Markus Armbruster | bdrv_set_geometry_hint(dinfo->bdrv, cyls, heads, secs); |
486 | 666daa68 | Markus Armbruster | bdrv_set_translation_hint(dinfo->bdrv, translation); |
487 | 666daa68 | Markus Armbruster | } |
488 | 666daa68 | Markus Armbruster | break;
|
489 | 666daa68 | Markus Armbruster | case MEDIA_CDROM:
|
490 | 666daa68 | Markus Armbruster | bdrv_set_type_hint(dinfo->bdrv, BDRV_TYPE_CDROM); |
491 | 95b5edcd | Markus Armbruster | dinfo->media_cd = 1;
|
492 | 666daa68 | Markus Armbruster | break;
|
493 | 666daa68 | Markus Armbruster | } |
494 | 666daa68 | Markus Armbruster | break;
|
495 | 666daa68 | Markus Armbruster | case IF_SD:
|
496 | 666daa68 | Markus Armbruster | /* FIXME: This isn't really a floppy, but it's a reasonable
|
497 | 666daa68 | Markus Armbruster | approximation. */
|
498 | 666daa68 | Markus Armbruster | case IF_FLOPPY:
|
499 | 666daa68 | Markus Armbruster | bdrv_set_type_hint(dinfo->bdrv, BDRV_TYPE_FLOPPY); |
500 | 666daa68 | Markus Armbruster | break;
|
501 | 666daa68 | Markus Armbruster | case IF_PFLASH:
|
502 | 666daa68 | Markus Armbruster | case IF_MTD:
|
503 | 666daa68 | Markus Armbruster | break;
|
504 | 666daa68 | Markus Armbruster | case IF_VIRTIO:
|
505 | 666daa68 | Markus Armbruster | /* add virtio block device */
|
506 | 3329f07b | Gerd Hoffmann | opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0); |
507 | 29f82b37 | Alexander Graf | qemu_opt_set(opts, "driver", "virtio-blk"); |
508 | 666daa68 | Markus Armbruster | qemu_opt_set(opts, "drive", dinfo->id);
|
509 | 666daa68 | Markus Armbruster | if (devaddr)
|
510 | 666daa68 | Markus Armbruster | qemu_opt_set(opts, "addr", devaddr);
|
511 | 666daa68 | Markus Armbruster | break;
|
512 | 2292ddae | Markus Armbruster | default:
|
513 | 666daa68 | Markus Armbruster | abort(); |
514 | 666daa68 | Markus Armbruster | } |
515 | dd5b0d71 | Markus Armbruster | if (!file || !*file) {
|
516 | 319ae529 | Markus Armbruster | return dinfo;
|
517 | 666daa68 | Markus Armbruster | } |
518 | 666daa68 | Markus Armbruster | if (snapshot) {
|
519 | 666daa68 | Markus Armbruster | /* always use cache=unsafe with snapshot */
|
520 | 666daa68 | Markus Armbruster | bdrv_flags &= ~BDRV_O_CACHE_MASK; |
521 | 666daa68 | Markus Armbruster | bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB|BDRV_O_NO_FLUSH); |
522 | 666daa68 | Markus Armbruster | } |
523 | 666daa68 | Markus Armbruster | |
524 | 666daa68 | Markus Armbruster | if (media == MEDIA_CDROM) {
|
525 | 666daa68 | Markus Armbruster | /* CDROM is fine for any interface, don't check. */
|
526 | 666daa68 | Markus Armbruster | ro = 1;
|
527 | 666daa68 | Markus Armbruster | } else if (ro == 1) { |
528 | 666daa68 | Markus Armbruster | if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY && type != IF_NONE) {
|
529 | 807105a7 | Markus Armbruster | error_report("readonly not supported by this bus type");
|
530 | a9ae2bff | Markus Armbruster | goto err;
|
531 | 666daa68 | Markus Armbruster | } |
532 | 666daa68 | Markus Armbruster | } |
533 | 666daa68 | Markus Armbruster | |
534 | 666daa68 | Markus Armbruster | bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
|
535 | 666daa68 | Markus Armbruster | |
536 | 666daa68 | Markus Armbruster | ret = bdrv_open(dinfo->bdrv, file, bdrv_flags, drv); |
537 | 666daa68 | Markus Armbruster | if (ret < 0) { |
538 | 807105a7 | Markus Armbruster | error_report("could not open disk image %s: %s",
|
539 | 807105a7 | Markus Armbruster | file, strerror(-ret)); |
540 | a9ae2bff | Markus Armbruster | goto err;
|
541 | 666daa68 | Markus Armbruster | } |
542 | 666daa68 | Markus Armbruster | |
543 | 666daa68 | Markus Armbruster | if (bdrv_key_required(dinfo->bdrv))
|
544 | 666daa68 | Markus Armbruster | autostart = 0;
|
545 | 666daa68 | Markus Armbruster | return dinfo;
|
546 | a9ae2bff | Markus Armbruster | |
547 | a9ae2bff | Markus Armbruster | err:
|
548 | a9ae2bff | Markus Armbruster | bdrv_delete(dinfo->bdrv); |
549 | a9ae2bff | Markus Armbruster | qemu_free(dinfo->id); |
550 | a9ae2bff | Markus Armbruster | QTAILQ_REMOVE(&drives, dinfo, next); |
551 | a9ae2bff | Markus Armbruster | qemu_free(dinfo); |
552 | a9ae2bff | Markus Armbruster | return NULL; |
553 | 666daa68 | Markus Armbruster | } |
554 | 666daa68 | Markus Armbruster | |
555 | 666daa68 | Markus Armbruster | void do_commit(Monitor *mon, const QDict *qdict) |
556 | 666daa68 | Markus Armbruster | { |
557 | 666daa68 | Markus Armbruster | const char *device = qdict_get_str(qdict, "device"); |
558 | 6ab4b5ab | Markus Armbruster | BlockDriverState *bs; |
559 | 666daa68 | Markus Armbruster | |
560 | 6ab4b5ab | Markus Armbruster | if (!strcmp(device, "all")) { |
561 | 6ab4b5ab | Markus Armbruster | bdrv_commit_all(); |
562 | 6ab4b5ab | Markus Armbruster | } else {
|
563 | 6ab4b5ab | Markus Armbruster | bs = bdrv_find(device); |
564 | ac59eb95 | Markus Armbruster | if (!bs) {
|
565 | ac59eb95 | Markus Armbruster | qerror_report(QERR_DEVICE_NOT_FOUND, device); |
566 | ac59eb95 | Markus Armbruster | return;
|
567 | 6ab4b5ab | Markus Armbruster | } |
568 | ac59eb95 | Markus Armbruster | bdrv_commit(bs); |
569 | 666daa68 | Markus Armbruster | } |
570 | 666daa68 | Markus Armbruster | } |
571 | 666daa68 | Markus Armbruster | |
572 | f8882568 | Jes Sorensen | int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data) |
573 | f8882568 | Jes Sorensen | { |
574 | f8882568 | Jes Sorensen | const char *device = qdict_get_str(qdict, "device"); |
575 | f8882568 | Jes Sorensen | const char *filename = qdict_get_try_str(qdict, "snapshot_file"); |
576 | f8882568 | Jes Sorensen | const char *format = qdict_get_try_str(qdict, "format"); |
577 | f8882568 | Jes Sorensen | BlockDriverState *bs; |
578 | 52f9a172 | Jes Sorensen | BlockDriver *drv, *old_drv, *proto_drv; |
579 | f8882568 | Jes Sorensen | int ret = 0; |
580 | f8882568 | Jes Sorensen | int flags;
|
581 | 52f9a172 | Jes Sorensen | char old_filename[1024]; |
582 | f8882568 | Jes Sorensen | |
583 | c90f1b32 | Jes Sorensen | if (!filename) {
|
584 | c90f1b32 | Jes Sorensen | qerror_report(QERR_MISSING_PARAMETER, "snapshot_file");
|
585 | c90f1b32 | Jes Sorensen | ret = -1;
|
586 | c90f1b32 | Jes Sorensen | goto out;
|
587 | c90f1b32 | Jes Sorensen | } |
588 | c90f1b32 | Jes Sorensen | |
589 | f8882568 | Jes Sorensen | bs = bdrv_find(device); |
590 | f8882568 | Jes Sorensen | if (!bs) {
|
591 | f8882568 | Jes Sorensen | qerror_report(QERR_DEVICE_NOT_FOUND, device); |
592 | f8882568 | Jes Sorensen | ret = -1;
|
593 | f8882568 | Jes Sorensen | goto out;
|
594 | f8882568 | Jes Sorensen | } |
595 | f8882568 | Jes Sorensen | |
596 | 52f9a172 | Jes Sorensen | pstrcpy(old_filename, sizeof(old_filename), bs->filename);
|
597 | 52f9a172 | Jes Sorensen | |
598 | 52f9a172 | Jes Sorensen | old_drv = bs->drv; |
599 | 52f9a172 | Jes Sorensen | flags = bs->open_flags; |
600 | 52f9a172 | Jes Sorensen | |
601 | f8882568 | Jes Sorensen | if (!format) {
|
602 | f8882568 | Jes Sorensen | format = "qcow2";
|
603 | f8882568 | Jes Sorensen | } |
604 | f8882568 | Jes Sorensen | |
605 | f8882568 | Jes Sorensen | drv = bdrv_find_format(format); |
606 | f8882568 | Jes Sorensen | if (!drv) {
|
607 | f8882568 | Jes Sorensen | qerror_report(QERR_INVALID_BLOCK_FORMAT, format); |
608 | f8882568 | Jes Sorensen | ret = -1;
|
609 | f8882568 | Jes Sorensen | goto out;
|
610 | f8882568 | Jes Sorensen | } |
611 | f8882568 | Jes Sorensen | |
612 | f8882568 | Jes Sorensen | proto_drv = bdrv_find_protocol(filename); |
613 | f8882568 | Jes Sorensen | if (!proto_drv) {
|
614 | f8882568 | Jes Sorensen | qerror_report(QERR_INVALID_BLOCK_FORMAT, format); |
615 | f8882568 | Jes Sorensen | ret = -1;
|
616 | f8882568 | Jes Sorensen | goto out;
|
617 | f8882568 | Jes Sorensen | } |
618 | f8882568 | Jes Sorensen | |
619 | f8882568 | Jes Sorensen | ret = bdrv_img_create(filename, format, bs->filename, |
620 | 52f9a172 | Jes Sorensen | bs->drv->format_name, NULL, -1, flags); |
621 | f8882568 | Jes Sorensen | if (ret) {
|
622 | f8882568 | Jes Sorensen | goto out;
|
623 | f8882568 | Jes Sorensen | } |
624 | f8882568 | Jes Sorensen | |
625 | f8882568 | Jes Sorensen | qemu_aio_flush(); |
626 | f8882568 | Jes Sorensen | bdrv_flush(bs); |
627 | f8882568 | Jes Sorensen | |
628 | f8882568 | Jes Sorensen | bdrv_close(bs); |
629 | f8882568 | Jes Sorensen | ret = bdrv_open(bs, filename, flags, drv); |
630 | f8882568 | Jes Sorensen | /*
|
631 | 52f9a172 | Jes Sorensen | * If reopening the image file we just created fails, fall back
|
632 | 52f9a172 | Jes Sorensen | * and try to re-open the original image. If that fails too, we
|
633 | 52f9a172 | Jes Sorensen | * are in serious trouble.
|
634 | f8882568 | Jes Sorensen | */
|
635 | f8882568 | Jes Sorensen | if (ret != 0) { |
636 | 52f9a172 | Jes Sorensen | ret = bdrv_open(bs, old_filename, flags, old_drv); |
637 | 52f9a172 | Jes Sorensen | if (ret != 0) { |
638 | 52f9a172 | Jes Sorensen | qerror_report(QERR_OPEN_FILE_FAILED, old_filename); |
639 | 52f9a172 | Jes Sorensen | } else {
|
640 | 52f9a172 | Jes Sorensen | qerror_report(QERR_OPEN_FILE_FAILED, filename); |
641 | 52f9a172 | Jes Sorensen | } |
642 | f8882568 | Jes Sorensen | } |
643 | f8882568 | Jes Sorensen | out:
|
644 | f8882568 | Jes Sorensen | if (ret) {
|
645 | f8882568 | Jes Sorensen | ret = -1;
|
646 | f8882568 | Jes Sorensen | } |
647 | f8882568 | Jes Sorensen | |
648 | f8882568 | Jes Sorensen | return ret;
|
649 | f8882568 | Jes Sorensen | } |
650 | f8882568 | Jes Sorensen | |
651 | 666daa68 | Markus Armbruster | static int eject_device(Monitor *mon, BlockDriverState *bs, int force) |
652 | 666daa68 | Markus Armbruster | { |
653 | 3b5276b5 | Eduardo Habkost | if (!force) {
|
654 | 3b5276b5 | Eduardo Habkost | if (!bdrv_is_removable(bs)) {
|
655 | 3b5276b5 | Eduardo Habkost | qerror_report(QERR_DEVICE_NOT_REMOVABLE, |
656 | 3b5276b5 | Eduardo Habkost | bdrv_get_device_name(bs)); |
657 | 3b5276b5 | Eduardo Habkost | return -1; |
658 | 3b5276b5 | Eduardo Habkost | } |
659 | 3b5276b5 | Eduardo Habkost | if (bdrv_is_locked(bs)) {
|
660 | 3b5276b5 | Eduardo Habkost | qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs)); |
661 | 3b5276b5 | Eduardo Habkost | return -1; |
662 | 666daa68 | Markus Armbruster | } |
663 | 666daa68 | Markus Armbruster | } |
664 | 3b5276b5 | Eduardo Habkost | bdrv_close(bs); |
665 | 666daa68 | Markus Armbruster | return 0; |
666 | 666daa68 | Markus Armbruster | } |
667 | 666daa68 | Markus Armbruster | |
668 | 666daa68 | Markus Armbruster | int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data) |
669 | 666daa68 | Markus Armbruster | { |
670 | 666daa68 | Markus Armbruster | BlockDriverState *bs; |
671 | eb159d13 | Luiz Capitulino | int force = qdict_get_try_bool(qdict, "force", 0); |
672 | 666daa68 | Markus Armbruster | const char *filename = qdict_get_str(qdict, "device"); |
673 | 666daa68 | Markus Armbruster | |
674 | 666daa68 | Markus Armbruster | bs = bdrv_find(filename); |
675 | 666daa68 | Markus Armbruster | if (!bs) {
|
676 | 666daa68 | Markus Armbruster | qerror_report(QERR_DEVICE_NOT_FOUND, filename); |
677 | 666daa68 | Markus Armbruster | return -1; |
678 | 666daa68 | Markus Armbruster | } |
679 | 666daa68 | Markus Armbruster | return eject_device(mon, bs, force);
|
680 | 666daa68 | Markus Armbruster | } |
681 | 666daa68 | Markus Armbruster | |
682 | 666daa68 | Markus Armbruster | int do_block_set_passwd(Monitor *mon, const QDict *qdict, |
683 | 666daa68 | Markus Armbruster | QObject **ret_data) |
684 | 666daa68 | Markus Armbruster | { |
685 | 666daa68 | Markus Armbruster | BlockDriverState *bs; |
686 | 666daa68 | Markus Armbruster | int err;
|
687 | 666daa68 | Markus Armbruster | |
688 | 666daa68 | Markus Armbruster | bs = bdrv_find(qdict_get_str(qdict, "device"));
|
689 | 666daa68 | Markus Armbruster | if (!bs) {
|
690 | 666daa68 | Markus Armbruster | qerror_report(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device"));
|
691 | 666daa68 | Markus Armbruster | return -1; |
692 | 666daa68 | Markus Armbruster | } |
693 | 666daa68 | Markus Armbruster | |
694 | 666daa68 | Markus Armbruster | err = bdrv_set_key(bs, qdict_get_str(qdict, "password"));
|
695 | 666daa68 | Markus Armbruster | if (err == -EINVAL) {
|
696 | 666daa68 | Markus Armbruster | qerror_report(QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs)); |
697 | 666daa68 | Markus Armbruster | return -1; |
698 | 666daa68 | Markus Armbruster | } else if (err < 0) { |
699 | 666daa68 | Markus Armbruster | qerror_report(QERR_INVALID_PASSWORD); |
700 | 666daa68 | Markus Armbruster | return -1; |
701 | 666daa68 | Markus Armbruster | } |
702 | 666daa68 | Markus Armbruster | |
703 | 666daa68 | Markus Armbruster | return 0; |
704 | 666daa68 | Markus Armbruster | } |
705 | 666daa68 | Markus Armbruster | |
706 | 666daa68 | Markus Armbruster | int do_change_block(Monitor *mon, const char *device, |
707 | 666daa68 | Markus Armbruster | const char *filename, const char *fmt) |
708 | 666daa68 | Markus Armbruster | { |
709 | 666daa68 | Markus Armbruster | BlockDriverState *bs; |
710 | 666daa68 | Markus Armbruster | BlockDriver *drv = NULL;
|
711 | 666daa68 | Markus Armbruster | int bdrv_flags;
|
712 | 666daa68 | Markus Armbruster | |
713 | 666daa68 | Markus Armbruster | bs = bdrv_find(device); |
714 | 666daa68 | Markus Armbruster | if (!bs) {
|
715 | 666daa68 | Markus Armbruster | qerror_report(QERR_DEVICE_NOT_FOUND, device); |
716 | 666daa68 | Markus Armbruster | return -1; |
717 | 666daa68 | Markus Armbruster | } |
718 | 666daa68 | Markus Armbruster | if (fmt) {
|
719 | 666daa68 | Markus Armbruster | drv = bdrv_find_whitelisted_format(fmt); |
720 | 666daa68 | Markus Armbruster | if (!drv) {
|
721 | 666daa68 | Markus Armbruster | qerror_report(QERR_INVALID_BLOCK_FORMAT, fmt); |
722 | 666daa68 | Markus Armbruster | return -1; |
723 | 666daa68 | Markus Armbruster | } |
724 | 666daa68 | Markus Armbruster | } |
725 | 666daa68 | Markus Armbruster | if (eject_device(mon, bs, 0) < 0) { |
726 | 666daa68 | Markus Armbruster | return -1; |
727 | 666daa68 | Markus Armbruster | } |
728 | 528f7663 | Markus Armbruster | bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR;
|
729 | 199630b6 | Blue Swirl | bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0;
|
730 | 666daa68 | Markus Armbruster | if (bdrv_open(bs, filename, bdrv_flags, drv) < 0) { |
731 | 666daa68 | Markus Armbruster | qerror_report(QERR_OPEN_FILE_FAILED, filename); |
732 | 666daa68 | Markus Armbruster | return -1; |
733 | 666daa68 | Markus Armbruster | } |
734 | 666daa68 | Markus Armbruster | return monitor_read_bdrv_key_start(mon, bs, NULL, NULL); |
735 | 666daa68 | Markus Armbruster | } |
736 | 9063f814 | Ryan Harper | |
737 | 9063f814 | Ryan Harper | int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data) |
738 | 9063f814 | Ryan Harper | { |
739 | 9063f814 | Ryan Harper | const char *id = qdict_get_str(qdict, "id"); |
740 | 9063f814 | Ryan Harper | BlockDriverState *bs; |
741 | 9063f814 | Ryan Harper | |
742 | 9063f814 | Ryan Harper | bs = bdrv_find(id); |
743 | 9063f814 | Ryan Harper | if (!bs) {
|
744 | 9063f814 | Ryan Harper | qerror_report(QERR_DEVICE_NOT_FOUND, id); |
745 | 9063f814 | Ryan Harper | return -1; |
746 | 9063f814 | Ryan Harper | } |
747 | 8591675f | Marcelo Tosatti | if (bdrv_in_use(bs)) {
|
748 | 8591675f | Marcelo Tosatti | qerror_report(QERR_DEVICE_IN_USE, id); |
749 | 8591675f | Marcelo Tosatti | return -1; |
750 | 8591675f | Marcelo Tosatti | } |
751 | 9063f814 | Ryan Harper | |
752 | 9063f814 | Ryan Harper | /* quiesce block driver; prevent further io */
|
753 | 9063f814 | Ryan Harper | qemu_aio_flush(); |
754 | 9063f814 | Ryan Harper | bdrv_flush(bs); |
755 | 9063f814 | Ryan Harper | bdrv_close(bs); |
756 | 9063f814 | Ryan Harper | |
757 | d22b2f41 | Ryan Harper | /* if we have a device associated with this BlockDriverState (bs->peer)
|
758 | d22b2f41 | Ryan Harper | * then we need to make the drive anonymous until the device
|
759 | d22b2f41 | Ryan Harper | * can be removed. If this is a drive with no device backing
|
760 | d22b2f41 | Ryan Harper | * then we can just get rid of the block driver state right here.
|
761 | d22b2f41 | Ryan Harper | */
|
762 | 850ec113 | Markus Armbruster | if (bs->peer) {
|
763 | d22b2f41 | Ryan Harper | bdrv_make_anon(bs); |
764 | d22b2f41 | Ryan Harper | } else {
|
765 | d22b2f41 | Ryan Harper | drive_uninit(drive_get_by_blockdev(bs)); |
766 | 9063f814 | Ryan Harper | } |
767 | 9063f814 | Ryan Harper | |
768 | 9063f814 | Ryan Harper | return 0; |
769 | 9063f814 | Ryan Harper | } |
770 | 6d4a2b3a | Christoph Hellwig | |
771 | 6d4a2b3a | Christoph Hellwig | /*
|
772 | 6d4a2b3a | Christoph Hellwig | * XXX: replace the QERR_UNDEFINED_ERROR errors with real values once the
|
773 | 6d4a2b3a | Christoph Hellwig | * existing QERR_ macro mess is cleaned up. A good example for better
|
774 | 6d4a2b3a | Christoph Hellwig | * error reports can be found in the qemu-img resize code.
|
775 | 6d4a2b3a | Christoph Hellwig | */
|
776 | 6d4a2b3a | Christoph Hellwig | int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data) |
777 | 6d4a2b3a | Christoph Hellwig | { |
778 | 6d4a2b3a | Christoph Hellwig | const char *device = qdict_get_str(qdict, "device"); |
779 | 6d4a2b3a | Christoph Hellwig | int64_t size = qdict_get_int(qdict, "size");
|
780 | 6d4a2b3a | Christoph Hellwig | BlockDriverState *bs; |
781 | 6d4a2b3a | Christoph Hellwig | |
782 | 6d4a2b3a | Christoph Hellwig | bs = bdrv_find(device); |
783 | 6d4a2b3a | Christoph Hellwig | if (!bs) {
|
784 | 6d4a2b3a | Christoph Hellwig | qerror_report(QERR_DEVICE_NOT_FOUND, device); |
785 | 6d4a2b3a | Christoph Hellwig | return -1; |
786 | 6d4a2b3a | Christoph Hellwig | } |
787 | 6d4a2b3a | Christoph Hellwig | |
788 | 6d4a2b3a | Christoph Hellwig | if (size < 0) { |
789 | 6d4a2b3a | Christoph Hellwig | qerror_report(QERR_UNDEFINED_ERROR); |
790 | 6d4a2b3a | Christoph Hellwig | return -1; |
791 | 6d4a2b3a | Christoph Hellwig | } |
792 | 6d4a2b3a | Christoph Hellwig | |
793 | 6d4a2b3a | Christoph Hellwig | if (bdrv_truncate(bs, size)) {
|
794 | 6d4a2b3a | Christoph Hellwig | qerror_report(QERR_UNDEFINED_ERROR); |
795 | 6d4a2b3a | Christoph Hellwig | return -1; |
796 | 6d4a2b3a | Christoph Hellwig | } |
797 | 6d4a2b3a | Christoph Hellwig | |
798 | 6d4a2b3a | Christoph Hellwig | return 0; |
799 | 6d4a2b3a | Christoph Hellwig | } |