root / blockdev.c @ dd5b0d71
History | View | Annotate | Download (16 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 | 666daa68 | Markus Armbruster | |
18 | 666daa68 | Markus Armbruster | struct drivelist drives = QTAILQ_HEAD_INITIALIZER(drives);
|
19 | 666daa68 | Markus Armbruster | |
20 | 666daa68 | Markus Armbruster | QemuOpts *drive_add(const char *file, const char *fmt, ...) |
21 | 666daa68 | Markus Armbruster | { |
22 | 666daa68 | Markus Armbruster | va_list ap; |
23 | 666daa68 | Markus Armbruster | char optstr[1024]; |
24 | 666daa68 | Markus Armbruster | QemuOpts *opts; |
25 | 666daa68 | Markus Armbruster | |
26 | 666daa68 | Markus Armbruster | va_start(ap, fmt); |
27 | 666daa68 | Markus Armbruster | vsnprintf(optstr, sizeof(optstr), fmt, ap);
|
28 | 666daa68 | Markus Armbruster | va_end(ap); |
29 | 666daa68 | Markus Armbruster | |
30 | 666daa68 | Markus Armbruster | opts = qemu_opts_parse(&qemu_drive_opts, optstr, 0);
|
31 | 666daa68 | Markus Armbruster | if (!opts) {
|
32 | 666daa68 | Markus Armbruster | return NULL; |
33 | 666daa68 | Markus Armbruster | } |
34 | 666daa68 | Markus Armbruster | if (file)
|
35 | 666daa68 | Markus Armbruster | qemu_opt_set(opts, "file", file);
|
36 | 666daa68 | Markus Armbruster | return opts;
|
37 | 666daa68 | Markus Armbruster | } |
38 | 666daa68 | Markus Armbruster | |
39 | 666daa68 | Markus Armbruster | DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit) |
40 | 666daa68 | Markus Armbruster | { |
41 | 666daa68 | Markus Armbruster | DriveInfo *dinfo; |
42 | 666daa68 | Markus Armbruster | |
43 | 666daa68 | Markus Armbruster | /* seek interface, bus and unit */
|
44 | 666daa68 | Markus Armbruster | |
45 | 666daa68 | Markus Armbruster | QTAILQ_FOREACH(dinfo, &drives, next) { |
46 | 666daa68 | Markus Armbruster | if (dinfo->type == type &&
|
47 | 666daa68 | Markus Armbruster | dinfo->bus == bus && |
48 | 666daa68 | Markus Armbruster | dinfo->unit == unit) |
49 | 666daa68 | Markus Armbruster | return dinfo;
|
50 | 666daa68 | Markus Armbruster | } |
51 | 666daa68 | Markus Armbruster | |
52 | 666daa68 | Markus Armbruster | return NULL; |
53 | 666daa68 | Markus Armbruster | } |
54 | 666daa68 | Markus Armbruster | |
55 | 666daa68 | Markus Armbruster | DriveInfo *drive_get_by_id(const char *id) |
56 | 666daa68 | Markus Armbruster | { |
57 | 666daa68 | Markus Armbruster | DriveInfo *dinfo; |
58 | 666daa68 | Markus Armbruster | |
59 | 666daa68 | Markus Armbruster | QTAILQ_FOREACH(dinfo, &drives, next) { |
60 | 666daa68 | Markus Armbruster | if (strcmp(id, dinfo->id))
|
61 | 666daa68 | Markus Armbruster | continue;
|
62 | 666daa68 | Markus Armbruster | return dinfo;
|
63 | 666daa68 | Markus Armbruster | } |
64 | 666daa68 | Markus Armbruster | return NULL; |
65 | 666daa68 | Markus Armbruster | } |
66 | 666daa68 | Markus Armbruster | |
67 | 666daa68 | Markus Armbruster | int drive_get_max_bus(BlockInterfaceType type)
|
68 | 666daa68 | Markus Armbruster | { |
69 | 666daa68 | Markus Armbruster | int max_bus;
|
70 | 666daa68 | Markus Armbruster | DriveInfo *dinfo; |
71 | 666daa68 | Markus Armbruster | |
72 | 666daa68 | Markus Armbruster | max_bus = -1;
|
73 | 666daa68 | Markus Armbruster | QTAILQ_FOREACH(dinfo, &drives, next) { |
74 | 666daa68 | Markus Armbruster | if(dinfo->type == type &&
|
75 | 666daa68 | Markus Armbruster | dinfo->bus > max_bus) |
76 | 666daa68 | Markus Armbruster | max_bus = dinfo->bus; |
77 | 666daa68 | Markus Armbruster | } |
78 | 666daa68 | Markus Armbruster | return max_bus;
|
79 | 666daa68 | Markus Armbruster | } |
80 | 666daa68 | Markus Armbruster | |
81 | 666daa68 | Markus Armbruster | const char *drive_get_serial(BlockDriverState *bdrv) |
82 | 666daa68 | Markus Armbruster | { |
83 | 666daa68 | Markus Armbruster | DriveInfo *dinfo; |
84 | 666daa68 | Markus Armbruster | |
85 | 666daa68 | Markus Armbruster | QTAILQ_FOREACH(dinfo, &drives, next) { |
86 | 666daa68 | Markus Armbruster | if (dinfo->bdrv == bdrv)
|
87 | 666daa68 | Markus Armbruster | return dinfo->serial;
|
88 | 666daa68 | Markus Armbruster | } |
89 | 666daa68 | Markus Armbruster | |
90 | 666daa68 | Markus Armbruster | return "\0"; |
91 | 666daa68 | Markus Armbruster | } |
92 | 666daa68 | Markus Armbruster | |
93 | 666daa68 | Markus Armbruster | BlockInterfaceErrorAction drive_get_on_error( |
94 | 666daa68 | Markus Armbruster | BlockDriverState *bdrv, int is_read)
|
95 | 666daa68 | Markus Armbruster | { |
96 | 666daa68 | Markus Armbruster | DriveInfo *dinfo; |
97 | 666daa68 | Markus Armbruster | |
98 | 666daa68 | Markus Armbruster | QTAILQ_FOREACH(dinfo, &drives, next) { |
99 | 666daa68 | Markus Armbruster | if (dinfo->bdrv == bdrv)
|
100 | 666daa68 | Markus Armbruster | return is_read ? dinfo->on_read_error : dinfo->on_write_error;
|
101 | 666daa68 | Markus Armbruster | } |
102 | 666daa68 | Markus Armbruster | |
103 | 666daa68 | Markus Armbruster | return is_read ? BLOCK_ERR_REPORT : BLOCK_ERR_STOP_ENOSPC;
|
104 | 666daa68 | Markus Armbruster | } |
105 | 666daa68 | Markus Armbruster | |
106 | 666daa68 | Markus Armbruster | static void bdrv_format_print(void *opaque, const char *name) |
107 | 666daa68 | Markus Armbruster | { |
108 | 666daa68 | Markus Armbruster | fprintf(stderr, " %s", name);
|
109 | 666daa68 | Markus Armbruster | } |
110 | 666daa68 | Markus Armbruster | |
111 | 666daa68 | Markus Armbruster | void drive_uninit(DriveInfo *dinfo)
|
112 | 666daa68 | Markus Armbruster | { |
113 | 666daa68 | Markus Armbruster | qemu_opts_del(dinfo->opts); |
114 | 666daa68 | Markus Armbruster | bdrv_delete(dinfo->bdrv); |
115 | 666daa68 | Markus Armbruster | QTAILQ_REMOVE(&drives, dinfo, next); |
116 | 666daa68 | Markus Armbruster | qemu_free(dinfo); |
117 | 666daa68 | Markus Armbruster | } |
118 | 666daa68 | Markus Armbruster | |
119 | 666daa68 | Markus Armbruster | static int parse_block_error_action(const char *buf, int is_read) |
120 | 666daa68 | Markus Armbruster | { |
121 | 666daa68 | Markus Armbruster | if (!strcmp(buf, "ignore")) { |
122 | 666daa68 | Markus Armbruster | return BLOCK_ERR_IGNORE;
|
123 | 666daa68 | Markus Armbruster | } else if (!is_read && !strcmp(buf, "enospc")) { |
124 | 666daa68 | Markus Armbruster | return BLOCK_ERR_STOP_ENOSPC;
|
125 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "stop")) { |
126 | 666daa68 | Markus Armbruster | return BLOCK_ERR_STOP_ANY;
|
127 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "report")) { |
128 | 666daa68 | Markus Armbruster | return BLOCK_ERR_REPORT;
|
129 | 666daa68 | Markus Armbruster | } else {
|
130 | 666daa68 | Markus Armbruster | fprintf(stderr, "qemu: '%s' invalid %s error action\n",
|
131 | 666daa68 | Markus Armbruster | buf, is_read ? "read" : "write"); |
132 | 666daa68 | Markus Armbruster | return -1; |
133 | 666daa68 | Markus Armbruster | } |
134 | 666daa68 | Markus Armbruster | } |
135 | 666daa68 | Markus Armbruster | |
136 | 666daa68 | Markus Armbruster | DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error) |
137 | 666daa68 | Markus Armbruster | { |
138 | 666daa68 | Markus Armbruster | const char *buf; |
139 | 666daa68 | Markus Armbruster | const char *file = NULL; |
140 | 666daa68 | Markus Armbruster | char devname[128]; |
141 | 666daa68 | Markus Armbruster | const char *serial; |
142 | 666daa68 | Markus Armbruster | const char *mediastr = ""; |
143 | 666daa68 | Markus Armbruster | BlockInterfaceType type; |
144 | 666daa68 | Markus Armbruster | enum { MEDIA_DISK, MEDIA_CDROM } media;
|
145 | 666daa68 | Markus Armbruster | int bus_id, unit_id;
|
146 | 666daa68 | Markus Armbruster | int cyls, heads, secs, translation;
|
147 | 666daa68 | Markus Armbruster | BlockDriver *drv = NULL;
|
148 | 666daa68 | Markus Armbruster | int max_devs;
|
149 | 666daa68 | Markus Armbruster | int index;
|
150 | 666daa68 | Markus Armbruster | int ro = 0; |
151 | 666daa68 | Markus Armbruster | int bdrv_flags = 0; |
152 | 666daa68 | Markus Armbruster | int on_read_error, on_write_error;
|
153 | 666daa68 | Markus Armbruster | const char *devaddr; |
154 | 666daa68 | Markus Armbruster | DriveInfo *dinfo; |
155 | 666daa68 | Markus Armbruster | int snapshot = 0; |
156 | 666daa68 | Markus Armbruster | int ret;
|
157 | 666daa68 | Markus Armbruster | |
158 | 666daa68 | Markus Armbruster | *fatal_error = 1;
|
159 | 666daa68 | Markus Armbruster | |
160 | 666daa68 | Markus Armbruster | translation = BIOS_ATA_TRANSLATION_AUTO; |
161 | 666daa68 | Markus Armbruster | |
162 | 666daa68 | Markus Armbruster | if (default_to_scsi) {
|
163 | 666daa68 | Markus Armbruster | type = IF_SCSI; |
164 | 666daa68 | Markus Armbruster | max_devs = MAX_SCSI_DEVS; |
165 | 666daa68 | Markus Armbruster | pstrcpy(devname, sizeof(devname), "scsi"); |
166 | 666daa68 | Markus Armbruster | } else {
|
167 | 666daa68 | Markus Armbruster | type = IF_IDE; |
168 | 666daa68 | Markus Armbruster | max_devs = MAX_IDE_DEVS; |
169 | 666daa68 | Markus Armbruster | pstrcpy(devname, sizeof(devname), "ide"); |
170 | 666daa68 | Markus Armbruster | } |
171 | 666daa68 | Markus Armbruster | media = MEDIA_DISK; |
172 | 666daa68 | Markus Armbruster | |
173 | 666daa68 | Markus Armbruster | /* extract parameters */
|
174 | 666daa68 | Markus Armbruster | bus_id = qemu_opt_get_number(opts, "bus", 0); |
175 | 666daa68 | Markus Armbruster | unit_id = qemu_opt_get_number(opts, "unit", -1); |
176 | 666daa68 | Markus Armbruster | index = qemu_opt_get_number(opts, "index", -1); |
177 | 666daa68 | Markus Armbruster | |
178 | 666daa68 | Markus Armbruster | cyls = qemu_opt_get_number(opts, "cyls", 0); |
179 | 666daa68 | Markus Armbruster | heads = qemu_opt_get_number(opts, "heads", 0); |
180 | 666daa68 | Markus Armbruster | secs = qemu_opt_get_number(opts, "secs", 0); |
181 | 666daa68 | Markus Armbruster | |
182 | 666daa68 | Markus Armbruster | snapshot = qemu_opt_get_bool(opts, "snapshot", 0); |
183 | 666daa68 | Markus Armbruster | ro = qemu_opt_get_bool(opts, "readonly", 0); |
184 | 666daa68 | Markus Armbruster | |
185 | 666daa68 | Markus Armbruster | file = qemu_opt_get(opts, "file");
|
186 | 666daa68 | Markus Armbruster | serial = qemu_opt_get(opts, "serial");
|
187 | 666daa68 | Markus Armbruster | |
188 | 666daa68 | Markus Armbruster | if ((buf = qemu_opt_get(opts, "if")) != NULL) { |
189 | 666daa68 | Markus Armbruster | pstrcpy(devname, sizeof(devname), buf);
|
190 | 666daa68 | Markus Armbruster | if (!strcmp(buf, "ide")) { |
191 | 666daa68 | Markus Armbruster | type = IF_IDE; |
192 | 666daa68 | Markus Armbruster | max_devs = MAX_IDE_DEVS; |
193 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "scsi")) { |
194 | 666daa68 | Markus Armbruster | type = IF_SCSI; |
195 | 666daa68 | Markus Armbruster | max_devs = MAX_SCSI_DEVS; |
196 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "floppy")) { |
197 | 666daa68 | Markus Armbruster | type = IF_FLOPPY; |
198 | 666daa68 | Markus Armbruster | max_devs = 0;
|
199 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "pflash")) { |
200 | 666daa68 | Markus Armbruster | type = IF_PFLASH; |
201 | 666daa68 | Markus Armbruster | max_devs = 0;
|
202 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "mtd")) { |
203 | 666daa68 | Markus Armbruster | type = IF_MTD; |
204 | 666daa68 | Markus Armbruster | max_devs = 0;
|
205 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "sd")) { |
206 | 666daa68 | Markus Armbruster | type = IF_SD; |
207 | 666daa68 | Markus Armbruster | max_devs = 0;
|
208 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "virtio")) { |
209 | 666daa68 | Markus Armbruster | type = IF_VIRTIO; |
210 | 666daa68 | Markus Armbruster | max_devs = 0;
|
211 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "xen")) { |
212 | 666daa68 | Markus Armbruster | type = IF_XEN; |
213 | 666daa68 | Markus Armbruster | max_devs = 0;
|
214 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "none")) { |
215 | 666daa68 | Markus Armbruster | type = IF_NONE; |
216 | 666daa68 | Markus Armbruster | max_devs = 0;
|
217 | 666daa68 | Markus Armbruster | } else {
|
218 | 666daa68 | Markus Armbruster | fprintf(stderr, "qemu: unsupported bus type '%s'\n", buf);
|
219 | 666daa68 | Markus Armbruster | return NULL; |
220 | 666daa68 | Markus Armbruster | } |
221 | 666daa68 | Markus Armbruster | } |
222 | 666daa68 | Markus Armbruster | |
223 | 666daa68 | Markus Armbruster | if (cyls || heads || secs) {
|
224 | 666daa68 | Markus Armbruster | if (cyls < 1 || (type == IF_IDE && cyls > 16383)) { |
225 | 666daa68 | Markus Armbruster | fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", buf);
|
226 | 666daa68 | Markus Armbruster | return NULL; |
227 | 666daa68 | Markus Armbruster | } |
228 | 666daa68 | Markus Armbruster | if (heads < 1 || (type == IF_IDE && heads > 16)) { |
229 | 666daa68 | Markus Armbruster | fprintf(stderr, "qemu: '%s' invalid physical heads number\n", buf);
|
230 | 666daa68 | Markus Armbruster | return NULL; |
231 | 666daa68 | Markus Armbruster | } |
232 | 666daa68 | Markus Armbruster | if (secs < 1 || (type == IF_IDE && secs > 63)) { |
233 | 666daa68 | Markus Armbruster | fprintf(stderr, "qemu: '%s' invalid physical secs number\n", buf);
|
234 | 666daa68 | Markus Armbruster | return NULL; |
235 | 666daa68 | Markus Armbruster | } |
236 | 666daa68 | Markus Armbruster | } |
237 | 666daa68 | Markus Armbruster | |
238 | 666daa68 | Markus Armbruster | if ((buf = qemu_opt_get(opts, "trans")) != NULL) { |
239 | 666daa68 | Markus Armbruster | if (!cyls) {
|
240 | 666daa68 | Markus Armbruster | fprintf(stderr, |
241 | 666daa68 | Markus Armbruster | "qemu: '%s' trans must be used with cyls,heads and secs\n",
|
242 | 666daa68 | Markus Armbruster | buf); |
243 | 666daa68 | Markus Armbruster | return NULL; |
244 | 666daa68 | Markus Armbruster | } |
245 | 666daa68 | Markus Armbruster | if (!strcmp(buf, "none")) |
246 | 666daa68 | Markus Armbruster | translation = BIOS_ATA_TRANSLATION_NONE; |
247 | 666daa68 | Markus Armbruster | else if (!strcmp(buf, "lba")) |
248 | 666daa68 | Markus Armbruster | translation = BIOS_ATA_TRANSLATION_LBA; |
249 | 666daa68 | Markus Armbruster | else if (!strcmp(buf, "auto")) |
250 | 666daa68 | Markus Armbruster | translation = BIOS_ATA_TRANSLATION_AUTO; |
251 | 666daa68 | Markus Armbruster | else {
|
252 | 666daa68 | Markus Armbruster | fprintf(stderr, "qemu: '%s' invalid translation type\n", buf);
|
253 | 666daa68 | Markus Armbruster | return NULL; |
254 | 666daa68 | Markus Armbruster | } |
255 | 666daa68 | Markus Armbruster | } |
256 | 666daa68 | Markus Armbruster | |
257 | 666daa68 | Markus Armbruster | if ((buf = qemu_opt_get(opts, "media")) != NULL) { |
258 | 666daa68 | Markus Armbruster | if (!strcmp(buf, "disk")) { |
259 | 666daa68 | Markus Armbruster | media = MEDIA_DISK; |
260 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "cdrom")) { |
261 | 666daa68 | Markus Armbruster | if (cyls || secs || heads) {
|
262 | 666daa68 | Markus Armbruster | fprintf(stderr, |
263 | 666daa68 | Markus Armbruster | "qemu: '%s' invalid physical CHS format\n", buf);
|
264 | 666daa68 | Markus Armbruster | return NULL; |
265 | 666daa68 | Markus Armbruster | } |
266 | 666daa68 | Markus Armbruster | media = MEDIA_CDROM; |
267 | 666daa68 | Markus Armbruster | } else {
|
268 | 666daa68 | Markus Armbruster | fprintf(stderr, "qemu: '%s' invalid media\n", buf);
|
269 | 666daa68 | Markus Armbruster | return NULL; |
270 | 666daa68 | Markus Armbruster | } |
271 | 666daa68 | Markus Armbruster | } |
272 | 666daa68 | Markus Armbruster | |
273 | 666daa68 | Markus Armbruster | if ((buf = qemu_opt_get(opts, "cache")) != NULL) { |
274 | 666daa68 | Markus Armbruster | if (!strcmp(buf, "off") || !strcmp(buf, "none")) { |
275 | 666daa68 | Markus Armbruster | bdrv_flags |= BDRV_O_NOCACHE; |
276 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "writeback")) { |
277 | 666daa68 | Markus Armbruster | bdrv_flags |= BDRV_O_CACHE_WB; |
278 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "unsafe")) { |
279 | 666daa68 | Markus Armbruster | bdrv_flags |= BDRV_O_CACHE_WB; |
280 | 666daa68 | Markus Armbruster | bdrv_flags |= BDRV_O_NO_FLUSH; |
281 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "writethrough")) { |
282 | 666daa68 | Markus Armbruster | /* this is the default */
|
283 | 666daa68 | Markus Armbruster | } else {
|
284 | 666daa68 | Markus Armbruster | fprintf(stderr, "qemu: invalid cache option\n");
|
285 | 666daa68 | Markus Armbruster | return NULL; |
286 | 666daa68 | Markus Armbruster | } |
287 | 666daa68 | Markus Armbruster | } |
288 | 666daa68 | Markus Armbruster | |
289 | 666daa68 | Markus Armbruster | #ifdef CONFIG_LINUX_AIO
|
290 | 666daa68 | Markus Armbruster | if ((buf = qemu_opt_get(opts, "aio")) != NULL) { |
291 | 666daa68 | Markus Armbruster | if (!strcmp(buf, "native")) { |
292 | 666daa68 | Markus Armbruster | bdrv_flags |= BDRV_O_NATIVE_AIO; |
293 | 666daa68 | Markus Armbruster | } else if (!strcmp(buf, "threads")) { |
294 | 666daa68 | Markus Armbruster | /* this is the default */
|
295 | 666daa68 | Markus Armbruster | } else {
|
296 | 666daa68 | Markus Armbruster | fprintf(stderr, "qemu: invalid aio option\n");
|
297 | 666daa68 | Markus Armbruster | return NULL; |
298 | 666daa68 | Markus Armbruster | } |
299 | 666daa68 | Markus Armbruster | } |
300 | 666daa68 | Markus Armbruster | #endif
|
301 | 666daa68 | Markus Armbruster | |
302 | 666daa68 | Markus Armbruster | if ((buf = qemu_opt_get(opts, "format")) != NULL) { |
303 | 666daa68 | Markus Armbruster | if (strcmp(buf, "?") == 0) { |
304 | 666daa68 | Markus Armbruster | fprintf(stderr, "qemu: Supported formats:");
|
305 | 666daa68 | Markus Armbruster | bdrv_iterate_format(bdrv_format_print, NULL);
|
306 | 666daa68 | Markus Armbruster | fprintf(stderr, "\n");
|
307 | 666daa68 | Markus Armbruster | return NULL; |
308 | 666daa68 | Markus Armbruster | } |
309 | 666daa68 | Markus Armbruster | drv = bdrv_find_whitelisted_format(buf); |
310 | 666daa68 | Markus Armbruster | if (!drv) {
|
311 | 666daa68 | Markus Armbruster | fprintf(stderr, "qemu: '%s' invalid format\n", buf);
|
312 | 666daa68 | Markus Armbruster | return NULL; |
313 | 666daa68 | Markus Armbruster | } |
314 | 666daa68 | Markus Armbruster | } |
315 | 666daa68 | Markus Armbruster | |
316 | 666daa68 | Markus Armbruster | on_write_error = BLOCK_ERR_STOP_ENOSPC; |
317 | 666daa68 | Markus Armbruster | if ((buf = qemu_opt_get(opts, "werror")) != NULL) { |
318 | 666daa68 | Markus Armbruster | if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
|
319 | 666daa68 | Markus Armbruster | fprintf(stderr, "werror is no supported by this format\n");
|
320 | 666daa68 | Markus Armbruster | return NULL; |
321 | 666daa68 | Markus Armbruster | } |
322 | 666daa68 | Markus Armbruster | |
323 | 666daa68 | Markus Armbruster | on_write_error = parse_block_error_action(buf, 0);
|
324 | 666daa68 | Markus Armbruster | if (on_write_error < 0) { |
325 | 666daa68 | Markus Armbruster | return NULL; |
326 | 666daa68 | Markus Armbruster | } |
327 | 666daa68 | Markus Armbruster | } |
328 | 666daa68 | Markus Armbruster | |
329 | 666daa68 | Markus Armbruster | on_read_error = BLOCK_ERR_REPORT; |
330 | 666daa68 | Markus Armbruster | if ((buf = qemu_opt_get(opts, "rerror")) != NULL) { |
331 | 666daa68 | Markus Armbruster | if (type != IF_IDE && type != IF_VIRTIO && type != IF_NONE) {
|
332 | 666daa68 | Markus Armbruster | fprintf(stderr, "rerror is no supported by this format\n");
|
333 | 666daa68 | Markus Armbruster | return NULL; |
334 | 666daa68 | Markus Armbruster | } |
335 | 666daa68 | Markus Armbruster | |
336 | 666daa68 | Markus Armbruster | on_read_error = parse_block_error_action(buf, 1);
|
337 | 666daa68 | Markus Armbruster | if (on_read_error < 0) { |
338 | 666daa68 | Markus Armbruster | return NULL; |
339 | 666daa68 | Markus Armbruster | } |
340 | 666daa68 | Markus Armbruster | } |
341 | 666daa68 | Markus Armbruster | |
342 | 666daa68 | Markus Armbruster | if ((devaddr = qemu_opt_get(opts, "addr")) != NULL) { |
343 | 666daa68 | Markus Armbruster | if (type != IF_VIRTIO) {
|
344 | 666daa68 | Markus Armbruster | fprintf(stderr, "addr is not supported\n");
|
345 | 666daa68 | Markus Armbruster | return NULL; |
346 | 666daa68 | Markus Armbruster | } |
347 | 666daa68 | Markus Armbruster | } |
348 | 666daa68 | Markus Armbruster | |
349 | 666daa68 | Markus Armbruster | /* compute bus and unit according index */
|
350 | 666daa68 | Markus Armbruster | |
351 | 666daa68 | Markus Armbruster | if (index != -1) { |
352 | 666daa68 | Markus Armbruster | if (bus_id != 0 || unit_id != -1) { |
353 | 666daa68 | Markus Armbruster | fprintf(stderr, |
354 | 666daa68 | Markus Armbruster | "qemu: index cannot be used with bus and unit\n");
|
355 | 666daa68 | Markus Armbruster | return NULL; |
356 | 666daa68 | Markus Armbruster | } |
357 | 666daa68 | Markus Armbruster | if (max_devs == 0) |
358 | 666daa68 | Markus Armbruster | { |
359 | 666daa68 | Markus Armbruster | unit_id = index; |
360 | 666daa68 | Markus Armbruster | bus_id = 0;
|
361 | 666daa68 | Markus Armbruster | } else {
|
362 | 666daa68 | Markus Armbruster | unit_id = index % max_devs; |
363 | 666daa68 | Markus Armbruster | bus_id = index / max_devs; |
364 | 666daa68 | Markus Armbruster | } |
365 | 666daa68 | Markus Armbruster | } |
366 | 666daa68 | Markus Armbruster | |
367 | 666daa68 | Markus Armbruster | /* if user doesn't specify a unit_id,
|
368 | 666daa68 | Markus Armbruster | * try to find the first free
|
369 | 666daa68 | Markus Armbruster | */
|
370 | 666daa68 | Markus Armbruster | |
371 | 666daa68 | Markus Armbruster | if (unit_id == -1) { |
372 | 666daa68 | Markus Armbruster | unit_id = 0;
|
373 | 666daa68 | Markus Armbruster | while (drive_get(type, bus_id, unit_id) != NULL) { |
374 | 666daa68 | Markus Armbruster | unit_id++; |
375 | 666daa68 | Markus Armbruster | if (max_devs && unit_id >= max_devs) {
|
376 | 666daa68 | Markus Armbruster | unit_id -= max_devs; |
377 | 666daa68 | Markus Armbruster | bus_id++; |
378 | 666daa68 | Markus Armbruster | } |
379 | 666daa68 | Markus Armbruster | } |
380 | 666daa68 | Markus Armbruster | } |
381 | 666daa68 | Markus Armbruster | |
382 | 666daa68 | Markus Armbruster | /* check unit id */
|
383 | 666daa68 | Markus Armbruster | |
384 | 666daa68 | Markus Armbruster | if (max_devs && unit_id >= max_devs) {
|
385 | 666daa68 | Markus Armbruster | fprintf(stderr, "qemu: unit %d too big (max is %d)\n",
|
386 | 666daa68 | Markus Armbruster | unit_id, max_devs - 1);
|
387 | 666daa68 | Markus Armbruster | return NULL; |
388 | 666daa68 | Markus Armbruster | } |
389 | 666daa68 | Markus Armbruster | |
390 | 666daa68 | Markus Armbruster | /*
|
391 | 666daa68 | Markus Armbruster | * ignore multiple definitions
|
392 | 666daa68 | Markus Armbruster | */
|
393 | 666daa68 | Markus Armbruster | |
394 | 666daa68 | Markus Armbruster | if (drive_get(type, bus_id, unit_id) != NULL) { |
395 | 666daa68 | Markus Armbruster | *fatal_error = 0;
|
396 | 666daa68 | Markus Armbruster | return NULL; |
397 | 666daa68 | Markus Armbruster | } |
398 | 666daa68 | Markus Armbruster | |
399 | 666daa68 | Markus Armbruster | /* init */
|
400 | 666daa68 | Markus Armbruster | |
401 | 666daa68 | Markus Armbruster | dinfo = qemu_mallocz(sizeof(*dinfo));
|
402 | 666daa68 | Markus Armbruster | if ((buf = qemu_opts_id(opts)) != NULL) { |
403 | 666daa68 | Markus Armbruster | dinfo->id = qemu_strdup(buf); |
404 | 666daa68 | Markus Armbruster | } else {
|
405 | 666daa68 | Markus Armbruster | /* no id supplied -> create one */
|
406 | 666daa68 | Markus Armbruster | dinfo->id = qemu_mallocz(32);
|
407 | 666daa68 | Markus Armbruster | if (type == IF_IDE || type == IF_SCSI)
|
408 | 666daa68 | Markus Armbruster | mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd"; |
409 | 666daa68 | Markus Armbruster | if (max_devs)
|
410 | 666daa68 | Markus Armbruster | snprintf(dinfo->id, 32, "%s%i%s%i", |
411 | 666daa68 | Markus Armbruster | devname, bus_id, mediastr, unit_id); |
412 | 666daa68 | Markus Armbruster | else
|
413 | 666daa68 | Markus Armbruster | snprintf(dinfo->id, 32, "%s%s%i", |
414 | 666daa68 | Markus Armbruster | devname, mediastr, unit_id); |
415 | 666daa68 | Markus Armbruster | } |
416 | 666daa68 | Markus Armbruster | dinfo->bdrv = bdrv_new(dinfo->id); |
417 | 666daa68 | Markus Armbruster | dinfo->devaddr = devaddr; |
418 | 666daa68 | Markus Armbruster | dinfo->type = type; |
419 | 666daa68 | Markus Armbruster | dinfo->bus = bus_id; |
420 | 666daa68 | Markus Armbruster | dinfo->unit = unit_id; |
421 | 666daa68 | Markus Armbruster | dinfo->on_read_error = on_read_error; |
422 | 666daa68 | Markus Armbruster | dinfo->on_write_error = on_write_error; |
423 | 666daa68 | Markus Armbruster | dinfo->opts = opts; |
424 | 666daa68 | Markus Armbruster | if (serial)
|
425 | 653dbec7 | Luiz Capitulino | strncpy(dinfo->serial, serial, sizeof(dinfo->serial) - 1); |
426 | 666daa68 | Markus Armbruster | QTAILQ_INSERT_TAIL(&drives, dinfo, next); |
427 | 666daa68 | Markus Armbruster | |
428 | 666daa68 | Markus Armbruster | switch(type) {
|
429 | 666daa68 | Markus Armbruster | case IF_IDE:
|
430 | 666daa68 | Markus Armbruster | case IF_SCSI:
|
431 | 666daa68 | Markus Armbruster | case IF_XEN:
|
432 | 666daa68 | Markus Armbruster | case IF_NONE:
|
433 | 666daa68 | Markus Armbruster | switch(media) {
|
434 | 666daa68 | Markus Armbruster | case MEDIA_DISK:
|
435 | 666daa68 | Markus Armbruster | if (cyls != 0) { |
436 | 666daa68 | Markus Armbruster | bdrv_set_geometry_hint(dinfo->bdrv, cyls, heads, secs); |
437 | 666daa68 | Markus Armbruster | bdrv_set_translation_hint(dinfo->bdrv, translation); |
438 | 666daa68 | Markus Armbruster | } |
439 | 666daa68 | Markus Armbruster | break;
|
440 | 666daa68 | Markus Armbruster | case MEDIA_CDROM:
|
441 | 666daa68 | Markus Armbruster | bdrv_set_type_hint(dinfo->bdrv, BDRV_TYPE_CDROM); |
442 | 666daa68 | Markus Armbruster | break;
|
443 | 666daa68 | Markus Armbruster | } |
444 | 666daa68 | Markus Armbruster | break;
|
445 | 666daa68 | Markus Armbruster | case IF_SD:
|
446 | 666daa68 | Markus Armbruster | /* FIXME: This isn't really a floppy, but it's a reasonable
|
447 | 666daa68 | Markus Armbruster | approximation. */
|
448 | 666daa68 | Markus Armbruster | case IF_FLOPPY:
|
449 | 666daa68 | Markus Armbruster | bdrv_set_type_hint(dinfo->bdrv, BDRV_TYPE_FLOPPY); |
450 | 666daa68 | Markus Armbruster | break;
|
451 | 666daa68 | Markus Armbruster | case IF_PFLASH:
|
452 | 666daa68 | Markus Armbruster | case IF_MTD:
|
453 | 666daa68 | Markus Armbruster | break;
|
454 | 666daa68 | Markus Armbruster | case IF_VIRTIO:
|
455 | 666daa68 | Markus Armbruster | /* add virtio block device */
|
456 | 666daa68 | Markus Armbruster | opts = qemu_opts_create(&qemu_device_opts, NULL, 0); |
457 | 666daa68 | Markus Armbruster | qemu_opt_set(opts, "driver", "virtio-blk-pci"); |
458 | 666daa68 | Markus Armbruster | qemu_opt_set(opts, "drive", dinfo->id);
|
459 | 666daa68 | Markus Armbruster | if (devaddr)
|
460 | 666daa68 | Markus Armbruster | qemu_opt_set(opts, "addr", devaddr);
|
461 | 666daa68 | Markus Armbruster | break;
|
462 | 666daa68 | Markus Armbruster | case IF_COUNT:
|
463 | 666daa68 | Markus Armbruster | abort(); |
464 | 666daa68 | Markus Armbruster | } |
465 | dd5b0d71 | Markus Armbruster | if (!file || !*file) {
|
466 | 666daa68 | Markus Armbruster | *fatal_error = 0;
|
467 | 666daa68 | Markus Armbruster | return NULL; |
468 | 666daa68 | Markus Armbruster | } |
469 | 666daa68 | Markus Armbruster | if (snapshot) {
|
470 | 666daa68 | Markus Armbruster | /* always use cache=unsafe with snapshot */
|
471 | 666daa68 | Markus Armbruster | bdrv_flags &= ~BDRV_O_CACHE_MASK; |
472 | 666daa68 | Markus Armbruster | bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB|BDRV_O_NO_FLUSH); |
473 | 666daa68 | Markus Armbruster | } |
474 | 666daa68 | Markus Armbruster | |
475 | 666daa68 | Markus Armbruster | if (media == MEDIA_CDROM) {
|
476 | 666daa68 | Markus Armbruster | /* CDROM is fine for any interface, don't check. */
|
477 | 666daa68 | Markus Armbruster | ro = 1;
|
478 | 666daa68 | Markus Armbruster | } else if (ro == 1) { |
479 | 666daa68 | Markus Armbruster | if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY && type != IF_NONE) {
|
480 | 666daa68 | Markus Armbruster | fprintf(stderr, "qemu: readonly flag not supported for drive with this interface\n");
|
481 | 666daa68 | Markus Armbruster | return NULL; |
482 | 666daa68 | Markus Armbruster | } |
483 | 666daa68 | Markus Armbruster | } |
484 | 666daa68 | Markus Armbruster | |
485 | 666daa68 | Markus Armbruster | bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
|
486 | 666daa68 | Markus Armbruster | |
487 | 666daa68 | Markus Armbruster | ret = bdrv_open(dinfo->bdrv, file, bdrv_flags, drv); |
488 | 666daa68 | Markus Armbruster | if (ret < 0) { |
489 | 666daa68 | Markus Armbruster | fprintf(stderr, "qemu: could not open disk image %s: %s\n",
|
490 | 666daa68 | Markus Armbruster | file, strerror(-ret)); |
491 | 666daa68 | Markus Armbruster | return NULL; |
492 | 666daa68 | Markus Armbruster | } |
493 | 666daa68 | Markus Armbruster | |
494 | 666daa68 | Markus Armbruster | if (bdrv_key_required(dinfo->bdrv))
|
495 | 666daa68 | Markus Armbruster | autostart = 0;
|
496 | 666daa68 | Markus Armbruster | *fatal_error = 0;
|
497 | 666daa68 | Markus Armbruster | return dinfo;
|
498 | 666daa68 | Markus Armbruster | } |
499 | 666daa68 | Markus Armbruster | |
500 | 666daa68 | Markus Armbruster | void do_commit(Monitor *mon, const QDict *qdict) |
501 | 666daa68 | Markus Armbruster | { |
502 | 666daa68 | Markus Armbruster | int all_devices;
|
503 | 666daa68 | Markus Armbruster | DriveInfo *dinfo; |
504 | 666daa68 | Markus Armbruster | const char *device = qdict_get_str(qdict, "device"); |
505 | 666daa68 | Markus Armbruster | |
506 | 666daa68 | Markus Armbruster | all_devices = !strcmp(device, "all");
|
507 | 666daa68 | Markus Armbruster | QTAILQ_FOREACH(dinfo, &drives, next) { |
508 | 666daa68 | Markus Armbruster | if (!all_devices)
|
509 | 666daa68 | Markus Armbruster | if (strcmp(bdrv_get_device_name(dinfo->bdrv), device))
|
510 | 666daa68 | Markus Armbruster | continue;
|
511 | 666daa68 | Markus Armbruster | bdrv_commit(dinfo->bdrv); |
512 | 666daa68 | Markus Armbruster | } |
513 | 666daa68 | Markus Armbruster | } |
514 | 666daa68 | Markus Armbruster | |
515 | 666daa68 | Markus Armbruster | static int eject_device(Monitor *mon, BlockDriverState *bs, int force) |
516 | 666daa68 | Markus Armbruster | { |
517 | 666daa68 | Markus Armbruster | if (bdrv_is_inserted(bs)) {
|
518 | 666daa68 | Markus Armbruster | if (!force) {
|
519 | 666daa68 | Markus Armbruster | if (!bdrv_is_removable(bs)) {
|
520 | 666daa68 | Markus Armbruster | qerror_report(QERR_DEVICE_NOT_REMOVABLE, |
521 | 666daa68 | Markus Armbruster | bdrv_get_device_name(bs)); |
522 | 666daa68 | Markus Armbruster | return -1; |
523 | 666daa68 | Markus Armbruster | } |
524 | 666daa68 | Markus Armbruster | if (bdrv_is_locked(bs)) {
|
525 | 666daa68 | Markus Armbruster | qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs)); |
526 | 666daa68 | Markus Armbruster | return -1; |
527 | 666daa68 | Markus Armbruster | } |
528 | 666daa68 | Markus Armbruster | } |
529 | 666daa68 | Markus Armbruster | bdrv_close(bs); |
530 | 666daa68 | Markus Armbruster | } |
531 | 666daa68 | Markus Armbruster | return 0; |
532 | 666daa68 | Markus Armbruster | } |
533 | 666daa68 | Markus Armbruster | |
534 | 666daa68 | Markus Armbruster | int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data) |
535 | 666daa68 | Markus Armbruster | { |
536 | 666daa68 | Markus Armbruster | BlockDriverState *bs; |
537 | 666daa68 | Markus Armbruster | int force = qdict_get_int(qdict, "force"); |
538 | 666daa68 | Markus Armbruster | const char *filename = qdict_get_str(qdict, "device"); |
539 | 666daa68 | Markus Armbruster | |
540 | 666daa68 | Markus Armbruster | bs = bdrv_find(filename); |
541 | 666daa68 | Markus Armbruster | if (!bs) {
|
542 | 666daa68 | Markus Armbruster | qerror_report(QERR_DEVICE_NOT_FOUND, filename); |
543 | 666daa68 | Markus Armbruster | return -1; |
544 | 666daa68 | Markus Armbruster | } |
545 | 666daa68 | Markus Armbruster | return eject_device(mon, bs, force);
|
546 | 666daa68 | Markus Armbruster | } |
547 | 666daa68 | Markus Armbruster | |
548 | 666daa68 | Markus Armbruster | int do_block_set_passwd(Monitor *mon, const QDict *qdict, |
549 | 666daa68 | Markus Armbruster | QObject **ret_data) |
550 | 666daa68 | Markus Armbruster | { |
551 | 666daa68 | Markus Armbruster | BlockDriverState *bs; |
552 | 666daa68 | Markus Armbruster | int err;
|
553 | 666daa68 | Markus Armbruster | |
554 | 666daa68 | Markus Armbruster | bs = bdrv_find(qdict_get_str(qdict, "device"));
|
555 | 666daa68 | Markus Armbruster | if (!bs) {
|
556 | 666daa68 | Markus Armbruster | qerror_report(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device"));
|
557 | 666daa68 | Markus Armbruster | return -1; |
558 | 666daa68 | Markus Armbruster | } |
559 | 666daa68 | Markus Armbruster | |
560 | 666daa68 | Markus Armbruster | err = bdrv_set_key(bs, qdict_get_str(qdict, "password"));
|
561 | 666daa68 | Markus Armbruster | if (err == -EINVAL) {
|
562 | 666daa68 | Markus Armbruster | qerror_report(QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs)); |
563 | 666daa68 | Markus Armbruster | return -1; |
564 | 666daa68 | Markus Armbruster | } else if (err < 0) { |
565 | 666daa68 | Markus Armbruster | qerror_report(QERR_INVALID_PASSWORD); |
566 | 666daa68 | Markus Armbruster | return -1; |
567 | 666daa68 | Markus Armbruster | } |
568 | 666daa68 | Markus Armbruster | |
569 | 666daa68 | Markus Armbruster | return 0; |
570 | 666daa68 | Markus Armbruster | } |
571 | 666daa68 | Markus Armbruster | |
572 | 666daa68 | Markus Armbruster | int do_change_block(Monitor *mon, const char *device, |
573 | 666daa68 | Markus Armbruster | const char *filename, const char *fmt) |
574 | 666daa68 | Markus Armbruster | { |
575 | 666daa68 | Markus Armbruster | BlockDriverState *bs; |
576 | 666daa68 | Markus Armbruster | BlockDriver *drv = NULL;
|
577 | 666daa68 | Markus Armbruster | int bdrv_flags;
|
578 | 666daa68 | Markus Armbruster | |
579 | 666daa68 | Markus Armbruster | bs = bdrv_find(device); |
580 | 666daa68 | Markus Armbruster | if (!bs) {
|
581 | 666daa68 | Markus Armbruster | qerror_report(QERR_DEVICE_NOT_FOUND, device); |
582 | 666daa68 | Markus Armbruster | return -1; |
583 | 666daa68 | Markus Armbruster | } |
584 | 666daa68 | Markus Armbruster | if (fmt) {
|
585 | 666daa68 | Markus Armbruster | drv = bdrv_find_whitelisted_format(fmt); |
586 | 666daa68 | Markus Armbruster | if (!drv) {
|
587 | 666daa68 | Markus Armbruster | qerror_report(QERR_INVALID_BLOCK_FORMAT, fmt); |
588 | 666daa68 | Markus Armbruster | return -1; |
589 | 666daa68 | Markus Armbruster | } |
590 | 666daa68 | Markus Armbruster | } |
591 | 666daa68 | Markus Armbruster | if (eject_device(mon, bs, 0) < 0) { |
592 | 666daa68 | Markus Armbruster | return -1; |
593 | 666daa68 | Markus Armbruster | } |
594 | 666daa68 | Markus Armbruster | bdrv_flags = bdrv_get_type_hint(bs) == BDRV_TYPE_CDROM ? 0 : BDRV_O_RDWR;
|
595 | 666daa68 | Markus Armbruster | if (bdrv_open(bs, filename, bdrv_flags, drv) < 0) { |
596 | 666daa68 | Markus Armbruster | qerror_report(QERR_OPEN_FILE_FAILED, filename); |
597 | 666daa68 | Markus Armbruster | return -1; |
598 | 666daa68 | Markus Armbruster | } |
599 | 666daa68 | Markus Armbruster | return monitor_read_bdrv_key_start(mon, bs, NULL, NULL); |
600 | 666daa68 | Markus Armbruster | } |