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