]> Git Repo - qemu.git/blob - hw/block/xen-block.c
475a67845d12dd05600ce68a21fe92f26b71f6eb
[qemu.git] / hw / block / xen-block.c
1 /*
2  * Copyright (c) 2018  Citrix Systems Inc.
3  *
4  * This work is licensed under the terms of the GNU GPL, version 2 or later.
5  * See the COPYING file in the top-level directory.
6  */
7
8 #include "qemu/osdep.h"
9 #include "qemu/cutils.h"
10 #include "qemu/option.h"
11 #include "qapi/error.h"
12 #include "qapi/qapi-commands-block-core.h"
13 #include "qapi/qapi-commands-misc.h"
14 #include "qapi/qapi-visit-block-core.h"
15 #include "qapi/qobject-input-visitor.h"
16 #include "qapi/visitor.h"
17 #include "qapi/qmp/qdict.h"
18 #include "qapi/qmp/qstring.h"
19 #include "hw/hw.h"
20 #include "hw/xen/xen_common.h"
21 #include "hw/block/xen_blkif.h"
22 #include "hw/xen/xen-block.h"
23 #include "hw/xen/xen-backend.h"
24 #include "sysemu/blockdev.h"
25 #include "sysemu/block-backend.h"
26 #include "sysemu/iothread.h"
27 #include "dataplane/xen-block.h"
28 #include "trace.h"
29
30 static char *xen_block_get_name(XenDevice *xendev, Error **errp)
31 {
32     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
33     XenBlockVdev *vdev = &blockdev->props.vdev;
34
35     return g_strdup_printf("%lu", vdev->number);
36 }
37
38 static void xen_block_disconnect(XenDevice *xendev, Error **errp)
39 {
40     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
41     const char *type = object_get_typename(OBJECT(blockdev));
42     XenBlockVdev *vdev = &blockdev->props.vdev;
43
44     trace_xen_block_disconnect(type, vdev->disk, vdev->partition);
45
46     xen_block_dataplane_stop(blockdev->dataplane);
47 }
48
49 static void xen_block_connect(XenDevice *xendev, Error **errp)
50 {
51     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
52     const char *type = object_get_typename(OBJECT(blockdev));
53     XenBlockVdev *vdev = &blockdev->props.vdev;
54     unsigned int order, nr_ring_ref, *ring_ref, event_channel, protocol;
55     char *str;
56
57     trace_xen_block_connect(type, vdev->disk, vdev->partition);
58
59     if (xen_device_frontend_scanf(xendev, "ring-page-order", "%u",
60                                   &order) != 1) {
61         nr_ring_ref = 1;
62         ring_ref = g_new(unsigned int, nr_ring_ref);
63
64         if (xen_device_frontend_scanf(xendev, "ring-ref", "%u",
65                                       &ring_ref[0]) != 1) {
66             error_setg(errp, "failed to read ring-ref");
67             g_free(ring_ref);
68             return;
69         }
70     } else if (order <= blockdev->props.max_ring_page_order) {
71         unsigned int i;
72
73         nr_ring_ref = 1 << order;
74         ring_ref = g_new(unsigned int, nr_ring_ref);
75
76         for (i = 0; i < nr_ring_ref; i++) {
77             const char *key = g_strdup_printf("ring-ref%u", i);
78
79             if (xen_device_frontend_scanf(xendev, key, "%u",
80                                           &ring_ref[i]) != 1) {
81                 error_setg(errp, "failed to read %s", key);
82                 g_free((gpointer)key);
83                 g_free(ring_ref);
84                 return;
85             }
86
87             g_free((gpointer)key);
88         }
89     } else {
90         error_setg(errp, "invalid ring-page-order (%d)", order);
91         return;
92     }
93
94     if (xen_device_frontend_scanf(xendev, "event-channel", "%u",
95                                   &event_channel) != 1) {
96         error_setg(errp, "failed to read event-channel");
97         g_free(ring_ref);
98         return;
99     }
100
101     if (xen_device_frontend_scanf(xendev, "protocol", "%ms",
102                                   &str) != 1) {
103         protocol = BLKIF_PROTOCOL_NATIVE;
104     } else {
105         if (strcmp(str, XEN_IO_PROTO_ABI_X86_32) == 0) {
106             protocol = BLKIF_PROTOCOL_X86_32;
107         } else if (strcmp(str, XEN_IO_PROTO_ABI_X86_64) == 0) {
108             protocol = BLKIF_PROTOCOL_X86_64;
109         } else {
110             protocol = BLKIF_PROTOCOL_NATIVE;
111         }
112
113         free(str);
114     }
115
116     xen_block_dataplane_start(blockdev->dataplane, ring_ref, nr_ring_ref,
117                               event_channel, protocol, errp);
118
119     g_free(ring_ref);
120 }
121
122 static void xen_block_unrealize(XenDevice *xendev, Error **errp)
123 {
124     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
125     XenBlockDeviceClass *blockdev_class =
126         XEN_BLOCK_DEVICE_GET_CLASS(xendev);
127     const char *type = object_get_typename(OBJECT(blockdev));
128     XenBlockVdev *vdev = &blockdev->props.vdev;
129
130     if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID) {
131         return;
132     }
133
134     trace_xen_block_unrealize(type, vdev->disk, vdev->partition);
135
136     /* Disconnect from the frontend in case this has not already happened */
137     xen_block_disconnect(xendev, NULL);
138
139     xen_block_dataplane_destroy(blockdev->dataplane);
140     blockdev->dataplane = NULL;
141
142     if (blockdev_class->unrealize) {
143         blockdev_class->unrealize(blockdev, errp);
144     }
145 }
146
147 static void xen_block_set_size(XenBlockDevice *blockdev)
148 {
149     const char *type = object_get_typename(OBJECT(blockdev));
150     XenBlockVdev *vdev = &blockdev->props.vdev;
151     BlockConf *conf = &blockdev->props.conf;
152     int64_t sectors = blk_getlength(conf->blk) / conf->logical_block_size;
153     XenDevice *xendev = XEN_DEVICE(blockdev);
154
155     trace_xen_block_size(type, vdev->disk, vdev->partition, sectors);
156
157     xen_device_backend_printf(xendev, "sectors", "%"PRIi64, sectors);
158 }
159
160 static void xen_block_resize_cb(void *opaque)
161 {
162     XenBlockDevice *blockdev = opaque;
163     XenDevice *xendev = XEN_DEVICE(blockdev);
164     enum xenbus_state state = xen_device_backend_get_state(xendev);
165
166     xen_block_set_size(blockdev);
167
168     /*
169      * Mimic the behaviour of Linux xen-blkback and re-write the state
170      * to trigger the frontend watch.
171      */
172     xen_device_backend_printf(xendev, "state", "%u", state);
173 }
174
175 static const BlockDevOps xen_block_dev_ops = {
176     .resize_cb = xen_block_resize_cb,
177 };
178
179 static void xen_block_realize(XenDevice *xendev, Error **errp)
180 {
181     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
182     XenBlockDeviceClass *blockdev_class =
183         XEN_BLOCK_DEVICE_GET_CLASS(xendev);
184     const char *type = object_get_typename(OBJECT(blockdev));
185     XenBlockVdev *vdev = &blockdev->props.vdev;
186     BlockConf *conf = &blockdev->props.conf;
187     Error *local_err = NULL;
188
189     if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID) {
190         error_setg(errp, "vdev property not set");
191         return;
192     }
193
194     trace_xen_block_realize(type, vdev->disk, vdev->partition);
195
196     if (blockdev_class->realize) {
197         blockdev_class->realize(blockdev, &local_err);
198         if (local_err) {
199             error_propagate(errp, local_err);
200             return;
201         }
202     }
203
204     /*
205      * The blkif protocol does not deal with removable media, so it must
206      * always be present, even for CDRom devices.
207      */
208     assert(conf->blk);
209     if (!blk_is_inserted(conf->blk)) {
210         error_setg(errp, "device needs media, but drive is empty");
211         return;
212     }
213
214     if (!blkconf_apply_backend_options(conf, blockdev->info & VDISK_READONLY,
215                                        true, errp)) {
216         return;
217     }
218
219     if (!(blockdev->info & VDISK_CDROM) &&
220         !blkconf_geometry(conf, NULL, 65535, 255, 255, errp)) {
221         return;
222     }
223
224     blkconf_blocksizes(conf);
225
226     if (conf->logical_block_size > conf->physical_block_size) {
227         error_setg(
228             errp, "logical_block_size > physical_block_size not supported");
229         return;
230     }
231
232     blk_set_dev_ops(conf->blk, &xen_block_dev_ops, blockdev);
233     blk_set_guest_block_size(conf->blk, conf->logical_block_size);
234
235     if (conf->discard_granularity == -1) {
236         conf->discard_granularity = conf->physical_block_size;
237     }
238
239     if (blk_get_flags(conf->blk) & BDRV_O_UNMAP) {
240         xen_device_backend_printf(xendev, "feature-discard", "%u", 1);
241         xen_device_backend_printf(xendev, "discard-granularity", "%u",
242                                   conf->discard_granularity);
243     }
244
245     xen_device_backend_printf(xendev, "feature-flush-cache", "%u", 1);
246     xen_device_backend_printf(xendev, "max-ring-page-order", "%u",
247                               blockdev->props.max_ring_page_order);
248     xen_device_backend_printf(xendev, "info", "%u", blockdev->info);
249
250     xen_device_frontend_printf(xendev, "virtual-device", "%lu",
251                                vdev->number);
252     xen_device_frontend_printf(xendev, "device-type", "%s",
253                                blockdev->device_type);
254
255     xen_device_backend_printf(xendev, "sector-size", "%u",
256                               conf->logical_block_size);
257
258     xen_block_set_size(blockdev);
259
260     blockdev->dataplane =
261         xen_block_dataplane_create(xendev, conf, blockdev->props.iothread);
262 }
263
264 static void xen_block_frontend_changed(XenDevice *xendev,
265                                        enum xenbus_state frontend_state,
266                                        Error **errp)
267 {
268     enum xenbus_state backend_state = xen_device_backend_get_state(xendev);
269     Error *local_err = NULL;
270
271     switch (frontend_state) {
272     case XenbusStateInitialised:
273     case XenbusStateConnected:
274         if (backend_state == XenbusStateConnected) {
275             break;
276         }
277
278         xen_block_disconnect(xendev, &local_err);
279         if (local_err) {
280             error_propagate(errp, local_err);
281             break;
282         }
283
284         xen_block_connect(xendev, &local_err);
285         if (local_err) {
286             error_propagate(errp, local_err);
287             break;
288         }
289
290         xen_device_backend_set_state(xendev, XenbusStateConnected);
291         break;
292
293     case XenbusStateClosing:
294         xen_device_backend_set_state(xendev, XenbusStateClosing);
295         break;
296
297     case XenbusStateClosed:
298         xen_block_disconnect(xendev, &local_err);
299         if (local_err) {
300             error_propagate(errp, local_err);
301             break;
302         }
303
304         xen_device_backend_set_state(xendev, XenbusStateClosed);
305         break;
306
307     default:
308         break;
309     }
310 }
311
312 static char *disk_to_vbd_name(unsigned int disk)
313 {
314     char *name, *prefix = (disk >= 26) ?
315         disk_to_vbd_name((disk / 26) - 1) : g_strdup("");
316
317     name = g_strdup_printf("%s%c", prefix, 'a' + disk % 26);
318     g_free(prefix);
319
320     return name;
321 }
322
323 static void xen_block_get_vdev(Object *obj, Visitor *v, const char *name,
324                                void *opaque, Error **errp)
325 {
326     DeviceState *dev = DEVICE(obj);
327     Property *prop = opaque;
328     XenBlockVdev *vdev = qdev_get_prop_ptr(dev, prop);
329     char *str;
330
331     switch (vdev->type) {
332     case XEN_BLOCK_VDEV_TYPE_DP:
333         str = g_strdup_printf("d%lup%lu", vdev->disk, vdev->partition);
334         break;
335
336     case XEN_BLOCK_VDEV_TYPE_XVD:
337     case XEN_BLOCK_VDEV_TYPE_HD:
338     case XEN_BLOCK_VDEV_TYPE_SD: {
339         char *name = disk_to_vbd_name(vdev->disk);
340
341         str = g_strdup_printf("%s%s%lu",
342                               (vdev->type == XEN_BLOCK_VDEV_TYPE_XVD) ?
343                               "xvd" :
344                               (vdev->type == XEN_BLOCK_VDEV_TYPE_HD) ?
345                               "hd" :
346                               "sd",
347                               name, vdev->partition);
348         g_free(name);
349         break;
350     }
351     default:
352         error_setg(errp, "invalid vdev type");
353         return;
354     }
355
356     visit_type_str(v, name, &str, errp);
357     g_free(str);
358 }
359
360 static int vbd_name_to_disk(const char *name, const char **endp,
361                             unsigned long *disk)
362 {
363     unsigned int n = 0;
364
365     while (*name != '\0') {
366         if (!g_ascii_isalpha(*name) || !g_ascii_islower(*name)) {
367             break;
368         }
369
370         n *= 26;
371         n += *name++ - 'a' + 1;
372     }
373     *endp = name;
374
375     if (!n) {
376         return -1;
377     }
378
379     *disk = n - 1;
380
381     return 0;
382 }
383
384 static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name,
385                                void *opaque, Error **errp)
386 {
387     DeviceState *dev = DEVICE(obj);
388     Property *prop = opaque;
389     XenBlockVdev *vdev = qdev_get_prop_ptr(dev, prop);
390     Error *local_err = NULL;
391     char *str, *p;
392     const char *end;
393
394     if (dev->realized) {
395         qdev_prop_set_after_realize(dev, name, errp);
396         return;
397     }
398
399     visit_type_str(v, name, &str, &local_err);
400     if (local_err) {
401         error_propagate(errp, local_err);
402         return;
403     }
404
405     p = strchr(str, 'd');
406     if (!p) {
407         goto invalid;
408     }
409
410     *p++ = '\0';
411     if (*str == '\0') {
412         vdev->type = XEN_BLOCK_VDEV_TYPE_DP;
413     } else if (strcmp(str, "xv") == 0) {
414         vdev->type = XEN_BLOCK_VDEV_TYPE_XVD;
415     } else if (strcmp(str, "h") == 0) {
416         vdev->type = XEN_BLOCK_VDEV_TYPE_HD;
417     } else if (strcmp(str, "s") == 0) {
418         vdev->type = XEN_BLOCK_VDEV_TYPE_SD;
419     } else {
420         goto invalid;
421     }
422
423     if (vdev->type == XEN_BLOCK_VDEV_TYPE_DP) {
424         if (qemu_strtoul(p, &end, 10, &vdev->disk)) {
425             goto invalid;
426         }
427
428         if (*end == 'p') {
429             if (*(++end) == '\0') {
430                 goto invalid;
431             }
432         }
433     } else {
434         if (vbd_name_to_disk(p, &end, &vdev->disk)) {
435             goto invalid;
436         }
437     }
438
439     if (*end != '\0') {
440         p = (char *)end;
441
442         if (qemu_strtoul(p, &end, 10, &vdev->partition)) {
443             goto invalid;
444         }
445
446         if (*end != '\0') {
447             goto invalid;
448         }
449     } else {
450         vdev->partition = 0;
451     }
452
453     switch (vdev->type) {
454     case XEN_BLOCK_VDEV_TYPE_DP:
455     case XEN_BLOCK_VDEV_TYPE_XVD:
456         if (vdev->disk < (1 << 4) && vdev->partition < (1 << 4)) {
457             vdev->number = (202 << 8) | (vdev->disk << 4) |
458                 vdev->partition;
459         } else if (vdev->disk < (1 << 20) && vdev->partition < (1 << 8)) {
460             vdev->number = (1 << 28) | (vdev->disk << 8) |
461                 vdev->partition;
462         } else {
463             goto invalid;
464         }
465         break;
466
467     case XEN_BLOCK_VDEV_TYPE_HD:
468         if ((vdev->disk == 0 || vdev->disk == 1) &&
469             vdev->partition < (1 << 6)) {
470             vdev->number = (3 << 8) | (vdev->disk << 6) | vdev->partition;
471         } else if ((vdev->disk == 2 || vdev->disk == 3) &&
472                    vdev->partition < (1 << 6)) {
473             vdev->number = (22 << 8) | ((vdev->disk - 2) << 6) |
474                 vdev->partition;
475         } else {
476             goto invalid;
477         }
478         break;
479
480     case XEN_BLOCK_VDEV_TYPE_SD:
481         if (vdev->disk < (1 << 4) && vdev->partition < (1 << 4)) {
482             vdev->number = (8 << 8) | (vdev->disk << 4) | vdev->partition;
483         } else {
484             goto invalid;
485         }
486         break;
487
488     default:
489         goto invalid;
490     }
491
492     g_free(str);
493     return;
494
495 invalid:
496     error_setg(errp, "invalid virtual disk specifier");
497
498     vdev->type = XEN_BLOCK_VDEV_TYPE_INVALID;
499     g_free(str);
500 }
501
502 /*
503  * This property deals with 'vdev' names adhering to the Xen VBD naming
504  * scheme described in:
505  *
506  * https://xenbits.xen.org/docs/unstable/man/xen-vbd-interface.7.html
507  */
508 const PropertyInfo xen_block_prop_vdev = {
509     .name  = "str",
510     .description = "Virtual Disk specifier: d*p*/xvd*/hd*/sd*",
511     .get = xen_block_get_vdev,
512     .set = xen_block_set_vdev,
513 };
514
515 static Property xen_block_props[] = {
516     DEFINE_PROP("vdev", XenBlockDevice, props.vdev,
517                 xen_block_prop_vdev, XenBlockVdev),
518     DEFINE_BLOCK_PROPERTIES(XenBlockDevice, props.conf),
519     DEFINE_PROP_UINT32("max-ring-page-order", XenBlockDevice,
520                        props.max_ring_page_order, 4),
521     DEFINE_PROP_LINK("iothread", XenBlockDevice, props.iothread,
522                      TYPE_IOTHREAD, IOThread *),
523     DEFINE_PROP_END_OF_LIST()
524 };
525
526 static void xen_block_class_init(ObjectClass *class, void *data)
527 {
528     DeviceClass *dev_class = DEVICE_CLASS(class);
529     XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class);
530
531     xendev_class->backend = "qdisk";
532     xendev_class->device = "vbd";
533     xendev_class->get_name = xen_block_get_name;
534     xendev_class->realize = xen_block_realize;
535     xendev_class->frontend_changed = xen_block_frontend_changed;
536     xendev_class->unrealize = xen_block_unrealize;
537
538     dev_class->props = xen_block_props;
539 }
540
541 static const TypeInfo xen_block_type_info = {
542     .name = TYPE_XEN_BLOCK_DEVICE,
543     .parent = TYPE_XEN_DEVICE,
544     .instance_size = sizeof(XenBlockDevice),
545     .abstract = true,
546     .class_size = sizeof(XenBlockDeviceClass),
547     .class_init = xen_block_class_init,
548 };
549
550 static void xen_disk_unrealize(XenBlockDevice *blockdev, Error **errp)
551 {
552     trace_xen_disk_unrealize();
553 }
554
555 static void xen_disk_realize(XenBlockDevice *blockdev, Error **errp)
556 {
557     BlockConf *conf = &blockdev->props.conf;
558
559     trace_xen_disk_realize();
560
561     blockdev->device_type = "disk";
562
563     if (!conf->blk) {
564         error_setg(errp, "drive property not set");
565         return;
566     }
567
568     blockdev->info = blk_is_read_only(conf->blk) ? VDISK_READONLY : 0;
569 }
570
571 static void xen_disk_class_init(ObjectClass *class, void *data)
572 {
573     DeviceClass *dev_class = DEVICE_CLASS(class);
574     XenBlockDeviceClass *blockdev_class = XEN_BLOCK_DEVICE_CLASS(class);
575
576     blockdev_class->realize = xen_disk_realize;
577     blockdev_class->unrealize = xen_disk_unrealize;
578
579     dev_class->desc = "Xen Disk Device";
580 }
581
582 static const TypeInfo xen_disk_type_info = {
583     .name = TYPE_XEN_DISK_DEVICE,
584     .parent = TYPE_XEN_BLOCK_DEVICE,
585     .instance_size = sizeof(XenDiskDevice),
586     .class_init = xen_disk_class_init,
587 };
588
589 static void xen_cdrom_unrealize(XenBlockDevice *blockdev, Error **errp)
590 {
591     trace_xen_cdrom_unrealize();
592 }
593
594 static void xen_cdrom_realize(XenBlockDevice *blockdev, Error **errp)
595 {
596     BlockConf *conf = &blockdev->props.conf;
597
598     trace_xen_cdrom_realize();
599
600     blockdev->device_type = "cdrom";
601
602     if (!conf->blk) {
603         int rc;
604
605         /* Set up an empty drive */
606         conf->blk = blk_new(0, BLK_PERM_ALL);
607
608         rc = blk_attach_dev(conf->blk, DEVICE(blockdev));
609         if (!rc) {
610             error_setg_errno(errp, -rc, "failed to create drive");
611             return;
612         }
613     }
614
615     blockdev->info = VDISK_READONLY | VDISK_CDROM;
616 }
617
618 static void xen_cdrom_class_init(ObjectClass *class, void *data)
619 {
620     DeviceClass *dev_class = DEVICE_CLASS(class);
621     XenBlockDeviceClass *blockdev_class = XEN_BLOCK_DEVICE_CLASS(class);
622
623     blockdev_class->realize = xen_cdrom_realize;
624     blockdev_class->unrealize = xen_cdrom_unrealize;
625
626     dev_class->desc = "Xen CD-ROM Device";
627 }
628
629 static const TypeInfo xen_cdrom_type_info = {
630     .name = TYPE_XEN_CDROM_DEVICE,
631     .parent = TYPE_XEN_BLOCK_DEVICE,
632     .instance_size = sizeof(XenCDRomDevice),
633     .class_init = xen_cdrom_class_init,
634 };
635
636 static void xen_block_register_types(void)
637 {
638     type_register_static(&xen_block_type_info);
639     type_register_static(&xen_disk_type_info);
640     type_register_static(&xen_cdrom_type_info);
641 }
642
643 type_init(xen_block_register_types)
644
645 static void xen_block_blockdev_del(const char *node_name, Error **errp)
646 {
647     trace_xen_block_blockdev_del(node_name);
648
649     qmp_blockdev_del(node_name, errp);
650 }
651
652 static char *xen_block_blockdev_add(const char *id, QDict *qdict,
653                                     Error **errp)
654 {
655     const char *driver = qdict_get_try_str(qdict, "driver");
656     BlockdevOptions *options = NULL;
657     Error *local_err = NULL;
658     char *node_name;
659     Visitor *v;
660
661     if (!driver) {
662         error_setg(errp, "no 'driver' parameter");
663         return NULL;
664     }
665
666     node_name = g_strdup_printf("%s-%s", id, driver);
667     qdict_put_str(qdict, "node-name", node_name);
668
669     trace_xen_block_blockdev_add(node_name);
670
671     v = qobject_input_visitor_new(QOBJECT(qdict));
672     visit_type_BlockdevOptions(v, NULL, &options, &local_err);
673     visit_free(v);
674
675     if (local_err) {
676         error_propagate(errp, local_err);
677         goto fail;
678     }
679
680     qmp_blockdev_add(options, &local_err);
681
682     if (local_err) {
683         error_propagate(errp, local_err);
684         goto fail;
685     }
686
687     qapi_free_BlockdevOptions(options);
688
689     return node_name;
690
691 fail:
692     if (options) {
693         qapi_free_BlockdevOptions(options);
694     }
695     g_free(node_name);
696
697     return NULL;
698 }
699
700 static void xen_block_drive_destroy(XenBlockDrive *drive, Error **errp)
701 {
702     char *node_name = drive->node_name;
703
704     if (node_name) {
705         Error *local_err = NULL;
706
707         xen_block_blockdev_del(node_name, &local_err);
708         if (local_err) {
709             error_propagate(errp, local_err);
710             return;
711         }
712         g_free(node_name);
713         drive->node_name = NULL;
714     }
715     g_free(drive->id);
716     g_free(drive);
717 }
718
719 static XenBlockDrive *xen_block_drive_create(const char *id,
720                                              const char *device_type,
721                                              QDict *opts, Error **errp)
722 {
723     const char *params = qdict_get_try_str(opts, "params");
724     const char *mode = qdict_get_try_str(opts, "mode");
725     const char *direct_io_safe = qdict_get_try_str(opts, "direct-io-safe");
726     const char *discard_enable = qdict_get_try_str(opts, "discard-enable");
727     char *driver = NULL;
728     char *filename = NULL;
729     XenBlockDrive *drive = NULL;
730     Error *local_err = NULL;
731     QDict *file_layer;
732     QDict *driver_layer;
733
734     if (params) {
735         char **v = g_strsplit(params, ":", 2);
736
737         if (v[1] == NULL) {
738             filename = g_strdup(v[0]);
739             driver = g_strdup("raw");
740         } else {
741             if (strcmp(v[0], "aio") == 0) {
742                 driver = g_strdup("raw");
743             } else if (strcmp(v[0], "vhd") == 0) {
744                 driver = g_strdup("vpc");
745             } else {
746                 driver = g_strdup(v[0]);
747             }
748             filename = g_strdup(v[1]);
749         }
750
751         g_strfreev(v);
752     } else {
753         error_setg(errp, "no params");
754         goto done;
755     }
756
757     assert(filename);
758     assert(driver);
759
760     drive = g_new0(XenBlockDrive, 1);
761     drive->id = g_strdup(id);
762
763     file_layer = qdict_new();
764     driver_layer = qdict_new();
765
766     qdict_put_str(file_layer, "driver", "file");
767     qdict_put_str(file_layer, "filename", filename);
768     g_free(filename);
769
770     if (mode && *mode != 'w') {
771         qdict_put_bool(file_layer, "read-only", true);
772     }
773
774     if (direct_io_safe) {
775         unsigned long value;
776
777         if (!qemu_strtoul(direct_io_safe, NULL, 2, &value) && !!value) {
778             QDict *cache_qdict = qdict_new();
779
780             qdict_put_bool(cache_qdict, "direct", true);
781             qdict_put(file_layer, "cache", cache_qdict);
782
783             qdict_put_str(file_layer, "aio", "native");
784         }
785     }
786
787     if (discard_enable) {
788         unsigned long value;
789
790         if (!qemu_strtoul(discard_enable, NULL, 2, &value) && !!value) {
791             qdict_put_str(file_layer, "discard", "unmap");
792             qdict_put_str(driver_layer, "discard", "unmap");
793         }
794     }
795
796     /*
797      * It is necessary to turn file locking off as an emulated device
798      * may have already opened the same image file.
799      */
800     qdict_put_str(file_layer, "locking", "off");
801
802     qdict_put_str(driver_layer, "driver", driver);
803     g_free(driver);
804
805     qdict_put(driver_layer, "file", file_layer);
806
807     g_assert(!drive->node_name);
808     drive->node_name = xen_block_blockdev_add(drive->id, driver_layer,
809                                               &local_err);
810
811     qobject_unref(driver_layer);
812
813 done:
814     if (local_err) {
815         error_propagate(errp, local_err);
816         xen_block_drive_destroy(drive, NULL);
817         return NULL;
818     }
819
820     return drive;
821 }
822
823 static const char *xen_block_drive_get_node_name(XenBlockDrive *drive)
824 {
825     return drive->node_name ? drive->node_name : "";
826 }
827
828 static void xen_block_iothread_destroy(XenBlockIOThread *iothread,
829                                        Error **errp)
830 {
831     qmp_object_del(iothread->id, errp);
832
833     g_free(iothread->id);
834     g_free(iothread);
835 }
836
837 static XenBlockIOThread *xen_block_iothread_create(const char *id,
838                                                    Error **errp)
839 {
840     XenBlockIOThread *iothread = g_new(XenBlockIOThread, 1);
841     Error *local_err = NULL;
842
843     iothread->id = g_strdup(id);
844
845     qmp_object_add(TYPE_IOTHREAD, id, false, NULL, &local_err);
846     if (local_err) {
847         error_propagate(errp, local_err);
848
849         g_free(iothread->id);
850         g_free(iothread);
851         return NULL;
852     }
853
854     return iothread;
855 }
856
857 static void xen_block_device_create(XenBackendInstance *backend,
858                                     QDict *opts, Error **errp)
859 {
860     XenBus *xenbus = xen_backend_get_bus(backend);
861     const char *name = xen_backend_get_name(backend);
862     unsigned long number;
863     const char *vdev, *device_type;
864     XenBlockDrive *drive = NULL;
865     XenBlockIOThread *iothread = NULL;
866     XenDevice *xendev = NULL;
867     Error *local_err = NULL;
868     const char *type;
869     XenBlockDevice *blockdev;
870
871     if (qemu_strtoul(name, NULL, 10, &number)) {
872         error_setg(errp, "failed to parse name '%s'", name);
873         goto fail;
874     }
875
876     trace_xen_block_device_create(number);
877
878     vdev = qdict_get_try_str(opts, "dev");
879     if (!vdev) {
880         error_setg(errp, "no dev parameter");
881         goto fail;
882     }
883
884     device_type = qdict_get_try_str(opts, "device-type");
885     if (!device_type) {
886         error_setg(errp, "no device-type parameter");
887         goto fail;
888     }
889
890     if (!strcmp(device_type, "disk")) {
891         type = TYPE_XEN_DISK_DEVICE;
892     } else if (!strcmp(device_type, "cdrom")) {
893         type = TYPE_XEN_CDROM_DEVICE;
894     } else {
895         error_setg(errp, "invalid device-type parameter '%s'", device_type);
896         goto fail;
897     }
898
899     drive = xen_block_drive_create(vdev, device_type, opts, &local_err);
900     if (!drive) {
901         error_propagate_prepend(errp, local_err, "failed to create drive: ");
902         goto fail;
903     }
904
905     iothread = xen_block_iothread_create(vdev, &local_err);
906     if (local_err) {
907         error_propagate_prepend(errp, local_err,
908                                 "failed to create iothread: ");
909         goto fail;
910     }
911
912     xendev = XEN_DEVICE(qdev_create(BUS(xenbus), type));
913     blockdev = XEN_BLOCK_DEVICE(xendev);
914
915     object_property_set_str(OBJECT(xendev), vdev, "vdev", &local_err);
916     if (local_err) {
917         error_propagate_prepend(errp, local_err, "failed to set 'vdev': ");
918         goto fail;
919     }
920
921     object_property_set_str(OBJECT(xendev),
922                             xen_block_drive_get_node_name(drive), "drive",
923                             &local_err);
924     if (local_err) {
925         error_propagate_prepend(errp, local_err, "failed to set 'drive': ");
926         goto fail;
927     }
928
929     object_property_set_str(OBJECT(xendev), iothread->id, "iothread",
930                             &local_err);
931     if (local_err) {
932         error_propagate_prepend(errp, local_err,
933                                 "failed to set 'iothread': ");
934         goto fail;
935     }
936
937     blockdev->iothread = iothread;
938     blockdev->drive = drive;
939
940     object_property_set_bool(OBJECT(xendev), true, "realized", &local_err);
941     if (local_err) {
942         error_propagate_prepend(errp, local_err,
943                                 "realization of device %s failed: ",
944                                 type);
945         goto fail;
946     }
947
948     xen_backend_set_device(backend, xendev);
949     return;
950
951 fail:
952     if (xendev) {
953         object_unparent(OBJECT(xendev));
954     }
955
956     if (iothread) {
957         xen_block_iothread_destroy(iothread, NULL);
958     }
959
960     if (drive) {
961         xen_block_drive_destroy(drive, NULL);
962     }
963 }
964
965 static void xen_block_device_destroy(XenBackendInstance *backend,
966                                      Error **errp)
967 {
968     XenDevice *xendev = xen_backend_get_device(backend);
969     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
970     XenBlockVdev *vdev = &blockdev->props.vdev;
971     XenBlockDrive *drive = blockdev->drive;
972     XenBlockIOThread *iothread = blockdev->iothread;
973
974     trace_xen_block_device_destroy(vdev->number);
975
976     object_unparent(OBJECT(xendev));
977
978     if (iothread) {
979         Error *local_err = NULL;
980
981         xen_block_iothread_destroy(iothread, &local_err);
982         if (local_err) {
983             error_propagate_prepend(errp, local_err,
984                                 "failed to destroy iothread: ");
985             return;
986         }
987     }
988
989     if (drive) {
990         Error *local_err = NULL;
991
992         xen_block_drive_destroy(drive, &local_err);
993         if (local_err) {
994             error_propagate_prepend(errp, local_err,
995                                 "failed to destroy drive: ");
996         }
997     }
998 }
999
1000 static const XenBackendInfo xen_block_backend_info = {
1001     .type = "qdisk",
1002     .create = xen_block_device_create,
1003     .destroy = xen_block_device_destroy,
1004 };
1005
1006 static void xen_block_register_backend(void)
1007 {
1008     xen_backend_register(&xen_block_backend_info);
1009 }
1010
1011 xen_backend_init(xen_block_register_backend);
This page took 0.07224 seconds and 2 git commands to generate.