You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

blockdev-nbd.c 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /*
  2. * Serving QEMU block devices via NBD
  3. *
  4. * Copyright (c) 2012 Red Hat, Inc.
  5. *
  6. * Author: Paolo Bonzini <pbonzini@redhat.com>
  7. *
  8. * This work is licensed under the terms of the GNU GPL, version 2 or
  9. * later. See the COPYING file in the top-level directory.
  10. */
  11. #include "qemu/osdep.h"
  12. #include "sysemu/blockdev.h"
  13. #include "sysemu/block-backend.h"
  14. #include "hw/block/block.h"
  15. #include "qapi/error.h"
  16. #include "qapi/qapi-commands-block.h"
  17. #include "sysemu/sysemu.h"
  18. #include "block/nbd.h"
  19. #include "io/channel-socket.h"
  20. #include "io/net-listener.h"
  21. typedef struct NBDServerData {
  22. QIONetListener *listener;
  23. QCryptoTLSCreds *tlscreds;
  24. char *tlsauthz;
  25. } NBDServerData;
  26. static NBDServerData *nbd_server;
  27. static void nbd_blockdev_client_closed(NBDClient *client, bool ignored)
  28. {
  29. nbd_client_put(client);
  30. }
  31. static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc,
  32. gpointer opaque)
  33. {
  34. qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server");
  35. nbd_client_new(cioc, nbd_server->tlscreds, nbd_server->tlsauthz,
  36. nbd_blockdev_client_closed);
  37. }
  38. static void nbd_server_free(NBDServerData *server)
  39. {
  40. if (!server) {
  41. return;
  42. }
  43. qio_net_listener_disconnect(server->listener);
  44. object_unref(OBJECT(server->listener));
  45. if (server->tlscreds) {
  46. object_unref(OBJECT(server->tlscreds));
  47. }
  48. g_free(server->tlsauthz);
  49. g_free(server);
  50. }
  51. static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp)
  52. {
  53. Object *obj;
  54. QCryptoTLSCreds *creds;
  55. obj = object_resolve_path_component(
  56. object_get_objects_root(), id);
  57. if (!obj) {
  58. error_setg(errp, "No TLS credentials with id '%s'",
  59. id);
  60. return NULL;
  61. }
  62. creds = (QCryptoTLSCreds *)
  63. object_dynamic_cast(obj, TYPE_QCRYPTO_TLS_CREDS);
  64. if (!creds) {
  65. error_setg(errp, "Object with id '%s' is not TLS credentials",
  66. id);
  67. return NULL;
  68. }
  69. if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
  70. error_setg(errp,
  71. "Expecting TLS credentials with a server endpoint");
  72. return NULL;
  73. }
  74. object_ref(obj);
  75. return creds;
  76. }
  77. void nbd_server_start(SocketAddress *addr, const char *tls_creds,
  78. const char *tls_authz, Error **errp)
  79. {
  80. if (nbd_server) {
  81. error_setg(errp, "NBD server already running");
  82. return;
  83. }
  84. nbd_server = g_new0(NBDServerData, 1);
  85. nbd_server->listener = qio_net_listener_new();
  86. qio_net_listener_set_name(nbd_server->listener,
  87. "nbd-listener");
  88. if (qio_net_listener_open_sync(nbd_server->listener, addr, errp) < 0) {
  89. goto error;
  90. }
  91. if (tls_creds) {
  92. nbd_server->tlscreds = nbd_get_tls_creds(tls_creds, errp);
  93. if (!nbd_server->tlscreds) {
  94. goto error;
  95. }
  96. /* TODO SOCKET_ADDRESS_TYPE_FD where fd has AF_INET or AF_INET6 */
  97. if (addr->type != SOCKET_ADDRESS_TYPE_INET) {
  98. error_setg(errp, "TLS is only supported with IPv4/IPv6");
  99. goto error;
  100. }
  101. }
  102. nbd_server->tlsauthz = g_strdup(tls_authz);
  103. qio_net_listener_set_client_func(nbd_server->listener,
  104. nbd_accept,
  105. NULL,
  106. NULL);
  107. return;
  108. error:
  109. nbd_server_free(nbd_server);
  110. nbd_server = NULL;
  111. }
  112. void qmp_nbd_server_start(SocketAddressLegacy *addr,
  113. bool has_tls_creds, const char *tls_creds,
  114. bool has_tls_authz, const char *tls_authz,
  115. Error **errp)
  116. {
  117. SocketAddress *addr_flat = socket_address_flatten(addr);
  118. nbd_server_start(addr_flat, tls_creds, tls_authz, errp);
  119. qapi_free_SocketAddress(addr_flat);
  120. }
  121. void qmp_nbd_server_add(const char *device, bool has_name, const char *name,
  122. bool has_writable, bool writable,
  123. bool has_bitmap, const char *bitmap, Error **errp)
  124. {
  125. BlockDriverState *bs = NULL;
  126. BlockBackend *on_eject_blk;
  127. NBDExport *exp;
  128. int64_t len;
  129. if (!nbd_server) {
  130. error_setg(errp, "NBD server not running");
  131. return;
  132. }
  133. if (!has_name) {
  134. name = device;
  135. }
  136. if (nbd_export_find(name)) {
  137. error_setg(errp, "NBD server already has export named '%s'", name);
  138. return;
  139. }
  140. on_eject_blk = blk_by_name(device);
  141. bs = bdrv_lookup_bs(device, device, errp);
  142. if (!bs) {
  143. return;
  144. }
  145. len = bdrv_getlength(bs);
  146. if (len < 0) {
  147. error_setg_errno(errp, -len,
  148. "Failed to determine the NBD export's length");
  149. return;
  150. }
  151. if (!has_writable) {
  152. writable = false;
  153. }
  154. if (bdrv_is_read_only(bs)) {
  155. writable = false;
  156. }
  157. exp = nbd_export_new(bs, 0, len, name, NULL, bitmap,
  158. writable ? 0 : NBD_FLAG_READ_ONLY,
  159. NULL, false, on_eject_blk, errp);
  160. if (!exp) {
  161. return;
  162. }
  163. /* The list of named exports has a strong reference to this export now and
  164. * our only way of accessing it is through nbd_export_find(), so we can drop
  165. * the strong reference that is @exp. */
  166. nbd_export_put(exp);
  167. }
  168. void qmp_nbd_server_remove(const char *name,
  169. bool has_mode, NbdServerRemoveMode mode,
  170. Error **errp)
  171. {
  172. NBDExport *exp;
  173. if (!nbd_server) {
  174. error_setg(errp, "NBD server not running");
  175. return;
  176. }
  177. exp = nbd_export_find(name);
  178. if (exp == NULL) {
  179. error_setg(errp, "Export '%s' is not found", name);
  180. return;
  181. }
  182. if (!has_mode) {
  183. mode = NBD_SERVER_REMOVE_MODE_SAFE;
  184. }
  185. nbd_export_remove(exp, mode, errp);
  186. }
  187. void qmp_nbd_server_stop(Error **errp)
  188. {
  189. if (!nbd_server) {
  190. error_setg(errp, "NBD server not running");
  191. return;
  192. }
  193. nbd_export_close_all();
  194. nbd_server_free(nbd_server);
  195. nbd_server = NULL;
  196. }