2
0

vhost-user.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*
  2. * QEMU vhost-user backend
  3. *
  4. * Copyright (C) 2018 Red Hat Inc
  5. *
  6. * Authors:
  7. * Marc-André Lureau <marcandre.lureau@redhat.com>
  8. *
  9. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10. * See the COPYING file in the top-level directory.
  11. */
  12. #include "qemu/osdep.h"
  13. #include "qapi/error.h"
  14. #include "qapi/qmp/qerror.h"
  15. #include "qemu/error-report.h"
  16. #include "qom/object_interfaces.h"
  17. #include "sysemu/vhost-user-backend.h"
  18. #include "sysemu/kvm.h"
  19. #include "io/channel-command.h"
  20. #include "hw/virtio/virtio-bus.h"
  21. static bool
  22. ioeventfd_enabled(void)
  23. {
  24. return kvm_enabled() && kvm_eventfds_enabled();
  25. }
  26. int
  27. vhost_user_backend_dev_init(VhostUserBackend *b, VirtIODevice *vdev,
  28. unsigned nvqs, Error **errp)
  29. {
  30. int ret;
  31. assert(!b->vdev && vdev);
  32. if (!ioeventfd_enabled()) {
  33. error_setg(errp, "vhost initialization failed: requires kvm");
  34. return -1;
  35. }
  36. if (!vhost_user_init(&b->vhost_user, &b->chr, errp)) {
  37. return -1;
  38. }
  39. b->vdev = vdev;
  40. b->dev.nvqs = nvqs;
  41. b->dev.vqs = g_new0(struct vhost_virtqueue, nvqs);
  42. ret = vhost_dev_init(&b->dev, &b->vhost_user, VHOST_BACKEND_TYPE_USER, 0);
  43. if (ret < 0) {
  44. error_setg_errno(errp, -ret, "vhost initialization failed");
  45. return -1;
  46. }
  47. return 0;
  48. }
  49. void
  50. vhost_user_backend_start(VhostUserBackend *b)
  51. {
  52. BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(b->vdev)));
  53. VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
  54. int ret, i ;
  55. if (b->started) {
  56. return;
  57. }
  58. if (!k->set_guest_notifiers) {
  59. error_report("binding does not support guest notifiers");
  60. return;
  61. }
  62. ret = vhost_dev_enable_notifiers(&b->dev, b->vdev);
  63. if (ret < 0) {
  64. return;
  65. }
  66. ret = k->set_guest_notifiers(qbus->parent, b->dev.nvqs, true);
  67. if (ret < 0) {
  68. error_report("Error binding guest notifier");
  69. goto err_host_notifiers;
  70. }
  71. b->dev.acked_features = b->vdev->guest_features;
  72. ret = vhost_dev_start(&b->dev, b->vdev);
  73. if (ret < 0) {
  74. error_report("Error start vhost dev");
  75. goto err_guest_notifiers;
  76. }
  77. /* guest_notifier_mask/pending not used yet, so just unmask
  78. * everything here. virtio-pci will do the right thing by
  79. * enabling/disabling irqfd.
  80. */
  81. for (i = 0; i < b->dev.nvqs; i++) {
  82. vhost_virtqueue_mask(&b->dev, b->vdev,
  83. b->dev.vq_index + i, false);
  84. }
  85. b->started = true;
  86. return;
  87. err_guest_notifiers:
  88. k->set_guest_notifiers(qbus->parent, b->dev.nvqs, false);
  89. err_host_notifiers:
  90. vhost_dev_disable_notifiers(&b->dev, b->vdev);
  91. }
  92. void
  93. vhost_user_backend_stop(VhostUserBackend *b)
  94. {
  95. BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(b->vdev)));
  96. VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
  97. int ret = 0;
  98. if (!b->started) {
  99. return;
  100. }
  101. vhost_dev_stop(&b->dev, b->vdev);
  102. if (k->set_guest_notifiers) {
  103. ret = k->set_guest_notifiers(qbus->parent,
  104. b->dev.nvqs, false);
  105. if (ret < 0) {
  106. error_report("vhost guest notifier cleanup failed: %d", ret);
  107. }
  108. }
  109. assert(ret >= 0);
  110. vhost_dev_disable_notifiers(&b->dev, b->vdev);
  111. b->started = false;
  112. }
  113. static void set_chardev(Object *obj, const char *value, Error **errp)
  114. {
  115. VhostUserBackend *b = VHOST_USER_BACKEND(obj);
  116. Chardev *chr;
  117. if (b->completed) {
  118. error_setg(errp, QERR_PERMISSION_DENIED);
  119. return;
  120. }
  121. g_free(b->chr_name);
  122. b->chr_name = g_strdup(value);
  123. chr = qemu_chr_find(b->chr_name);
  124. if (chr == NULL) {
  125. error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
  126. "Chardev '%s' not found", b->chr_name);
  127. return;
  128. }
  129. if (!qemu_chr_fe_init(&b->chr, chr, errp)) {
  130. return;
  131. }
  132. b->completed = true;
  133. /* could call vhost_dev_init() so early message can be exchanged */
  134. }
  135. static char *get_chardev(Object *obj, Error **errp)
  136. {
  137. VhostUserBackend *b = VHOST_USER_BACKEND(obj);
  138. Chardev *chr = qemu_chr_fe_get_driver(&b->chr);
  139. if (chr && chr->label) {
  140. return g_strdup(chr->label);
  141. }
  142. return NULL;
  143. }
  144. static void vhost_user_backend_init(Object *obj)
  145. {
  146. object_property_add_str(obj, "chardev", get_chardev, set_chardev);
  147. }
  148. static void vhost_user_backend_finalize(Object *obj)
  149. {
  150. VhostUserBackend *b = VHOST_USER_BACKEND(obj);
  151. g_free(b->dev.vqs);
  152. g_free(b->chr_name);
  153. vhost_user_cleanup(&b->vhost_user);
  154. qemu_chr_fe_deinit(&b->chr, true);
  155. }
  156. static const TypeInfo vhost_user_backend_info = {
  157. .name = TYPE_VHOST_USER_BACKEND,
  158. .parent = TYPE_OBJECT,
  159. .instance_size = sizeof(VhostUserBackend),
  160. .instance_init = vhost_user_backend_init,
  161. .instance_finalize = vhost_user_backend_finalize,
  162. .class_size = sizeof(VhostUserBackendClass),
  163. };
  164. static void register_types(void)
  165. {
  166. type_register_static(&vhost_user_backend_info);
  167. }
  168. type_init(register_types);