]> git.proxmox.com Git - mirror_qemu.git/blame - blockdev-nbd.c
nbd: convert qemu-nbd server to use I/O channels for connection setup
[mirror_qemu.git] / blockdev-nbd.c
CommitLineData
6dd844db
PB
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
d38ea87a 12#include "qemu/osdep.h"
9c17d615 13#include "sysemu/blockdev.h"
e140177d 14#include "sysemu/block-backend.h"
0d09e41a 15#include "hw/block/block.h"
7b1b5d19 16#include "qapi/qmp/qerror.h"
9c17d615 17#include "sysemu/sysemu.h"
6dd844db
PB
18#include "qmp-commands.h"
19#include "trace.h"
737e150e 20#include "block/nbd.h"
1de7afc9 21#include "qemu/sockets.h"
6dd844db
PB
22
23static int server_fd = -1;
24
25static void nbd_accept(void *opaque)
26{
27 struct sockaddr_in addr;
28 socklen_t addr_len = sizeof(addr);
29
30 int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len);
ee7d7aab
FZ
31 if (fd >= 0) {
32 nbd_client_new(NULL, fd, nbd_client_put);
6dd844db
PB
33 }
34}
35
36void qmp_nbd_server_start(SocketAddress *addr, Error **errp)
37{
38 if (server_fd != -1) {
39 error_setg(errp, "NBD server already running");
40 return;
41 }
42
43 server_fd = socket_listen(addr, errp);
44 if (server_fd != -1) {
82e1cc4b 45 qemu_set_fd_handler(server_fd, nbd_accept, NULL, NULL);
6dd844db
PB
46 }
47}
48
6dd844db
PB
49void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
50 Error **errp)
51{
e140177d 52 BlockBackend *blk;
6dd844db 53 NBDExport *exp;
6dd844db 54
17b6be4a
PB
55 if (server_fd == -1) {
56 error_setg(errp, "NBD server not running");
57 return;
58 }
59
6dd844db
PB
60 if (nbd_export_find(device)) {
61 error_setg(errp, "NBD server already exporting device '%s'", device);
62 return;
63 }
64
e140177d
HR
65 blk = blk_by_name(device);
66 if (!blk) {
75158ebb
MA
67 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
68 "Device '%s' not found", device);
6dd844db
PB
69 return;
70 }
e140177d 71 if (!blk_is_inserted(blk)) {
c6bd8c70 72 error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
60fe4fac
HB
73 return;
74 }
6dd844db 75
e6444734 76 if (!has_writable) {
f3313d23 77 writable = false;
e6444734 78 }
e140177d 79 if (blk_is_read_only(blk)) {
e6444734
PB
80 writable = false;
81 }
82
98f44bbe
HR
83 exp = nbd_export_new(blk, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY, NULL,
84 errp);
85 if (!exp) {
86 return;
87 }
6dd844db
PB
88
89 nbd_export_set_name(exp, device);
6dd844db 90
741cc431
HR
91 /* The list of named exports has a strong reference to this export now and
92 * our only way of accessing it is through nbd_export_find(), so we can drop
93 * the strong reference that is @exp. */
94 nbd_export_put(exp);
6dd844db
PB
95}
96
97void qmp_nbd_server_stop(Error **errp)
98{
741cc431 99 nbd_export_close_all();
6dd844db 100
fc6467ea 101 if (server_fd != -1) {
82e1cc4b 102 qemu_set_fd_handler(server_fd, NULL, NULL, NULL);
fc6467ea
PB
103 close(server_fd);
104 server_fd = -1;
105 }
6dd844db 106}