blockdev-nbd.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  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 "sysemu/blockdev.h"
  12. #include "hw/block/block.h"
  13. #include "monitor/monitor.h"
  14. #include "qapi/qmp/qerror.h"
  15. #include "sysemu/sysemu.h"
  16. #include "qmp-commands.h"
  17. #include "trace.h"
  18. #include "block/nbd.h"
  19. #include "qemu/sockets.h"
  20. static int server_fd = -1;
  21. static void nbd_accept(void *opaque)
  22. {
  23. struct sockaddr_in addr;
  24. socklen_t addr_len = sizeof(addr);
  25. int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len);
  26. if (fd >= 0 && !nbd_client_new(NULL, fd, nbd_client_put)) {
  27. shutdown(fd, 2);
  28. close(fd);
  29. }
  30. }
  31. void qmp_nbd_server_start(SocketAddress *addr, Error **errp)
  32. {
  33. if (server_fd != -1) {
  34. error_setg(errp, "NBD server already running");
  35. return;
  36. }
  37. server_fd = socket_listen(addr, errp);
  38. if (server_fd != -1) {
  39. qemu_set_fd_handler2(server_fd, NULL, nbd_accept, NULL, NULL);
  40. }
  41. }
  42. /* Hook into the BlockDriverState notifiers to close the export when
  43. * the file is closed.
  44. */
  45. typedef struct NBDCloseNotifier {
  46. Notifier n;
  47. NBDExport *exp;
  48. QTAILQ_ENTRY(NBDCloseNotifier) next;
  49. } NBDCloseNotifier;
  50. static QTAILQ_HEAD(, NBDCloseNotifier) close_notifiers =
  51. QTAILQ_HEAD_INITIALIZER(close_notifiers);
  52. static void nbd_close_notifier(Notifier *n, void *data)
  53. {
  54. NBDCloseNotifier *cn = DO_UPCAST(NBDCloseNotifier, n, n);
  55. notifier_remove(&cn->n);
  56. QTAILQ_REMOVE(&close_notifiers, cn, next);
  57. nbd_export_close(cn->exp);
  58. nbd_export_put(cn->exp);
  59. g_free(cn);
  60. }
  61. void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
  62. Error **errp)
  63. {
  64. BlockDriverState *bs;
  65. NBDExport *exp;
  66. NBDCloseNotifier *n;
  67. if (server_fd == -1) {
  68. error_setg(errp, "NBD server not running");
  69. return;
  70. }
  71. if (nbd_export_find(device)) {
  72. error_setg(errp, "NBD server already exporting device '%s'", device);
  73. return;
  74. }
  75. bs = bdrv_find(device);
  76. if (!bs) {
  77. error_set(errp, QERR_DEVICE_NOT_FOUND, device);
  78. return;
  79. }
  80. if (!bdrv_is_inserted(bs)) {
  81. error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
  82. return;
  83. }
  84. if (!has_writable) {
  85. writable = false;
  86. }
  87. if (bdrv_is_read_only(bs)) {
  88. writable = false;
  89. }
  90. exp = nbd_export_new(bs, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY, NULL);
  91. nbd_export_set_name(exp, device);
  92. n = g_malloc0(sizeof(NBDCloseNotifier));
  93. n->n.notify = nbd_close_notifier;
  94. n->exp = exp;
  95. bdrv_add_close_notifier(bs, &n->n);
  96. QTAILQ_INSERT_TAIL(&close_notifiers, n, next);
  97. }
  98. void qmp_nbd_server_stop(Error **errp)
  99. {
  100. while (!QTAILQ_EMPTY(&close_notifiers)) {
  101. NBDCloseNotifier *cn = QTAILQ_FIRST(&close_notifiers);
  102. nbd_close_notifier(&cn->n, nbd_export_get_blockdev(cn->exp));
  103. }
  104. if (server_fd != -1) {
  105. qemu_set_fd_handler2(server_fd, NULL, NULL, NULL, NULL);
  106. close(server_fd);
  107. server_fd = -1;
  108. }
  109. }