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 5.9KB

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