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