1 /* 2 * QEMU Block driver for NBD 3 * 4 * Copyright (c) 2021 Virtuozzo International GmbH. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25 #include "qemu/osdep.h" 26 #include "trace.h" 27 28 #include "block/nbd.h" 29 30 #include "qapi/qapi-visit-sockets.h" 31 #include "qapi/clone-visitor.h" 32 #include "qemu/coroutine.h" 33 34 #include "nbd/nbd-internal.h" 35 36 struct NBDClientConnection { 37 /* Initialization constants, never change */ 38 SocketAddress *saddr; /* address to connect to */ 39 QCryptoTLSCreds *tlscreds; 40 char *tlshostname; 41 NBDExportInfo initial_info; 42 bool do_negotiation; 43 bool do_retry; 44 45 QemuMutex mutex; 46 47 NBDExportInfo updated_info; 48 /* 49 * @sioc represents a successful result. While thread is running, @sioc is 50 * used only by thread and not protected by mutex. When thread is not 51 * running, @sioc is stolen by nbd_co_establish_connection() under mutex. 52 */ 53 QIOChannelSocket *sioc; 54 QIOChannel *ioc; 55 /* 56 * @err represents previous attempt. It may be copied by 57 * nbd_co_establish_connection() when it reports failure. 58 */ 59 Error *err; 60 61 /* All further fields are accessed only under mutex */ 62 bool running; /* thread is running now */ 63 bool detached; /* thread is detached and should cleanup the state */ 64 65 /* 66 * wait_co: if non-NULL, which coroutine to wake in 67 * nbd_co_establish_connection() after yield() 68 */ 69 Coroutine *wait_co; 70 }; 71 72 /* 73 * The function isn't protected by any mutex, only call it when the client 74 * connection attempt has not yet started. 75 */ 76 void nbd_client_connection_enable_retry(NBDClientConnection *conn) 77 { 78 conn->do_retry = true; 79 } 80 81 NBDClientConnection *nbd_client_connection_new(const SocketAddress *saddr, 82 bool do_negotiation, 83 const char *export_name, 84 const char *x_dirty_bitmap, 85 QCryptoTLSCreds *tlscreds, 86 const char *tlshostname) 87 { 88 NBDClientConnection *conn = g_new(NBDClientConnection, 1); 89 90 object_ref(OBJECT(tlscreds)); 91 *conn = (NBDClientConnection) { 92 .saddr = QAPI_CLONE(SocketAddress, saddr), 93 .tlscreds = tlscreds, 94 .tlshostname = g_strdup(tlshostname), 95 .do_negotiation = do_negotiation, 96 97 .initial_info.request_sizes = true, 98 .initial_info.mode = NBD_MODE_EXTENDED, 99 .initial_info.base_allocation = true, 100 .initial_info.x_dirty_bitmap = g_strdup(x_dirty_bitmap), 101 .initial_info.name = g_strdup(export_name ?: "") 102 }; 103 104 qemu_mutex_init(&conn->mutex); 105 106 return conn; 107 } 108 109 static void nbd_client_connection_do_free(NBDClientConnection *conn) 110 { 111 if (conn->sioc) { 112 qio_channel_close(QIO_CHANNEL(conn->sioc), NULL); 113 object_unref(OBJECT(conn->sioc)); 114 } 115 error_free(conn->err); 116 qapi_free_SocketAddress(conn->saddr); 117 g_free(conn->tlshostname); 118 object_unref(OBJECT(conn->tlscreds)); 119 g_free(conn->initial_info.x_dirty_bitmap); 120 g_free(conn->initial_info.name); 121 g_free(conn); 122 } 123 124 /* 125 * Connect to @addr and do NBD negotiation if @info is not null. If @tlscreds 126 * are given @outioc is returned. @outioc is provided only on success. The call 127 * may be cancelled from other thread by simply qio_channel_shutdown(sioc). 128 */ 129 static int nbd_connect(QIOChannelSocket *sioc, SocketAddress *addr, 130 NBDExportInfo *info, QCryptoTLSCreds *tlscreds, 131 const char *tlshostname, 132 QIOChannel **outioc, Error **errp) 133 { 134 int ret; 135 136 if (outioc) { 137 *outioc = NULL; 138 } 139 140 ret = qio_channel_socket_connect_sync(sioc, addr, errp); 141 if (ret < 0) { 142 return ret; 143 } 144 145 nbd_set_socket_send_buffer(sioc); 146 qio_channel_set_delay(QIO_CHANNEL(sioc), false); 147 148 if (!info) { 149 return 0; 150 } 151 152 ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), tlscreds, tlshostname, 153 outioc, info, errp); 154 if (ret < 0) { 155 /* 156 * nbd_receive_negotiate() may setup tls ioc and return it even on 157 * failure path. In this case we should use it instead of original 158 * channel. 159 */ 160 if (outioc && *outioc) { 161 qio_channel_close(*outioc, NULL); 162 object_unref(OBJECT(*outioc)); 163 *outioc = NULL; 164 } else { 165 qio_channel_close(QIO_CHANNEL(sioc), NULL); 166 } 167 168 return ret; 169 } 170 171 return 0; 172 } 173 174 static void *connect_thread_func(void *opaque) 175 { 176 NBDClientConnection *conn = opaque; 177 int ret; 178 bool do_free; 179 uint64_t timeout = 1; 180 uint64_t max_timeout = 16; 181 182 qemu_mutex_lock(&conn->mutex); 183 while (!conn->detached) { 184 Error *local_err = NULL; 185 186 assert(!conn->sioc); 187 conn->sioc = qio_channel_socket_new(); 188 189 qemu_mutex_unlock(&conn->mutex); 190 191 conn->updated_info = conn->initial_info; 192 193 ret = nbd_connect(conn->sioc, conn->saddr, 194 conn->do_negotiation ? &conn->updated_info : NULL, 195 conn->tlscreds, conn->tlshostname, 196 &conn->ioc, &local_err); 197 198 /* 199 * conn->updated_info will finally be returned to the user. Clear the 200 * pointers to our internally allocated strings, which are IN parameters 201 * of nbd_receive_negotiate() and therefore nbd_connect(). Caller 202 * shouldn't be interested in these fields. 203 */ 204 conn->updated_info.x_dirty_bitmap = NULL; 205 conn->updated_info.name = NULL; 206 207 qemu_mutex_lock(&conn->mutex); 208 209 error_free(conn->err); 210 conn->err = NULL; 211 error_propagate(&conn->err, local_err); 212 213 if (ret < 0) { 214 object_unref(OBJECT(conn->sioc)); 215 conn->sioc = NULL; 216 if (conn->do_retry && !conn->detached) { 217 trace_nbd_connect_thread_sleep(timeout); 218 qemu_mutex_unlock(&conn->mutex); 219 220 sleep(timeout); 221 if (timeout < max_timeout) { 222 timeout *= 2; 223 } 224 225 qemu_mutex_lock(&conn->mutex); 226 continue; 227 } 228 } 229 230 break; 231 } 232 233 /* mutex is locked */ 234 235 assert(conn->running); 236 conn->running = false; 237 if (conn->wait_co) { 238 aio_co_wake(conn->wait_co); 239 conn->wait_co = NULL; 240 } 241 do_free = conn->detached; 242 243 qemu_mutex_unlock(&conn->mutex); 244 245 if (do_free) { 246 nbd_client_connection_do_free(conn); 247 } 248 249 return NULL; 250 } 251 252 void nbd_client_connection_release(NBDClientConnection *conn) 253 { 254 bool do_free = false; 255 256 if (!conn) { 257 return; 258 } 259 260 WITH_QEMU_LOCK_GUARD(&conn->mutex) { 261 assert(!conn->detached); 262 if (conn->running) { 263 conn->detached = true; 264 } else { 265 do_free = true; 266 } 267 if (conn->sioc) { 268 qio_channel_shutdown(QIO_CHANNEL(conn->sioc), 269 QIO_CHANNEL_SHUTDOWN_BOTH, NULL); 270 } 271 } 272 273 if (do_free) { 274 nbd_client_connection_do_free(conn); 275 } 276 } 277 278 /* 279 * Get a new connection in context of @conn: 280 * if the thread is running, wait for completion 281 * if the thread already succeeded in the background, and user didn't get the 282 * result, just return it now 283 * otherwise the thread is not running, so start a thread and wait for 284 * completion 285 * 286 * If @blocking is false, don't wait for the thread, return immediately. 287 * 288 * If @info is not NULL, also do nbd-negotiation after successful connection. 289 * In this case info is used only as out parameter, and is fully initialized by 290 * nbd_co_establish_connection(). "IN" fields of info as well as related only to 291 * nbd_receive_export_list() would be zero (see description of NBDExportInfo in 292 * include/block/nbd.h). 293 */ 294 QIOChannel *coroutine_fn 295 nbd_co_establish_connection(NBDClientConnection *conn, NBDExportInfo *info, 296 bool blocking, Error **errp) 297 { 298 QemuThread thread; 299 300 if (conn->do_negotiation) { 301 assert(info); 302 } 303 304 WITH_QEMU_LOCK_GUARD(&conn->mutex) { 305 /* 306 * Don't call nbd_co_establish_connection() in several coroutines in 307 * parallel. Only one call at once is supported. 308 */ 309 assert(!conn->wait_co); 310 311 if (!conn->running) { 312 if (conn->sioc) { 313 /* Previous attempt finally succeeded in background */ 314 if (conn->do_negotiation) { 315 memcpy(info, &conn->updated_info, sizeof(*info)); 316 if (conn->ioc) { 317 /* TLS channel now has own reference to parent */ 318 object_unref(OBJECT(conn->sioc)); 319 conn->sioc = NULL; 320 321 return g_steal_pointer(&conn->ioc); 322 } 323 } 324 325 assert(!conn->ioc); 326 327 return QIO_CHANNEL(g_steal_pointer(&conn->sioc)); 328 } 329 330 conn->running = true; 331 qemu_thread_create(&thread, "nbd-connect", 332 connect_thread_func, conn, QEMU_THREAD_DETACHED); 333 } 334 335 if (!blocking) { 336 if (conn->err) { 337 error_propagate(errp, error_copy(conn->err)); 338 } else { 339 error_setg(errp, "No connection at the moment"); 340 } 341 342 return NULL; 343 } 344 345 conn->wait_co = qemu_coroutine_self(); 346 } 347 348 /* 349 * We are going to wait for connect-thread finish, but 350 * nbd_co_establish_connection_cancel() can interrupt. 351 */ 352 qemu_coroutine_yield(); 353 354 WITH_QEMU_LOCK_GUARD(&conn->mutex) { 355 if (conn->running) { 356 /* 357 * The connection attempt was canceled and the coroutine resumed 358 * before the connection thread finished its job. Report the 359 * attempt as failed, but leave the connection thread running, 360 * to reuse it for the next connection attempt. 361 */ 362 if (conn->err) { 363 error_propagate(errp, error_copy(conn->err)); 364 } else { 365 /* 366 * The only possible case here is cancelling by open_timer 367 * during nbd_open(). So, the error message is for that case. 368 * If we have more use cases, we can refactor 369 * nbd_co_establish_connection_cancel() to take an additional 370 * parameter cancel_reason, that would be passed than to the 371 * caller of cancelled nbd_co_establish_connection(). 372 */ 373 error_setg(errp, "Connection attempt cancelled by timeout"); 374 } 375 376 return NULL; 377 } else { 378 /* Thread finished. There must be either error or sioc */ 379 assert(!conn->err != !conn->sioc); 380 381 if (conn->err) { 382 error_propagate(errp, error_copy(conn->err)); 383 return NULL; 384 } 385 386 if (conn->do_negotiation) { 387 memcpy(info, &conn->updated_info, sizeof(*info)); 388 if (conn->ioc) { 389 /* TLS channel now has own reference to parent */ 390 object_unref(OBJECT(conn->sioc)); 391 conn->sioc = NULL; 392 393 return g_steal_pointer(&conn->ioc); 394 } 395 } 396 397 assert(!conn->ioc); 398 399 return QIO_CHANNEL(g_steal_pointer(&conn->sioc)); 400 } 401 } 402 403 abort(); /* unreachable */ 404 } 405 406 /* 407 * nbd_co_establish_connection_cancel 408 * Cancel nbd_co_establish_connection() asynchronously. 409 * 410 * Note that this function neither directly stops the thread nor closes the 411 * socket, but rather safely wakes nbd_co_establish_connection() which is 412 * sleeping in yield() 413 */ 414 void nbd_co_establish_connection_cancel(NBDClientConnection *conn) 415 { 416 Coroutine *wait_co = NULL; 417 418 WITH_QEMU_LOCK_GUARD(&conn->mutex) { 419 wait_co = g_steal_pointer(&conn->wait_co); 420 } 421 422 if (wait_co) { 423 aio_co_wake(wait_co); 424 } 425 } 426