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