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 "qemu/osdep.h" 13 #include "sysemu/blockdev.h" 14 #include "sysemu/block-backend.h" 15 #include "hw/block/block.h" 16 #include "qapi/error.h" 17 #include "qapi/clone-visitor.h" 18 #include "qapi/qapi-visit-block-export.h" 19 #include "qapi/qapi-commands-block-export.h" 20 #include "block/nbd.h" 21 #include "io/channel-socket.h" 22 #include "io/net-listener.h" 23 24 typedef struct NBDConn { 25 QIOChannelSocket *cioc; 26 QLIST_ENTRY(NBDConn) next; 27 } NBDConn; 28 29 typedef struct NBDServerData { 30 QIONetListener *listener; 31 QCryptoTLSCreds *tlscreds; 32 char *tlsauthz; 33 uint32_t max_connections; 34 uint32_t connections; 35 QLIST_HEAD(, NBDConn) conns; 36 } NBDServerData; 37 38 static NBDServerData *nbd_server; 39 static int qemu_nbd_connections = -1; /* Non-negative if this is qemu-nbd */ 40 41 static void nbd_update_server_watch(NBDServerData *s); 42 43 void nbd_server_is_qemu_nbd(int max_connections) 44 { 45 qemu_nbd_connections = max_connections; 46 } 47 48 bool nbd_server_is_running(void) 49 { 50 return nbd_server || qemu_nbd_connections >= 0; 51 } 52 53 int nbd_server_max_connections(void) 54 { 55 return nbd_server ? nbd_server->max_connections : qemu_nbd_connections; 56 } 57 58 static void nbd_blockdev_client_closed(NBDClient *client, bool ignored) 59 { 60 NBDConn *conn = nbd_client_owner(client); 61 62 assert(qemu_in_main_thread() && nbd_server); 63 64 object_unref(OBJECT(conn->cioc)); 65 QLIST_REMOVE(conn, next); 66 g_free(conn); 67 68 nbd_client_put(client); 69 assert(nbd_server->connections > 0); 70 nbd_server->connections--; 71 nbd_update_server_watch(nbd_server); 72 } 73 74 static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc, 75 gpointer opaque) 76 { 77 NBDConn *conn = g_new0(NBDConn, 1); 78 79 assert(qemu_in_main_thread() && nbd_server); 80 nbd_server->connections++; 81 object_ref(OBJECT(cioc)); 82 conn->cioc = cioc; 83 QLIST_INSERT_HEAD(&nbd_server->conns, conn, next); 84 nbd_update_server_watch(nbd_server); 85 86 qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server"); 87 /* TODO - expose handshake timeout as QMP option */ 88 nbd_client_new(cioc, NBD_DEFAULT_HANDSHAKE_MAX_SECS, 89 nbd_server->tlscreds, nbd_server->tlsauthz, 90 nbd_blockdev_client_closed, conn); 91 } 92 93 static void nbd_update_server_watch(NBDServerData *s) 94 { 95 if (!s->max_connections || s->connections < s->max_connections) { 96 qio_net_listener_set_client_func(s->listener, nbd_accept, NULL, NULL); 97 } else { 98 qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL); 99 } 100 } 101 102 static void nbd_server_free(NBDServerData *server) 103 { 104 NBDConn *conn, *tmp; 105 106 if (!server) { 107 return; 108 } 109 110 /* 111 * Forcefully close the listener socket, and any clients that have 112 * not yet disconnected on their own. 113 */ 114 qio_net_listener_disconnect(server->listener); 115 object_unref(OBJECT(server->listener)); 116 QLIST_FOREACH_SAFE(conn, &server->conns, next, tmp) { 117 qio_channel_shutdown(QIO_CHANNEL(conn->cioc), QIO_CHANNEL_SHUTDOWN_BOTH, 118 NULL); 119 } 120 121 AIO_WAIT_WHILE_UNLOCKED(NULL, server->connections > 0); 122 123 if (server->tlscreds) { 124 object_unref(OBJECT(server->tlscreds)); 125 } 126 g_free(server->tlsauthz); 127 128 g_free(server); 129 } 130 131 static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp) 132 { 133 Object *obj; 134 QCryptoTLSCreds *creds; 135 136 obj = object_resolve_path_component( 137 object_get_objects_root(), id); 138 if (!obj) { 139 error_setg(errp, "No TLS credentials with id '%s'", 140 id); 141 return NULL; 142 } 143 creds = (QCryptoTLSCreds *) 144 object_dynamic_cast(obj, TYPE_QCRYPTO_TLS_CREDS); 145 if (!creds) { 146 error_setg(errp, "Object with id '%s' is not TLS credentials", 147 id); 148 return NULL; 149 } 150 151 if (!qcrypto_tls_creds_check_endpoint(creds, 152 QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, 153 errp)) { 154 return NULL; 155 } 156 object_ref(obj); 157 return creds; 158 } 159 160 161 void nbd_server_start(SocketAddress *addr, const char *tls_creds, 162 const char *tls_authz, uint32_t max_connections, 163 Error **errp) 164 { 165 if (nbd_server) { 166 error_setg(errp, "NBD server already running"); 167 return; 168 } 169 170 nbd_server = g_new0(NBDServerData, 1); 171 nbd_server->max_connections = max_connections; 172 nbd_server->listener = qio_net_listener_new(); 173 174 qio_net_listener_set_name(nbd_server->listener, 175 "nbd-listener"); 176 177 /* 178 * Because this server is persistent, a backlog of SOMAXCONN is 179 * better than trying to size it to max_connections. 180 */ 181 if (qio_net_listener_open_sync(nbd_server->listener, addr, SOMAXCONN, 182 errp) < 0) { 183 goto error; 184 } 185 186 if (tls_creds) { 187 nbd_server->tlscreds = nbd_get_tls_creds(tls_creds, errp); 188 if (!nbd_server->tlscreds) { 189 goto error; 190 } 191 } 192 193 nbd_server->tlsauthz = g_strdup(tls_authz); 194 195 nbd_update_server_watch(nbd_server); 196 197 return; 198 199 error: 200 nbd_server_free(nbd_server); 201 nbd_server = NULL; 202 } 203 204 void nbd_server_start_options(NbdServerOptions *arg, Error **errp) 205 { 206 if (!arg->has_max_connections) { 207 arg->max_connections = NBD_DEFAULT_MAX_CONNECTIONS; 208 } 209 210 nbd_server_start(arg->addr, arg->tls_creds, arg->tls_authz, 211 arg->max_connections, errp); 212 } 213 214 void qmp_nbd_server_start(SocketAddressLegacy *addr, 215 const char *tls_creds, 216 const char *tls_authz, 217 bool has_max_connections, uint32_t max_connections, 218 Error **errp) 219 { 220 SocketAddress *addr_flat = socket_address_flatten(addr); 221 222 if (!has_max_connections) { 223 max_connections = NBD_DEFAULT_MAX_CONNECTIONS; 224 } 225 226 nbd_server_start(addr_flat, tls_creds, tls_authz, max_connections, errp); 227 qapi_free_SocketAddress(addr_flat); 228 } 229 230 void qmp_nbd_server_add(NbdServerAddOptions *arg, Error **errp) 231 { 232 BlockExport *export; 233 BlockDriverState *bs; 234 BlockBackend *on_eject_blk; 235 BlockExportOptions *export_opts; 236 237 bs = bdrv_lookup_bs(arg->device, arg->device, errp); 238 if (!bs) { 239 return; 240 } 241 242 /* 243 * block-export-add would default to the node-name, but we may have to use 244 * the device name as a default here for compatibility. 245 */ 246 if (!arg->name) { 247 arg->name = g_strdup(arg->device); 248 } 249 250 export_opts = g_new(BlockExportOptions, 1); 251 *export_opts = (BlockExportOptions) { 252 .type = BLOCK_EXPORT_TYPE_NBD, 253 .id = g_strdup(arg->name), 254 .node_name = g_strdup(bdrv_get_node_name(bs)), 255 .has_writable = arg->has_writable, 256 .writable = arg->writable, 257 }; 258 QAPI_CLONE_MEMBERS(BlockExportOptionsNbdBase, &export_opts->u.nbd, 259 qapi_NbdServerAddOptions_base(arg)); 260 if (arg->bitmap) { 261 BlockDirtyBitmapOrStr *el = g_new(BlockDirtyBitmapOrStr, 1); 262 263 *el = (BlockDirtyBitmapOrStr) { 264 .type = QTYPE_QSTRING, 265 .u.local = g_strdup(arg->bitmap), 266 }; 267 export_opts->u.nbd.has_bitmaps = true; 268 QAPI_LIST_PREPEND(export_opts->u.nbd.bitmaps, el); 269 } 270 271 /* 272 * nbd-server-add doesn't complain when a read-only device should be 273 * exported as writable, but simply downgrades it. This is an error with 274 * block-export-add. 275 */ 276 if (bdrv_is_read_only(bs)) { 277 export_opts->has_writable = true; 278 export_opts->writable = false; 279 } 280 281 export = blk_exp_add(export_opts, errp); 282 if (!export) { 283 goto fail; 284 } 285 286 /* 287 * nbd-server-add removes the export when the named BlockBackend used for 288 * @device goes away. 289 */ 290 on_eject_blk = blk_by_name(arg->device); 291 if (on_eject_blk) { 292 nbd_export_set_on_eject_blk(export, on_eject_blk); 293 } 294 295 fail: 296 qapi_free_BlockExportOptions(export_opts); 297 } 298 299 void qmp_nbd_server_remove(const char *name, 300 bool has_mode, BlockExportRemoveMode mode, 301 Error **errp) 302 { 303 BlockExport *exp; 304 305 exp = blk_exp_find(name); 306 if (exp && exp->drv->type != BLOCK_EXPORT_TYPE_NBD) { 307 error_setg(errp, "Block export '%s' is not an NBD export", name); 308 return; 309 } 310 311 qmp_block_export_del(name, has_mode, mode, errp); 312 } 313 314 void qmp_nbd_server_stop(Error **errp) 315 { 316 if (!nbd_server) { 317 error_setg(errp, "NBD server not running"); 318 return; 319 } 320 321 blk_exp_close_all_type(BLOCK_EXPORT_TYPE_NBD); 322 323 nbd_server_free(nbd_server); 324 nbd_server = NULL; 325 } 326