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