Lines Matching full:client

40  * recommends no larger than 32 mb, so that the client won't consider
83 NBDClient *client; member
126 void (*close_fn)(NBDClient *client, bool negotiated);
150 uint32_t check_align; /* If non-zero, check for aligned client requests */
160 static void nbd_client_receive_next_request(NBDClient *client);
164 Server Client
169 Server Client
178 Server Client
201 nbd_negotiate_send_rep_len(NBDClient *client, uint32_t type, in nbd_negotiate_send_rep_len() argument
206 trace_nbd_negotiate_send_rep_len(client->opt, nbd_opt_lookup(client->opt), in nbd_negotiate_send_rep_len()
211 set_be_option_rep(&rep, client->opt, type, len); in nbd_negotiate_send_rep_len()
212 return nbd_write(client->ioc, &rep, sizeof(rep), errp); in nbd_negotiate_send_rep_len()
218 nbd_negotiate_send_rep(NBDClient *client, uint32_t type, Error **errp) in nbd_negotiate_send_rep() argument
220 return nbd_negotiate_send_rep_len(client, type, 0, errp); in nbd_negotiate_send_rep()
226 nbd_negotiate_send_rep_verr(NBDClient *client, uint32_t type, in nbd_negotiate_send_rep_verr() argument
238 ret = nbd_negotiate_send_rep_len(client, type, len, errp); in nbd_negotiate_send_rep_verr()
242 if (nbd_write(client->ioc, msg, len, errp) < 0) { in nbd_negotiate_send_rep_verr()
266 nbd_negotiate_send_rep_err(NBDClient *client, uint32_t type, in nbd_negotiate_send_rep_err() argument
273 ret = nbd_negotiate_send_rep_verr(client, type, errp, fmt, va); in nbd_negotiate_send_rep_err()
282 nbd_opt_vdrop(NBDClient *client, uint32_t type, Error **errp, in nbd_opt_vdrop() argument
285 int ret = nbd_drop(client->ioc, client->optlen, errp); in nbd_opt_vdrop()
287 client->optlen = 0; in nbd_opt_vdrop()
289 ret = nbd_negotiate_send_rep_verr(client, type, errp, fmt, va); in nbd_opt_vdrop()
295 nbd_opt_drop(NBDClient *client, uint32_t type, Error **errp, in nbd_opt_drop() argument
302 ret = nbd_opt_vdrop(client, type, errp, fmt, va); in nbd_opt_drop()
309 nbd_opt_invalid(NBDClient *client, Error **errp, const char *fmt, ...) in nbd_opt_invalid() argument
315 ret = nbd_opt_vdrop(client, NBD_REP_ERR_INVALID, errp, fmt, va); in nbd_opt_invalid()
326 nbd_opt_read(NBDClient *client, void *buffer, size_t size, in nbd_opt_read() argument
329 if (size > client->optlen) { in nbd_opt_read()
330 return nbd_opt_invalid(client, errp, in nbd_opt_read()
332 nbd_opt_lookup(client->opt)); in nbd_opt_read()
334 client->optlen -= size; in nbd_opt_read()
335 if (qio_channel_read_all(client->ioc, buffer, size, errp) < 0) { in nbd_opt_read()
340 return nbd_opt_invalid(client, errp, in nbd_opt_read()
342 nbd_opt_lookup(client->opt)); in nbd_opt_read()
351 nbd_opt_skip(NBDClient *client, size_t size, Error **errp) in nbd_opt_skip() argument
353 if (size > client->optlen) { in nbd_opt_skip()
354 return nbd_opt_invalid(client, errp, in nbd_opt_skip()
356 nbd_opt_lookup(client->opt)); in nbd_opt_skip()
358 client->optlen -= size; in nbd_opt_skip()
359 return nbd_drop(client->ioc, size, errp) < 0 ? -EIO : 1; in nbd_opt_skip()
375 nbd_opt_read_name(NBDClient *client, char **name, uint32_t *length, in nbd_opt_read_name() argument
383 ret = nbd_opt_read(client, &len, sizeof(len), false, errp); in nbd_opt_read_name()
390 return nbd_opt_invalid(client, errp, in nbd_opt_read_name()
395 ret = nbd_opt_read(client, local_name, len, true, errp); in nbd_opt_read_name()
412 nbd_negotiate_send_rep_list(NBDClient *client, NBDExport *exp, Error **errp) in nbd_negotiate_send_rep_list() argument
419 QIOChannel *ioc = client->ioc; in nbd_negotiate_send_rep_list()
427 ret = nbd_negotiate_send_rep_len(client, NBD_REP_SERVER, len, errp); in nbd_negotiate_send_rep_list()
454 nbd_negotiate_handle_list(NBDClient *client, Error **errp) in nbd_negotiate_handle_list() argument
457 assert(client->opt == NBD_OPT_LIST); in nbd_negotiate_handle_list()
461 if (nbd_negotiate_send_rep_list(client, exp, errp)) { in nbd_negotiate_handle_list()
466 return nbd_negotiate_send_rep(client, NBD_REP_ACK, errp); in nbd_negotiate_handle_list()
470 nbd_check_meta_export(NBDClient *client, NBDExport *exp) in nbd_check_meta_export() argument
472 if (exp != client->contexts.exp) { in nbd_check_meta_export()
473 client->contexts.count = 0; in nbd_check_meta_export()
480 nbd_negotiate_handle_export_name(NBDClient *client, bool no_zeroes, in nbd_negotiate_handle_export_name() argument
490 /* Client sends: in nbd_negotiate_handle_export_name()
498 if (client->mode >= NBD_MODE_EXTENDED) { in nbd_negotiate_handle_export_name()
502 if (client->optlen > NBD_MAX_STRING_SIZE) { in nbd_negotiate_handle_export_name()
506 name = g_malloc(client->optlen + 1); in nbd_negotiate_handle_export_name()
507 if (nbd_read(client->ioc, name, client->optlen, "export name", errp) < 0) { in nbd_negotiate_handle_export_name()
510 name[client->optlen] = '\0'; in nbd_negotiate_handle_export_name()
511 client->optlen = 0; in nbd_negotiate_handle_export_name()
515 client->exp = nbd_export_find(name); in nbd_negotiate_handle_export_name()
516 if (!client->exp) { in nbd_negotiate_handle_export_name()
520 nbd_check_meta_export(client, client->exp); in nbd_negotiate_handle_export_name()
522 myflags = client->exp->nbdflags; in nbd_negotiate_handle_export_name()
523 if (client->mode >= NBD_MODE_STRUCTURED) { in nbd_negotiate_handle_export_name()
526 if (client->mode >= NBD_MODE_EXTENDED && client->contexts.count) { in nbd_negotiate_handle_export_name()
529 trace_nbd_negotiate_new_style_size_flags(client->exp->size, myflags); in nbd_negotiate_handle_export_name()
530 stq_be_p(buf, client->exp->size); in nbd_negotiate_handle_export_name()
533 ret = nbd_write(client->ioc, buf, len, errp); in nbd_negotiate_handle_export_name()
539 QTAILQ_INSERT_TAIL(&client->exp->clients, client, next); in nbd_negotiate_handle_export_name()
540 blk_exp_ref(&client->exp->common); in nbd_negotiate_handle_export_name()
549 nbd_negotiate_send_info(NBDClient *client, uint16_t info, uint32_t length, in nbd_negotiate_send_info() argument
555 rc = nbd_negotiate_send_rep_len(client, NBD_REP_INFO, in nbd_negotiate_send_info()
561 if (nbd_write(client->ioc, &info, sizeof(info), errp) < 0) { in nbd_negotiate_send_info()
564 if (nbd_write(client->ioc, buf, length, errp) < 0) { in nbd_negotiate_send_info()
571 * @fatal requests that we quit talking to the client, even if we are able
575 * 0 error message successfully sent to client, errp is not set
578 nbd_reject_length(NBDClient *client, bool fatal, Error **errp) in nbd_reject_length() argument
582 assert(client->optlen); in nbd_reject_length()
583 ret = nbd_opt_invalid(client, errp, "option '%s' has unexpected length", in nbd_reject_length()
584 nbd_opt_lookup(client->opt)); in nbd_reject_length()
587 nbd_opt_lookup(client->opt)); in nbd_reject_length()
597 nbd_negotiate_handle_info(NBDClient *client, Error **errp) in nbd_negotiate_handle_info() argument
612 /* Client sends: in nbd_negotiate_handle_info()
618 rc = nbd_opt_read_name(client, &name, &namelen, errp); in nbd_negotiate_handle_info()
624 rc = nbd_opt_read(client, &requests, sizeof(requests), false, errp); in nbd_negotiate_handle_info()
631 rc = nbd_opt_read(client, &request, sizeof(request), false, errp); in nbd_negotiate_handle_info()
650 if (client->optlen) { in nbd_negotiate_handle_info()
651 return nbd_reject_length(client, false, errp); in nbd_negotiate_handle_info()
658 return nbd_negotiate_send_rep_err(client, NBD_REP_ERR_UNKNOWN, in nbd_negotiate_handle_info()
662 if (client->opt == NBD_OPT_GO) { in nbd_negotiate_handle_info()
663 nbd_check_meta_export(client, exp); in nbd_negotiate_handle_info()
666 /* Don't bother sending NBD_INFO_NAME unless client requested it */ in nbd_negotiate_handle_info()
668 rc = nbd_negotiate_send_info(client, NBD_INFO_NAME, namelen, name, in nbd_negotiate_handle_info()
676 * client request */ in nbd_negotiate_handle_info()
681 rc = nbd_negotiate_send_info(client, NBD_INFO_DESCRIPTION, in nbd_negotiate_handle_info()
689 * according to whether the client requested it, and according to in nbd_negotiate_handle_info()
691 /* minimum - 1 for back-compat, or actual if client will obey it. */ in nbd_negotiate_handle_info()
692 if (client->opt == NBD_OPT_INFO || blocksize) { in nbd_negotiate_handle_info()
707 rc = nbd_negotiate_send_info(client, NBD_INFO_BLOCK_SIZE, in nbd_negotiate_handle_info()
715 if (client->mode >= NBD_MODE_STRUCTURED) { in nbd_negotiate_handle_info()
718 if (client->mode >= NBD_MODE_EXTENDED && in nbd_negotiate_handle_info()
719 (client->contexts.count || client->opt == NBD_OPT_INFO)) { in nbd_negotiate_handle_info()
725 rc = nbd_negotiate_send_info(client, NBD_INFO_EXPORT, in nbd_negotiate_handle_info()
732 * If the client is just asking for NBD_OPT_INFO, but forgot to in nbd_negotiate_handle_info()
737 if (client->opt == NBD_OPT_INFO && !blocksize && in nbd_negotiate_handle_info()
739 return nbd_negotiate_send_rep_err(client, in nbd_negotiate_handle_info()
747 rc = nbd_negotiate_send_rep(client, NBD_REP_ACK, errp); in nbd_negotiate_handle_info()
752 if (client->opt == NBD_OPT_GO) { in nbd_negotiate_handle_info()
753 client->exp = exp; in nbd_negotiate_handle_info()
754 client->check_align = check_align; in nbd_negotiate_handle_info()
755 QTAILQ_INSERT_TAIL(&client->exp->clients, client, next); in nbd_negotiate_handle_info()
756 blk_exp_ref(&client->exp->common); in nbd_negotiate_handle_info()
784 nbd_negotiate_handle_starttls(NBDClient *client, Error **errp) in nbd_negotiate_handle_starttls() argument
790 assert(client->opt == NBD_OPT_STARTTLS); in nbd_negotiate_handle_starttls()
793 ioc = client->ioc; in nbd_negotiate_handle_starttls()
795 if (nbd_negotiate_send_rep(client, NBD_REP_ACK, errp) < 0) { in nbd_negotiate_handle_starttls()
800 client->tlscreds, in nbd_negotiate_handle_starttls()
801 client->tlsauthz, in nbd_negotiate_handle_starttls()
837 nbd_negotiate_send_meta_context(NBDClient *client, const char *context, in nbd_negotiate_send_meta_context() argument
847 if (client->opt == NBD_OPT_LIST_META_CONTEXT) { in nbd_negotiate_send_meta_context()
852 set_be_option_rep(&opt.h, client->opt, NBD_REP_META_CONTEXT, in nbd_negotiate_send_meta_context()
856 return qio_channel_writev_all(client->ioc, iov, 2, errp) < 0 ? -EIO : 0; in nbd_negotiate_send_meta_context()
861 * the @client is performing _LIST_.
864 nbd_meta_empty_or_pattern(NBDClient *client, const char *pattern, in nbd_meta_empty_or_pattern() argument
869 return client->opt == NBD_OPT_LIST_META_CONTEXT; in nbd_meta_empty_or_pattern()
900 nbd_meta_base_query(NBDClient *client, NBDMetaContexts *meta, in nbd_meta_base_query() argument
908 if (nbd_meta_empty_or_pattern(client, "allocation", query)) { in nbd_meta_base_query()
921 nbd_meta_qemu_query(NBDClient *client, NBDMetaContexts *meta, in nbd_meta_qemu_query() argument
932 if (client->opt == NBD_OPT_LIST_META_CONTEXT) { in nbd_meta_qemu_query()
951 if (client->opt == NBD_OPT_LIST_META_CONTEXT && in nbd_meta_qemu_query()
987 nbd_negotiate_meta_query(NBDClient *client, in nbd_negotiate_meta_query() argument
994 ret = nbd_opt_read(client, &len, sizeof(len), false, errp); in nbd_negotiate_meta_query()
1002 return nbd_opt_skip(client, len, errp); in nbd_negotiate_meta_query()
1006 ret = nbd_opt_read(client, query, len, true, errp); in nbd_negotiate_meta_query()
1012 if (nbd_meta_base_query(client, meta, query)) { in nbd_negotiate_meta_query()
1015 if (nbd_meta_qemu_query(client, meta, query)) { in nbd_negotiate_meta_query()
1028 nbd_negotiate_meta_queries(NBDClient *client, Error **errp) in nbd_negotiate_meta_queries() argument
1040 if (client->opt == NBD_OPT_SET_META_CONTEXT && in nbd_negotiate_meta_queries()
1041 client->mode < NBD_MODE_STRUCTURED) { in nbd_negotiate_meta_queries()
1042 return nbd_opt_invalid(client, errp, in nbd_negotiate_meta_queries()
1045 nbd_opt_lookup(client->opt)); in nbd_negotiate_meta_queries()
1048 if (client->opt == NBD_OPT_LIST_META_CONTEXT) { in nbd_negotiate_meta_queries()
1052 meta = &client->contexts; in nbd_negotiate_meta_queries()
1058 ret = nbd_opt_read_name(client, &export_name, NULL, errp); in nbd_negotiate_meta_queries()
1067 return nbd_opt_drop(client, NBD_REP_ERR_UNKNOWN, errp, in nbd_negotiate_meta_queries()
1071 if (client->opt == NBD_OPT_LIST_META_CONTEXT) { in nbd_negotiate_meta_queries()
1075 ret = nbd_opt_read(client, &nb_queries, sizeof(nb_queries), false, errp); in nbd_negotiate_meta_queries()
1080 trace_nbd_negotiate_meta_context(nbd_opt_lookup(client->opt), in nbd_negotiate_meta_queries()
1083 if (client->opt == NBD_OPT_LIST_META_CONTEXT && !nb_queries) { in nbd_negotiate_meta_queries()
1092 ret = nbd_negotiate_meta_query(client, meta, errp); in nbd_negotiate_meta_queries()
1100 ret = nbd_negotiate_send_meta_context(client, "base:allocation", in nbd_negotiate_meta_queries()
1110 ret = nbd_negotiate_send_meta_context(client, "qemu:allocation-depth", in nbd_negotiate_meta_queries()
1130 ret = nbd_negotiate_send_meta_context(client, context, in nbd_negotiate_meta_queries()
1139 ret = nbd_negotiate_send_rep(client, NBD_REP_ACK, errp); in nbd_negotiate_meta_queries()
1148 * Process all NBD_OPT_* client option commands, during fixed newstyle
1153 * 1 if client sent NBD_OPT_ABORT (i.e. on valid disconnect) or never
1157 nbd_negotiate_options(NBDClient *client, Error **errp) in nbd_negotiate_options() argument
1163 /* Client sends: in nbd_negotiate_options()
1164 [ 0 .. 3] client flags in nbd_negotiate_options()
1183 if (nbd_read32(client->ioc, &flags, "flags", NULL) < 0) { in nbd_negotiate_options()
1186 client->mode = NBD_MODE_EXPORT_NAME; in nbd_negotiate_options()
1191 client->mode = NBD_MODE_SIMPLE; in nbd_negotiate_options()
1198 error_setg(errp, "Unknown client flags 0x%" PRIx32 " received", flags); in nbd_negotiate_options()
1207 if (nbd_read64(client->ioc, &magic, "opts magic", errp) < 0) { in nbd_negotiate_options()
1216 if (nbd_read32(client->ioc, &option, "option", errp) < 0) { in nbd_negotiate_options()
1219 client->opt = option; in nbd_negotiate_options()
1221 if (nbd_read32(client->ioc, &length, "option length", errp) < 0) { in nbd_negotiate_options()
1224 assert(!client->optlen); in nbd_negotiate_options()
1225 client->optlen = length; in nbd_negotiate_options()
1235 if (client->tlscreds && in nbd_negotiate_options()
1236 client->ioc == (QIOChannel *)client->sioc) { in nbd_negotiate_options()
1245 /* Unconditionally drop the connection if the client in nbd_negotiate_options()
1247 return nbd_reject_length(client, true, errp); in nbd_negotiate_options()
1249 tioc = nbd_negotiate_handle_starttls(client, errp); in nbd_negotiate_options()
1254 object_unref(OBJECT(client->ioc)); in nbd_negotiate_options()
1255 client->ioc = tioc; in nbd_negotiate_options()
1259 /* No way to return an error to client, so drop connection */ in nbd_negotiate_options()
1265 /* Let the client keep trying, unless they asked to in nbd_negotiate_options()
1267 * client; but when replying to OPT_ABORT, be aware in nbd_negotiate_options()
1268 * that the client may hang up before receiving the in nbd_negotiate_options()
1271 ret = nbd_opt_drop(client, NBD_REP_ERR_TLS_REQD, in nbd_negotiate_options()
1284 ret = nbd_reject_length(client, false, errp); in nbd_negotiate_options()
1286 ret = nbd_negotiate_handle_list(client, errp); in nbd_negotiate_options()
1294 nbd_negotiate_send_rep(client, NBD_REP_ACK, NULL); in nbd_negotiate_options()
1298 return nbd_negotiate_handle_export_name(client, no_zeroes, in nbd_negotiate_options()
1303 ret = nbd_negotiate_handle_info(client, errp); in nbd_negotiate_options()
1312 ret = nbd_reject_length(client, false, errp); in nbd_negotiate_options()
1313 } else if (client->tlscreds) { in nbd_negotiate_options()
1314 ret = nbd_negotiate_send_rep_err(client, in nbd_negotiate_options()
1318 ret = nbd_negotiate_send_rep_err(client, in nbd_negotiate_options()
1326 ret = nbd_reject_length(client, false, errp); in nbd_negotiate_options()
1327 } else if (client->mode >= NBD_MODE_EXTENDED) { in nbd_negotiate_options()
1329 client, NBD_REP_ERR_EXT_HEADER_REQD, errp, in nbd_negotiate_options()
1331 } else if (client->mode >= NBD_MODE_STRUCTURED) { in nbd_negotiate_options()
1333 client, NBD_REP_ERR_INVALID, errp, in nbd_negotiate_options()
1336 ret = nbd_negotiate_send_rep(client, NBD_REP_ACK, errp); in nbd_negotiate_options()
1337 client->mode = NBD_MODE_STRUCTURED; in nbd_negotiate_options()
1343 ret = nbd_negotiate_meta_queries(client, errp); in nbd_negotiate_options()
1348 ret = nbd_reject_length(client, false, errp); in nbd_negotiate_options()
1349 } else if (client->mode >= NBD_MODE_EXTENDED) { in nbd_negotiate_options()
1351 client, NBD_REP_ERR_INVALID, errp, in nbd_negotiate_options()
1354 ret = nbd_negotiate_send_rep(client, NBD_REP_ACK, errp); in nbd_negotiate_options()
1355 client->mode = NBD_MODE_EXTENDED; in nbd_negotiate_options()
1360 ret = nbd_opt_drop(client, NBD_REP_ERR_UNSUP, errp, in nbd_negotiate_options()
1372 return nbd_negotiate_handle_export_name(client, no_zeroes, in nbd_negotiate_options()
1391 * 1 if client sent NBD_OPT_ABORT (i.e. on valid disconnect) or never
1394 static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp) in nbd_negotiate() argument
1407 New style negotiation header, client can send options in nbd_negotiate()
1414 qio_channel_set_blocking(client->ioc, false, NULL); in nbd_negotiate()
1415 qio_channel_set_follow_coroutine_ctx(client->ioc, true); in nbd_negotiate()
1425 * wrong with a client testing if our port is alive. in nbd_negotiate()
1427 if (nbd_write(client->ioc, buf, 18, NULL) < 0) { in nbd_negotiate()
1430 ret = nbd_negotiate_options(client, errp); in nbd_negotiate()
1438 assert(!client->optlen); in nbd_negotiate()
1453 nbd_read_eof(NBDClient *client, void *buffer, size_t size, Error **errp) in nbd_read_eof() argument
1462 len = qio_channel_readv(client->ioc, &iov, 1, errp); in nbd_read_eof()
1464 WITH_QEMU_LOCK_GUARD(&client->lock) { in nbd_read_eof()
1465 client->read_yielding = true; in nbd_read_eof()
1470 qio_channel_yield(client->ioc, G_IO_IN); in nbd_read_eof()
1471 WITH_QEMU_LOCK_GUARD(&client->lock) { in nbd_read_eof()
1472 client->read_yielding = false; in nbd_read_eof()
1473 if (client->quiescing) { in nbd_read_eof()
1497 static int coroutine_fn nbd_receive_request(NBDClient *client, NBDRequest *request, in nbd_receive_request() argument
1503 size_t size = client->mode >= NBD_MODE_EXTENDED ? in nbd_receive_request()
1506 ret = nbd_read_eof(client, buf, size, errp); in nbd_receive_request()
1536 if (client->mode >= NBD_MODE_EXTENDED) { in nbd_receive_request()
1558 void nbd_client_get(NBDClient *client) in nbd_client_get() argument
1560 qatomic_inc(&client->refcount); in nbd_client_get()
1563 void nbd_client_put(NBDClient *client) in nbd_client_put() argument
1567 if (qatomic_fetch_dec(&client->refcount) == 1) { in nbd_client_put()
1568 /* The last reference should be dropped by client->close, in nbd_client_put()
1571 assert(client->closing); in nbd_client_put()
1573 object_unref(OBJECT(client->sioc)); in nbd_client_put()
1574 object_unref(OBJECT(client->ioc)); in nbd_client_put()
1575 if (client->tlscreds) { in nbd_client_put()
1576 object_unref(OBJECT(client->tlscreds)); in nbd_client_put()
1578 g_free(client->tlsauthz); in nbd_client_put()
1579 if (client->exp) { in nbd_client_put()
1580 QTAILQ_REMOVE(&client->exp->clients, client, next); in nbd_client_put()
1581 blk_exp_unref(&client->exp->common); in nbd_client_put()
1583 g_free(client->contexts.bitmaps); in nbd_client_put()
1584 qemu_mutex_destroy(&client->lock); in nbd_client_put()
1585 g_free(client); in nbd_client_put()
1590 * Tries to release the reference to @client, but only if other references
1597 static bool nbd_client_put_nonzero(NBDClient *client) in nbd_client_put_nonzero() argument
1599 int old = qatomic_read(&client->refcount); in nbd_client_put_nonzero()
1608 old = qatomic_cmpxchg(&client->refcount, expected, expected - 1); in nbd_client_put_nonzero()
1614 static void client_close(NBDClient *client, bool negotiated) in client_close() argument
1618 WITH_QEMU_LOCK_GUARD(&client->lock) { in client_close()
1619 if (client->closing) { in client_close()
1623 client->closing = true; in client_close()
1629 qio_channel_shutdown(client->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, in client_close()
1632 /* Also tell the client, so that they release their reference. */ in client_close()
1633 if (client->close_fn) { in client_close()
1634 client->close_fn(client, negotiated); in client_close()
1638 /* Runs in export AioContext with client->lock held */
1639 static NBDRequestData *nbd_request_get(NBDClient *client) in nbd_request_get() argument
1643 assert(client->nb_requests <= MAX_NBD_REQUESTS - 1); in nbd_request_get()
1644 client->nb_requests++; in nbd_request_get()
1647 req->client = client; in nbd_request_get()
1651 /* Runs in export AioContext with client->lock held */
1654 NBDClient *client = req->client; in nbd_request_put() local
1661 client->nb_requests--; in nbd_request_put()
1663 if (client->quiescing && client->nb_requests == 0) { in nbd_request_put()
1667 nbd_client_receive_next_request(client); in nbd_request_put()
1673 NBDClient *client; in blk_aio_attached() local
1681 QTAILQ_FOREACH(client, &exp->clients, next) { in blk_aio_attached()
1682 WITH_QEMU_LOCK_GUARD(&client->lock) { in blk_aio_attached()
1683 assert(client->nb_requests == 0); in blk_aio_attached()
1684 assert(client->recv_coroutine == NULL); in blk_aio_attached()
1685 assert(client->send_coroutine == NULL); in blk_aio_attached()
1704 NBDClient *client; in nbd_drained_begin() local
1708 QTAILQ_FOREACH(client, &exp->clients, next) { in nbd_drained_begin()
1709 WITH_QEMU_LOCK_GUARD(&client->lock) { in nbd_drained_begin()
1710 client->quiescing = true; in nbd_drained_begin()
1718 NBDClient *client; in nbd_drained_end() local
1722 QTAILQ_FOREACH(client, &exp->clients, next) { in nbd_drained_end()
1723 WITH_QEMU_LOCK_GUARD(&client->lock) { in nbd_drained_end()
1724 client->quiescing = false; in nbd_drained_end()
1725 nbd_client_receive_next_request(client); in nbd_drained_end()
1733 NBDClient *client = opaque; in nbd_wake_read_bh() local
1734 qio_channel_wake_read(client->ioc); in nbd_wake_read_bh()
1740 NBDClient *client; in nbd_drained_poll() local
1744 QTAILQ_FOREACH(client, &exp->clients, next) { in nbd_drained_poll()
1745 WITH_QEMU_LOCK_GUARD(&client->lock) { in nbd_drained_poll()
1746 if (client->nb_requests != 0) { in nbd_drained_poll()
1749 * enter it here so we don't depend on the client to wake it up. in nbd_drained_poll()
1755 if (client->recv_coroutine != NULL && client->read_yielding) { in nbd_drained_poll()
1756 aio_bh_schedule_oneshot(nbd_export_aio_context(client->exp), in nbd_drained_poll()
1757 nbd_wake_read_bh, client); in nbd_drained_poll()
1981 NBDClient *client, *next; in nbd_export_request_shutdown() local
1991 QTAILQ_FOREACH_SAFE(client, &exp->clients, next, next) { in nbd_export_request_shutdown()
1992 client_close(client, true); in nbd_export_request_shutdown()
2035 static int coroutine_fn nbd_co_send_iov(NBDClient *client, struct iovec *iov, in nbd_co_send_iov() argument
2041 qemu_co_mutex_lock(&client->send_lock); in nbd_co_send_iov()
2042 client->send_coroutine = qemu_coroutine_self(); in nbd_co_send_iov()
2044 ret = qio_channel_writev_all(client->ioc, iov, niov, errp) < 0 ? -EIO : 0; in nbd_co_send_iov()
2046 client->send_coroutine = NULL; in nbd_co_send_iov()
2047 qemu_co_mutex_unlock(&client->send_lock); in nbd_co_send_iov()
2060 static int coroutine_fn nbd_co_send_simple_reply(NBDClient *client, in nbd_co_send_simple_reply() argument
2076 assert(client->mode < NBD_MODE_STRUCTURED || in nbd_co_send_simple_reply()
2077 (client->mode == NBD_MODE_STRUCTURED && in nbd_co_send_simple_reply()
2083 return nbd_co_send_iov(client, iov, 2, errp); in nbd_co_send_simple_reply()
2094 static inline void set_be_chunk(NBDClient *client, struct iovec *iov, in set_be_chunk() argument
2105 if (client->mode >= NBD_MODE_EXTENDED) { in set_be_chunk()
2127 static int coroutine_fn nbd_co_send_chunk_done(NBDClient *client, in nbd_co_send_chunk_done() argument
2137 set_be_chunk(client, iov, 1, NBD_REPLY_FLAG_DONE, in nbd_co_send_chunk_done()
2139 return nbd_co_send_iov(client, iov, 1, errp); in nbd_co_send_chunk_done()
2142 static int coroutine_fn nbd_co_send_chunk_read(NBDClient *client, in nbd_co_send_chunk_read() argument
2160 set_be_chunk(client, iov, 3, final ? NBD_REPLY_FLAG_DONE : 0, in nbd_co_send_chunk_read()
2164 return nbd_co_send_iov(client, iov, 3, errp); in nbd_co_send_chunk_read()
2167 static int coroutine_fn nbd_co_send_chunk_error(NBDClient *client, in nbd_co_send_chunk_error() argument
2185 set_be_chunk(client, iov, 3, NBD_REPLY_FLAG_DONE, in nbd_co_send_chunk_error()
2190 return nbd_co_send_iov(client, iov, 3, errp); in nbd_co_send_chunk_error()
2193 /* Do a sparse read and send the structured reply to the client.
2195 * reported to the client, at which point this function succeeds.
2197 static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client, in nbd_co_send_sparse_read() argument
2205 NBDExport *exp = client->exp; in nbd_co_send_sparse_read()
2221 ret = nbd_co_send_chunk_error(client, request, -status, msg, errp); in nbd_co_send_sparse_read()
2237 set_be_chunk(client, iov, 2, in nbd_co_send_sparse_read()
2242 ret = nbd_co_send_iov(client, iov, 2, errp); in nbd_co_send_sparse_read()
2250 ret = nbd_co_send_chunk_read(client, request, offset + progress, in nbd_co_send_sparse_read()
2336 * would result in an incorrect range reported to the client)
2437 nbd_co_send_extents(NBDClient *client, NBDRequest *request, NBDExtentArray *ea, in nbd_co_send_extents() argument
2447 if (client->mode >= NBD_MODE_EXTENDED) { in nbd_co_send_extents()
2472 set_be_chunk(client, iov, 3, last ? NBD_REPLY_FLAG_DONE : 0, type, in nbd_co_send_extents()
2475 return nbd_co_send_iov(client, iov, 3, errp); in nbd_co_send_extents()
2478 /* Get block status from the exported device and send it to the client */
2480 coroutine_fn nbd_co_send_block_status(NBDClient *client, NBDRequest *request, in nbd_co_send_block_status() argument
2489 nbd_extent_array_new(nb_extents, client->mode); in nbd_co_send_block_status()
2497 return nbd_co_send_chunk_error(client, request, -ret, in nbd_co_send_block_status()
2501 return nbd_co_send_extents(client, request, ea, last, context_id, errp); in nbd_co_send_block_status()
2537 static int coroutine_fn nbd_co_send_bitmap(NBDClient *client, in nbd_co_send_bitmap() argument
2547 nbd_extent_array_new(nb_extents, client->mode); in nbd_co_send_bitmap()
2551 return nbd_co_send_extents(client, request, ea, last, context_id, errp); in nbd_co_send_bitmap()
2556 * Called when a client wants a subset of negotiated contexts via a
2565 nbd_co_block_status_payload_read(NBDClient *client, NBDRequest *request, in nbd_co_block_status_payload_read() argument
2579 assert(client->contexts.exp == client->exp); in nbd_co_block_status_payload_read()
2580 nr_bitmaps = client->exp->nr_export_bitmaps; in nbd_co_block_status_payload_read()
2582 request->contexts->exp = client->exp; in nbd_co_block_status_payload_read()
2587 sizeof(id) * client->contexts.count)) { in nbd_co_block_status_payload_read()
2592 if (nbd_read(client->ioc, buf, payload_len, in nbd_co_block_status_payload_read()
2605 if (!client->contexts.base_allocation || in nbd_co_block_status_payload_read()
2611 if (!client->contexts.allocation_depth || in nbd_co_block_status_payload_read()
2619 if (idx >= nr_bitmaps || !client->contexts.bitmaps[idx] || in nbd_co_block_status_payload_read()
2635 return nbd_drop(client->ioc, payload_len, errp); in nbd_co_block_status_payload_read()
2639 * Collect a client request. Return 0 if request looks valid, -EIO to drop
2642 * to the client (although the caller may still need to disconnect after
2649 NBDClient *client = req->client; in nbd_co_receive_request() local
2660 ret = nbd_receive_request(client, request, errp); in nbd_co_receive_request()
2667 extended_with_payload = client->mode >= NBD_MODE_EXTENDED && in nbd_co_receive_request()
2682 if (client->mode >= NBD_MODE_STRUCTURED) { in nbd_co_receive_request()
2690 if (client->mode >= NBD_MODE_EXTENDED) { in nbd_co_receive_request()
2692 /* The client is noncompliant. Trace it, but proceed. */ in nbd_co_receive_request()
2723 ret = nbd_co_block_status_payload_read(client, request, errp); in nbd_co_receive_request()
2732 request->contexts = &client->contexts; in nbd_co_receive_request()
2764 req->data = blk_try_blockalign(client->exp->common.blk, in nbd_co_receive_request()
2775 ret = nbd_read(client->ioc, req->data, payload_len, in nbd_co_receive_request()
2778 ret = nbd_drop(client->ioc, payload_len, errp); in nbd_co_receive_request()
2789 if (client->exp->nbdflags & NBD_FLAG_READ_ONLY && check_rofs) { in nbd_co_receive_request()
2794 if (request->from > client->exp->size || in nbd_co_receive_request()
2795 request->len > client->exp->size - request->from) { in nbd_co_receive_request()
2798 client->exp->size); in nbd_co_receive_request()
2802 if (client->check_align && !QEMU_IS_ALIGNED(request->from | request->len, in nbd_co_receive_request()
2803 client->check_align)) { in nbd_co_receive_request()
2806 * it's still worth tracing client non-compliance in nbd_co_receive_request()
2811 client->check_align); in nbd_co_receive_request()
2824 * Returns 0 if connection is still live, -errno on failure to talk to client
2826 static coroutine_fn int nbd_send_generic_reply(NBDClient *client, in nbd_send_generic_reply() argument
2832 if (client->mode >= NBD_MODE_STRUCTURED && ret < 0) { in nbd_send_generic_reply()
2833 return nbd_co_send_chunk_error(client, request, -ret, error_msg, errp); in nbd_send_generic_reply()
2834 } else if (client->mode >= NBD_MODE_EXTENDED) { in nbd_send_generic_reply()
2835 return nbd_co_send_chunk_done(client, request, errp); in nbd_send_generic_reply()
2837 return nbd_co_send_simple_reply(client, request, ret < 0 ? -ret : 0, in nbd_send_generic_reply()
2844 * client as an error reply. */
2845 static coroutine_fn int nbd_do_cmd_read(NBDClient *client, NBDRequest *request, in nbd_do_cmd_read() argument
2849 NBDExport *exp = client->exp; in nbd_do_cmd_read()
2858 return nbd_send_generic_reply(client, request, ret, in nbd_do_cmd_read()
2863 if (client->mode >= NBD_MODE_STRUCTURED && in nbd_do_cmd_read()
2866 return nbd_co_send_sparse_read(client, request, request->from, in nbd_do_cmd_read()
2872 return nbd_send_generic_reply(client, request, ret, in nbd_do_cmd_read()
2876 if (client->mode >= NBD_MODE_STRUCTURED) { in nbd_do_cmd_read()
2878 return nbd_co_send_chunk_read(client, request, request->from, data, in nbd_do_cmd_read()
2881 return nbd_co_send_chunk_done(client, request, errp); in nbd_do_cmd_read()
2884 return nbd_co_send_simple_reply(client, request, 0, in nbd_do_cmd_read()
2894 * client as an error reply.
2896 static coroutine_fn int nbd_do_cmd_cache(NBDClient *client, NBDRequest *request, in nbd_do_cmd_cache() argument
2900 NBDExport *exp = client->exp; in nbd_do_cmd_cache()
2908 return nbd_send_generic_reply(client, request, ret, in nbd_do_cmd_cache()
2914 * client as an error reply. */
2915 static coroutine_fn int nbd_handle_request(NBDClient *client, in nbd_handle_request() argument
2921 NBDExport *exp = client->exp; in nbd_handle_request()
2935 return nbd_send_generic_reply(client, request, -EPERM, in nbd_handle_request()
2943 return nbd_do_cmd_cache(client, request, errp); in nbd_handle_request()
2946 return nbd_do_cmd_read(client, request, data, errp); in nbd_handle_request()
2956 return nbd_send_generic_reply(client, request, ret, in nbd_handle_request()
2972 return nbd_send_generic_reply(client, request, ret, in nbd_handle_request()
2981 return nbd_send_generic_reply(client, request, ret, in nbd_handle_request()
2989 return nbd_send_generic_reply(client, request, ret, in nbd_handle_request()
2994 assert(client->mode >= NBD_MODE_EXTENDED || in nbd_handle_request()
3001 return nbd_send_generic_reply(client, request, -EINVAL, in nbd_handle_request()
3005 ret = nbd_co_send_block_status(client, request, in nbd_handle_request()
3018 ret = nbd_co_send_block_status(client, request, in nbd_handle_request()
3030 assert(request->contexts->exp == client->exp); in nbd_handle_request()
3031 for (i = 0; i < client->exp->nr_export_bitmaps; i++) { in nbd_handle_request()
3035 ret = nbd_co_send_bitmap(client, request, in nbd_handle_request()
3036 client->exp->export_bitmaps[i], in nbd_handle_request()
3048 } else if (client->contexts.count) { in nbd_handle_request()
3049 return nbd_send_generic_reply(client, request, -EINVAL, in nbd_handle_request()
3053 return nbd_send_generic_reply(client, request, -EINVAL, in nbd_handle_request()
3061 ret = nbd_send_generic_reply(client, request, -EINVAL, msg, in nbd_handle_request()
3072 NBDClient *client = req->client; in nbd_trip() local
3085 qemu_mutex_lock(&client->lock); in nbd_trip()
3087 if (client->closing) { in nbd_trip()
3091 if (client->quiescing) { in nbd_trip()
3096 client->recv_coroutine = NULL; in nbd_trip()
3103 * set client->quiescing but by the time we get back nbd_drained_end() may in nbd_trip()
3104 * have already cleared client->quiescing. In that case we try again in nbd_trip()
3106 * client->recv_coroutine = NULL further down. in nbd_trip()
3109 assert(client->recv_coroutine == qemu_coroutine_self()); in nbd_trip()
3110 qemu_mutex_unlock(&client->lock); in nbd_trip()
3112 qemu_mutex_lock(&client->lock); in nbd_trip()
3113 } while (ret == -EAGAIN && !client->quiescing); in nbd_trip()
3115 client->recv_coroutine = NULL; in nbd_trip()
3117 if (client->closing) { in nbd_trip()
3119 * The client may be closed when we are blocked in in nbd_trip()
3129 nbd_client_receive_next_request(client); in nbd_trip()
3135 qemu_mutex_unlock(&client->lock); in nbd_trip()
3136 qio_channel_set_cork(client->ioc, true); in nbd_trip()
3140 * semantics, we should return the error to the client. */ in nbd_trip()
3144 ret = nbd_send_generic_reply(client, &request, -EINVAL, in nbd_trip()
3148 ret = nbd_handle_request(client, &request, req->data, &local_err); in nbd_trip()
3150 if (request.contexts && request.contexts != &client->contexts) { in nbd_trip()
3156 qio_channel_set_cork(client->ioc, false); in nbd_trip()
3157 qemu_mutex_lock(&client->lock); in nbd_trip()
3176 qemu_mutex_unlock(&client->lock); in nbd_trip()
3178 if (!nbd_client_put_nonzero(client)) { in nbd_trip()
3180 nbd_client_put(client); in nbd_trip()
3186 error_reportf_err(local_err, "Disconnect client, due to: "); in nbd_trip()
3190 qemu_mutex_unlock(&client->lock); in nbd_trip()
3193 client_close(client, true); in nbd_trip()
3194 nbd_client_put(client); in nbd_trip()
3199 * client->lock.
3201 static void nbd_client_receive_next_request(NBDClient *client) in nbd_client_receive_next_request() argument
3205 if (!client->recv_coroutine && client->nb_requests < MAX_NBD_REQUESTS && in nbd_client_receive_next_request()
3206 !client->quiescing) { in nbd_client_receive_next_request()
3207 nbd_client_get(client); in nbd_client_receive_next_request()
3208 req = nbd_request_get(client); in nbd_client_receive_next_request()
3209 client->recv_coroutine = qemu_coroutine_create(nbd_trip, req); in nbd_client_receive_next_request()
3210 aio_co_schedule(client->exp->common.ctx, client->recv_coroutine); in nbd_client_receive_next_request()
3224 NBDClient *client = opaque; in nbd_co_client_start() local
3228 qemu_co_mutex_init(&client->send_lock); in nbd_co_client_start()
3235 if (client->handshake_max_secs > 0) { in nbd_co_client_start()
3240 client->sioc); in nbd_co_client_start()
3243 client->handshake_max_secs * NANOSECONDS_PER_SECOND); in nbd_co_client_start()
3246 if (nbd_negotiate(client, &local_err)) { in nbd_co_client_start()
3251 client_close(client, false); in nbd_co_client_start()
3256 WITH_QEMU_LOCK_GUARD(&client->lock) { in nbd_co_client_start()
3257 nbd_client_receive_next_request(client); in nbd_co_client_start()
3262 * Create a new client listener using the given channel @sioc and @owner.
3264 * @close_fn with an indication of whether the client completed negotiation
3274 NBDClient *client; in nbd_client_new() local
3277 client = g_new0(NBDClient, 1); in nbd_client_new()
3278 qemu_mutex_init(&client->lock); in nbd_client_new()
3279 client->refcount = 1; in nbd_client_new()
3280 client->tlscreds = tlscreds; in nbd_client_new()
3282 object_ref(OBJECT(client->tlscreds)); in nbd_client_new()
3284 client->tlsauthz = g_strdup(tlsauthz); in nbd_client_new()
3285 client->handshake_max_secs = handshake_max_secs; in nbd_client_new()
3286 client->sioc = sioc; in nbd_client_new()
3288 object_ref(OBJECT(client->sioc)); in nbd_client_new()
3289 client->ioc = QIO_CHANNEL(sioc); in nbd_client_new()
3290 object_ref(OBJECT(client->ioc)); in nbd_client_new()
3291 client->close_fn = close_fn; in nbd_client_new()
3292 client->owner = owner; in nbd_client_new()
3296 co = qemu_coroutine_create(nbd_co_client_start, client); in nbd_client_new()
3301 nbd_client_owner(NBDClient *client) in nbd_client_owner() argument
3303 return client->owner; in nbd_client_owner()