From nobody Tue Feb 10 19:48:05 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1498059540588176.8941253931613; Wed, 21 Jun 2017 08:39:00 -0700 (PDT) Received: from localhost ([::1]:54715 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dNhiY-0002lb-Sk for importer@patchew.org; Wed, 21 Jun 2017 11:38:54 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50427) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dNheN-0007vm-HV for qemu-devel@nongnu.org; Wed, 21 Jun 2017 11:34:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dNheI-0008Qt-Ob for qemu-devel@nongnu.org; Wed, 21 Jun 2017 11:34:35 -0400 Received: from mailhub.sw.ru ([195.214.232.25]:31325 helo=relay.sw.ru) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dNheI-0008Oy-4R for qemu-devel@nongnu.org; Wed, 21 Jun 2017 11:34:30 -0400 Received: from kvm.sw.ru (msk-vpn.virtuozzo.com [195.214.232.6]) by relay.sw.ru (8.13.4/8.13.4) with ESMTP id v5LFYOHg025147; Wed, 21 Jun 2017 18:34:24 +0300 (MSK) From: Vladimir Sementsov-Ogievskiy To: qemu-devel@nongnu.org Date: Wed, 21 Jun 2017 18:34:20 +0300 Message-Id: <20170621153424.16690-3-vsementsov@virtuozzo.com> X-Mailer: git-send-email 2.11.1 In-Reply-To: <20170621153424.16690-1-vsementsov@virtuozzo.com> References: <20170621153424.16690-1-vsementsov@virtuozzo.com> X-detected-operating-system: by eggs.gnu.org: OpenBSD 3.x [fuzzy] X-Received-From: 195.214.232.25 Subject: [Qemu-devel] [PATCH v2 2/6] nbd/server: use errp instead of LOG X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: pbonzini@redhat.com, vsementsov@virtuozzo.com, stefanha@redhat.com, den@openvz.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Move to modern errp scheme from just LOGging errors. Signed-off-by: Vladimir Sementsov-Ogievskiy --- nbd/server.c | 268 +++++++++++++++++++++++++++++++++++--------------------= ---- 1 file changed, 161 insertions(+), 107 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index f0bff23b8b..fa493602dd 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -134,7 +134,7 @@ static void nbd_client_receive_next_request(NBDClient *= client); /* Send a reply header, including length, but no payload. * Return -errno on error, 0 on success. */ static int nbd_negotiate_send_rep_len(QIOChannel *ioc, uint32_t type, - uint32_t opt, uint32_t len) + uint32_t opt, uint32_t len, Error **= errp) { uint64_t magic; =20 @@ -142,23 +142,26 @@ static int nbd_negotiate_send_rep_len(QIOChannel *ioc= , uint32_t type, type, opt, len); =20 magic =3D cpu_to_be64(NBD_REP_MAGIC); - if (nbd_write(ioc, &magic, sizeof(magic), NULL) < 0) { - LOG("write failed (rep magic)"); + if (nbd_write(ioc, &magic, sizeof(magic), errp) < 0) { + error_prepend(errp, "write failed (rep magic): "); return -EINVAL; } + opt =3D cpu_to_be32(opt); - if (nbd_write(ioc, &opt, sizeof(opt), NULL) < 0) { - LOG("write failed (rep opt)"); + if (nbd_write(ioc, &opt, sizeof(opt), errp) < 0) { + error_prepend(errp, "write failed (rep opt): "); return -EINVAL; } + type =3D cpu_to_be32(type); - if (nbd_write(ioc, &type, sizeof(type), NULL) < 0) { - LOG("write failed (rep type)"); + if (nbd_write(ioc, &type, sizeof(type), errp) < 0) { + error_prepend(errp, "write failed (rep type): "); return -EINVAL; } + len =3D cpu_to_be32(len); - if (nbd_write(ioc, &len, sizeof(len), NULL) < 0) { - LOG("write failed (rep data length)"); + if (nbd_write(ioc, &len, sizeof(len), errp) < 0) { + error_prepend(errp, "write failed (rep data length): "); return -EINVAL; } return 0; @@ -166,16 +169,17 @@ static int nbd_negotiate_send_rep_len(QIOChannel *ioc= , uint32_t type, =20 /* Send a reply header with default 0 length. * Return -errno on error, 0 on success. */ -static int nbd_negotiate_send_rep(QIOChannel *ioc, uint32_t type, uint32_t= opt) +static int nbd_negotiate_send_rep(QIOChannel *ioc, uint32_t type, uint32_t= opt, + Error **errp) { - return nbd_negotiate_send_rep_len(ioc, type, opt, 0); + return nbd_negotiate_send_rep_len(ioc, type, opt, 0, errp); } =20 /* Send an error reply. * Return -errno on error, 0 on success. */ -static int GCC_FMT_ATTR(4, 5) +static int GCC_FMT_ATTR(5, 6) nbd_negotiate_send_rep_err(QIOChannel *ioc, uint32_t type, - uint32_t opt, const char *fmt, ...) + uint32_t opt, Error **errp, const char *fmt, ..= .) { va_list va; char *msg; @@ -188,16 +192,17 @@ nbd_negotiate_send_rep_err(QIOChannel *ioc, uint32_t = type, len =3D strlen(msg); assert(len < 4096); TRACE("sending error message \"%s\"", msg); - ret =3D nbd_negotiate_send_rep_len(ioc, type, opt, len); + ret =3D nbd_negotiate_send_rep_len(ioc, type, opt, len, errp); if (ret < 0) { goto out; } - if (nbd_write(ioc, msg, len, NULL) < 0) { - LOG("write failed (error message)"); + if (nbd_write(ioc, msg, len, errp) < 0) { + error_prepend(errp, "write failed (error message): "); ret =3D -EIO; } else { ret =3D 0; } + out: g_free(msg); return ret; @@ -205,7 +210,8 @@ out: =20 /* Send a single NBD_REP_SERVER reply to NBD_OPT_LIST, including payload. * Return -errno on error, 0 on success. */ -static int nbd_negotiate_send_rep_list(QIOChannel *ioc, NBDExport *exp) +static int nbd_negotiate_send_rep_list(QIOChannel *ioc, NBDExport *exp, + Error **errp) { size_t name_len, desc_len; uint32_t len; @@ -217,53 +223,60 @@ static int nbd_negotiate_send_rep_list(QIOChannel *io= c, NBDExport *exp) name_len =3D strlen(name); desc_len =3D strlen(desc); len =3D name_len + desc_len + sizeof(len); - ret =3D nbd_negotiate_send_rep_len(ioc, NBD_REP_SERVER, NBD_OPT_LIST, = len); + ret =3D nbd_negotiate_send_rep_len(ioc, NBD_REP_SERVER, NBD_OPT_LIST, = len, + errp); if (ret < 0) { return ret; } =20 len =3D cpu_to_be32(name_len); - if (nbd_write(ioc, &len, sizeof(len), NULL) < 0) { - LOG("write failed (name length)"); + if (nbd_write(ioc, &len, sizeof(len), errp) < 0) { + error_prepend(errp, "write failed (name length): "); return -EINVAL; } - if (nbd_write(ioc, name, name_len, NULL) < 0) { - LOG("write failed (name buffer)"); + + if (nbd_write(ioc, name, name_len, errp) < 0) { + error_prepend(errp, "write failed (name buffer): "); return -EINVAL; } - if (nbd_write(ioc, desc, desc_len, NULL) < 0) { - LOG("write failed (description buffer)"); + + if (nbd_write(ioc, desc, desc_len, errp) < 0) { + error_prepend(errp, "write failed (description buffer): "); return -EINVAL; } + return 0; } =20 /* Process the NBD_OPT_LIST command, with a potential series of replies. * Return -errno on error, 0 on success. */ -static int nbd_negotiate_handle_list(NBDClient *client, uint32_t length) +static int nbd_negotiate_handle_list(NBDClient *client, uint32_t length, + Error **errp) { NBDExport *exp; =20 if (length) { - if (nbd_drop(client->ioc, length, NULL) < 0) { + if (nbd_drop(client->ioc, length, errp) < 0) { return -EIO; } return nbd_negotiate_send_rep_err(client->ioc, NBD_REP_ERR_INVALID, NBD_OPT_LIS= T, + errp, "OPT_LIST should not have length= "); } =20 /* For each export, send a NBD_REP_SERVER reply. */ QTAILQ_FOREACH(exp, &exports, next) { - if (nbd_negotiate_send_rep_list(client->ioc, exp)) { + if (nbd_negotiate_send_rep_list(client->ioc, exp, errp)) { return -EINVAL; } } /* Finish with a NBD_REP_ACK. */ - return nbd_negotiate_send_rep(client->ioc, NBD_REP_ACK, NBD_OPT_LIST); + return nbd_negotiate_send_rep(client->ioc, NBD_REP_ACK, NBD_OPT_LIST, = errp); } =20 -static int nbd_negotiate_handle_export_name(NBDClient *client, uint32_t le= ngth) +static int nbd_negotiate_handle_export_name(NBDClient *client, uint32_t le= ngth, + Error **errp) { char name[NBD_MAX_NAME_SIZE + 1]; =20 @@ -272,11 +285,11 @@ static int nbd_negotiate_handle_export_name(NBDClient= *client, uint32_t length) */ TRACE("Checking length"); if (length >=3D sizeof(name)) { - LOG("Bad length received"); + error_setg(errp, "Bad length received"); return -EINVAL; } - if (nbd_read(client->ioc, name, length, NULL) < 0) { - LOG("read failed"); + if (nbd_read(client->ioc, name, length, errp) < 0) { + error_prepend(errp, "read failed: "); return -EINVAL; } name[length] =3D '\0'; @@ -285,7 +298,7 @@ static int nbd_negotiate_handle_export_name(NBDClient *= client, uint32_t length) =20 client->exp =3D nbd_export_find(name); if (!client->exp) { - LOG("export not found"); + error_setg(errp, "export not found"); return -EINVAL; } =20 @@ -298,7 +311,8 @@ static int nbd_negotiate_handle_export_name(NBDClient *= client, uint32_t length) /* Handle NBD_OPT_STARTTLS. Return NULL to drop connection, or else the * new channel for all further (now-encrypted) communication. */ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client, - uint32_t length) + uint32_t length, + Error **errp) { QIOChannel *ioc; QIOChannelTLS *tioc; @@ -307,23 +321,24 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDC= lient *client, TRACE("Setting up TLS"); ioc =3D client->ioc; if (length) { - if (nbd_drop(ioc, length, NULL) < 0) { + if (nbd_drop(ioc, length, errp) < 0) { return NULL; } nbd_negotiate_send_rep_err(ioc, NBD_REP_ERR_INVALID, NBD_OPT_START= TLS, + errp, "OPT_STARTTLS should not have length"); return NULL; } =20 if (nbd_negotiate_send_rep(client->ioc, NBD_REP_ACK, - NBD_OPT_STARTTLS) < 0) { + NBD_OPT_STARTTLS, errp) < 0) { return NULL; } =20 tioc =3D qio_channel_tls_new_server(ioc, client->tlscreds, client->tlsaclname, - NULL); + errp); if (!tioc) { return NULL; } @@ -342,7 +357,7 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDCli= ent *client, g_main_loop_unref(data.loop); if (data.error) { object_unref(OBJECT(tioc)); - error_free(data.error); + error_propagate(errp, data.error); return NULL; } =20 @@ -352,14 +367,16 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDC= lient *client, /* nbd_negotiate_options * Process all NBD_OPT_* client option commands. * Return: - * -errno on error - * 0 on successful negotiation - * 1 if client sent NBD_OPT_ABORT, i.e. on legal disconnect + * -errno on error, errp is set + * 0 on successful negotiation, errp is not set + * 1 if client sent NBD_OPT_ABORT, i.e. on legal disconnect, + * errp is not set */ -static int nbd_negotiate_options(NBDClient *client) +static int nbd_negotiate_options(NBDClient *client, Error **errp) { uint32_t flags; bool fixedNewstyle =3D false; + Error *local_err =3D NULL; =20 /* Client sends: [ 0 .. 3] client flags @@ -375,8 +392,8 @@ static int nbd_negotiate_options(NBDClient *client) ... Rest of request */ =20 - if (nbd_read(client->ioc, &flags, sizeof(flags), NULL) < 0) { - LOG("read failed"); + if (nbd_read(client->ioc, &flags, sizeof(flags), errp) < 0) { + error_prepend(errp, "read failed: "); return -EIO; } TRACE("Checking client flags"); @@ -392,7 +409,7 @@ static int nbd_negotiate_options(NBDClient *client) flags &=3D ~NBD_FLAG_C_NO_ZEROES; } if (flags !=3D 0) { - TRACE("Unknown client flags 0x%" PRIx32 " received", flags); + error_setg(errp, "Unknown client flags 0x%" PRIx32 " received", fl= ags); return -EIO; } =20 @@ -401,26 +418,25 @@ static int nbd_negotiate_options(NBDClient *client) uint32_t clientflags, length; uint64_t magic; =20 - if (nbd_read(client->ioc, &magic, sizeof(magic), NULL) < 0) { - LOG("read failed"); + if (nbd_read(client->ioc, &magic, sizeof(magic), errp) < 0) { + error_prepend(errp, "read failed: "); return -EINVAL; } TRACE("Checking opts magic"); if (magic !=3D be64_to_cpu(NBD_OPTS_MAGIC)) { - LOG("Bad magic received"); + error_setg(errp, "Bad magic received"); return -EINVAL; } =20 if (nbd_read(client->ioc, &clientflags, - sizeof(clientflags), NULL) < 0) - { - LOG("read failed"); + sizeof(clientflags), errp) < 0) { + error_prepend(errp, "read failed: "); return -EINVAL; } clientflags =3D be32_to_cpu(clientflags); =20 - if (nbd_read(client->ioc, &length, sizeof(length), NULL) < 0) { - LOG("read failed"); + if (nbd_read(client->ioc, &length, sizeof(length), errp) < 0) { + error_prepend(errp, "read failed: "); return -EINVAL; } length =3D be32_to_cpu(length); @@ -430,12 +446,12 @@ static int nbd_negotiate_options(NBDClient *client) client->ioc =3D=3D (QIOChannel *)client->sioc) { QIOChannel *tioc; if (!fixedNewstyle) { - TRACE("Unsupported option 0x%" PRIx32, clientflags); + error_setg(errp, "Unsupported option 0x%" PRIx32, clientfl= ags); return -EINVAL; } switch (clientflags) { case NBD_OPT_STARTTLS: - tioc =3D nbd_negotiate_handle_starttls(client, length); + tioc =3D nbd_negotiate_handle_starttls(client, length, err= p); if (!tioc) { return -EIO; } @@ -445,16 +461,17 @@ static int nbd_negotiate_options(NBDClient *client) =20 case NBD_OPT_EXPORT_NAME: /* No way to return an error to client, so drop connection= */ - TRACE("Option 0x%x not permitted before TLS", clientflags); + error_setg(errp, "Option 0x%x not permitted before TLS", + clientflags); return -EINVAL; =20 default: - if (nbd_drop(client->ioc, length, NULL) < 0) { + if (nbd_drop(client->ioc, length, errp) < 0) { return -EIO; } ret =3D nbd_negotiate_send_rep_err(client->ioc, NBD_REP_ERR_TLS_REQD, - clientflags, + clientflags, errp, "Option 0x%" PRIx32 "not permitted before TLS= ", clientflags); @@ -470,7 +487,7 @@ static int nbd_negotiate_options(NBDClient *client) } else if (fixedNewstyle) { switch (clientflags) { case NBD_OPT_LIST: - ret =3D nbd_negotiate_handle_list(client, length); + ret =3D nbd_negotiate_handle_list(client, length, errp); if (ret < 0) { return ret; } @@ -480,25 +497,33 @@ static int nbd_negotiate_options(NBDClient *client) /* NBD spec says we must try to reply before * disconnecting, but that we must also tolerate * guests that don't wait for our reply. */ - nbd_negotiate_send_rep(client->ioc, NBD_REP_ACK, clientfla= gs); + nbd_negotiate_send_rep(client->ioc, NBD_REP_ACK, clientfla= gs, + &local_err); + + if (local_err !=3D NULL) { + TRACE("Reply to NBD_OPT_ABORT request failed: %s", + error_get_pretty(local_err)); + error_free(local_err); + } + return 1; =20 case NBD_OPT_EXPORT_NAME: - return nbd_negotiate_handle_export_name(client, length); + return nbd_negotiate_handle_export_name(client, length, er= rp); =20 case NBD_OPT_STARTTLS: - if (nbd_drop(client->ioc, length, NULL) < 0) { + if (nbd_drop(client->ioc, length, errp) < 0) { return -EIO; } if (client->tlscreds) { ret =3D nbd_negotiate_send_rep_err(client->ioc, NBD_REP_ERR_INVALID, - clientflags, + clientflags, errp, "TLS already enabled"= ); } else { ret =3D nbd_negotiate_send_rep_err(client->ioc, NBD_REP_ERR_POLICY, - clientflags, + clientflags, errp, "TLS not configured"); } if (ret < 0) { @@ -506,12 +531,12 @@ static int nbd_negotiate_options(NBDClient *client) } break; default: - if (nbd_drop(client->ioc, length, NULL) < 0) { + if (nbd_drop(client->ioc, length, errp) < 0) { return -EIO; } ret =3D nbd_negotiate_send_rep_err(client->ioc, NBD_REP_ERR_UNSUP, - clientflags, + clientflags, errp, "Unsupported option 0x%" PRIx32, clientflags); @@ -527,10 +552,10 @@ static int nbd_negotiate_options(NBDClient *client) */ switch (clientflags) { case NBD_OPT_EXPORT_NAME: - return nbd_negotiate_handle_export_name(client, length); + return nbd_negotiate_handle_export_name(client, length, er= rp); =20 default: - TRACE("Unsupported option 0x%" PRIx32, clientflags); + error_setg(errp, "Unsupported option 0x%" PRIx32, clientfl= ags); return -EINVAL; } } @@ -539,11 +564,12 @@ static int nbd_negotiate_options(NBDClient *client) =20 /* nbd_negotiate * Return: - * -errno on error - * 0 on successful negotiation - * 1 if client sent NBD_OPT_ABORT, i.e. on legal disconnect + * -errno on error, errp is set + * 0 on successful negotiation, errp is not set + * 1 if client sent NBD_OPT_ABORT, i.e. on legal disconnect, + * errp is not set */ -static coroutine_fn int nbd_negotiate(NBDClient *client) +static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp) { char buf[8 + 8 + 8 + 128]; int ret; @@ -591,21 +617,23 @@ static coroutine_fn int nbd_negotiate(NBDClient *clie= nt) =20 if (oldStyle) { if (client->tlscreds) { - TRACE("TLS cannot be enabled with oldstyle protocol"); + error_setg(errp, "TLS cannot be enabled with oldstyle protocol= "); return -EINVAL; } - if (nbd_write(client->ioc, buf, sizeof(buf), NULL) < 0) { - LOG("write failed"); + if (nbd_write(client->ioc, buf, sizeof(buf), errp) < 0) { + error_prepend(errp, "write failed: "); return -EINVAL; } } else { - if (nbd_write(client->ioc, buf, 18, NULL) < 0) { - LOG("write failed"); + if (nbd_write(client->ioc, buf, 18, errp) < 0) { + error_prepend(errp, "write failed: "); return -EINVAL; } - ret =3D nbd_negotiate_options(client); + ret =3D nbd_negotiate_options(client, errp); if (ret !=3D 0) { - LOG("option negotiation failed"); + if (ret < 0) { + error_prepend(errp, "option negotiation failed: "); + } return ret; } =20 @@ -614,9 +642,9 @@ static coroutine_fn int nbd_negotiate(NBDClient *client) stq_be_p(buf + 18, client->exp->size); stw_be_p(buf + 26, client->exp->nbdflags | myflags); len =3D client->no_zeroes ? 10 : sizeof(buf) - 18; - ret =3D nbd_write(client->ioc, buf + 18, len, NULL); + ret =3D nbd_write(client->ioc, buf + 18, len, errp); if (ret < 0) { - LOG("write failed"); + error_prepend(errp, "write failed: "); return ret; } } @@ -626,13 +654,14 @@ static coroutine_fn int nbd_negotiate(NBDClient *clie= nt) return 0; } =20 -static int nbd_receive_request(QIOChannel *ioc, NBDRequest *request) +static int nbd_receive_request(QIOChannel *ioc, NBDRequest *request, + Error **errp) { uint8_t buf[NBD_REQUEST_SIZE]; uint32_t magic; int ret; =20 - ret =3D nbd_read(ioc, buf, sizeof(buf), NULL); + ret =3D nbd_read(ioc, buf, sizeof(buf), errp); if (ret < 0) { return ret; } @@ -658,7 +687,7 @@ static int nbd_receive_request(QIOChannel *ioc, NBDRequ= est *request) magic, request->flags, request->type, request->from, request->le= n); =20 if (magic !=3D NBD_REQUEST_MAGIC) { - LOG("invalid magic (got 0x%" PRIx32 ")", magic); + error_setg(errp, "invalid magic (got 0x%" PRIx32 ")", magic); return -EINVAL; } return 0; @@ -1004,13 +1033,14 @@ static int nbd_co_send_reply(NBDRequestData *req, N= BDReply *reply, int len) * the client (although the caller may still need to disconnect after repo= rting * the error). */ -static int nbd_co_receive_request(NBDRequestData *req, NBDRequest *request) +static int nbd_co_receive_request(NBDRequestData *req, NBDRequest *request, + Error **errp) { NBDClient *client =3D req->client; =20 g_assert(qemu_in_coroutine()); assert(client->recv_coroutine =3D=3D qemu_coroutine_self()); - if (nbd_receive_request(client->ioc, request) < 0) { + if (nbd_receive_request(client->ioc, request, errp) < 0) { return -EIO; } =20 @@ -1032,27 +1062,29 @@ static int nbd_co_receive_request(NBDRequestData *r= eq, NBDRequest *request) * checks as possible until after reading any NBD_CMD_WRITE * payload, so we can try and keep the connection alive. */ if ((request->from + request->len) < request->from) { - LOG("integer overflow detected, you're probably being attacked"); + error_setg(errp, + "integer overflow detected, you're probably being attac= ked"); return -EINVAL; } =20 if (request->type =3D=3D NBD_CMD_READ || request->type =3D=3D NBD_CMD_= WRITE) { if (request->len > NBD_MAX_BUFFER_SIZE) { - LOG("len (%" PRIu32" ) is larger than max len (%u)", - request->len, NBD_MAX_BUFFER_SIZE); + error_setg(errp, "len (%" PRIu32" ) is larger than max len (%u= )", + request->len, NBD_MAX_BUFFER_SIZE); return -EINVAL; } =20 req->data =3D blk_try_blockalign(client->exp->blk, request->len); if (req->data =3D=3D NULL) { + error_setg(errp, "No memory"); return -ENOMEM; } } if (request->type =3D=3D NBD_CMD_WRITE) { TRACE("Reading %" PRIu32 " byte(s)", request->len); =20 - if (nbd_read(client->ioc, req->data, request->len, NULL) < 0) { - LOG("reading from socket failed"); + if (nbd_read(client->ioc, req->data, request->len, errp) < 0) { + error_prepend(errp, "reading from socket failed: "); return -EIO; } req->complete =3D true; @@ -1060,18 +1092,18 @@ static int nbd_co_receive_request(NBDRequestData *r= eq, NBDRequest *request) =20 /* Sanity checks, part 2. */ if (request->from + request->len > client->exp->size) { - LOG("operation past EOF; From: %" PRIu64 ", Len: %" PRIu32 - ", Size: %" PRIu64, request->from, request->len, - (uint64_t)client->exp->size); + error_setg(errp, "operation past EOF; From: %" PRIu64 ", Len: %" P= RIu32 + ", Size: %" PRIu64, request->from, request->len, + (uint64_t)client->exp->size); return request->type =3D=3D NBD_CMD_WRITE ? -ENOSPC : -EINVAL; } if (request->flags & ~(NBD_CMD_FLAG_FUA | NBD_CMD_FLAG_NO_HOLE)) { - LOG("unsupported flags (got 0x%x)", request->flags); + error_setg(errp, "unsupported flags (got 0x%x)", request->flags); return -EINVAL; } if (request->type !=3D NBD_CMD_WRITE_ZEROES && (request->flags & NBD_CMD_FLAG_NO_HOLE)) { - LOG("unexpected flags (got 0x%x)", request->flags); + error_setg(errp, "unexpected flags (got 0x%x)", request->flags); return -EINVAL; } =20 @@ -1089,6 +1121,7 @@ static coroutine_fn void nbd_trip(void *opaque) int ret; int flags; int reply_data_len =3D 0; + Error *local_err =3D NULL; =20 TRACE("Reading request."); if (client->closing) { @@ -1097,7 +1130,7 @@ static coroutine_fn void nbd_trip(void *opaque) } =20 req =3D nbd_request_get(client); - ret =3D nbd_co_receive_request(req, &request); + ret =3D nbd_co_receive_request(req, &request, &local_err); client->recv_coroutine =3D NULL; nbd_client_receive_next_request(client); if (ret =3D=3D -EIO) { @@ -1128,7 +1161,7 @@ static coroutine_fn void nbd_trip(void *opaque) if (request.flags & NBD_CMD_FLAG_FUA) { ret =3D blk_co_flush(exp->blk); if (ret < 0) { - LOG("flush failed"); + error_setg_errno(&local_err, -ret, "flush failed"); reply.error =3D -ret; break; } @@ -1137,7 +1170,7 @@ static coroutine_fn void nbd_trip(void *opaque) ret =3D blk_pread(exp->blk, request.from + exp->dev_offset, req->data, request.len); if (ret < 0) { - LOG("reading from file failed"); + error_setg_errno(&local_err, -ret, "reading from file failed"); reply.error =3D -ret; break; } @@ -1164,7 +1197,7 @@ static coroutine_fn void nbd_trip(void *opaque) ret =3D blk_pwrite(exp->blk, request.from + exp->dev_offset, req->data, request.len, flags); if (ret < 0) { - LOG("writing to file failed"); + error_setg_errno(&local_err, -ret, "writing to file failed"); reply.error =3D -ret; } =20 @@ -1173,7 +1206,7 @@ static coroutine_fn void nbd_trip(void *opaque) TRACE("Request type is WRITE_ZEROES"); =20 if (exp->nbdflags & NBD_FLAG_READ_ONLY) { - TRACE("Server is read-only, return error"); + error_setg(&local_err, "Server is read-only, return error"); reply.error =3D EROFS; break; } @@ -1190,7 +1223,7 @@ static coroutine_fn void nbd_trip(void *opaque) ret =3D blk_pwrite_zeroes(exp->blk, request.from + exp->dev_offset, request.len, flags); if (ret < 0) { - LOG("writing to file failed"); + error_setg_errno(&local_err, -ret, "writing to file failed"); reply.error =3D -ret; } =20 @@ -1204,7 +1237,7 @@ static coroutine_fn void nbd_trip(void *opaque) =20 ret =3D blk_co_flush(exp->blk); if (ret < 0) { - LOG("flush failed"); + error_setg_errno(&local_err, -ret, "flush failed"); reply.error =3D -ret; } =20 @@ -1214,21 +1247,35 @@ static coroutine_fn void nbd_trip(void *opaque) ret =3D blk_co_pdiscard(exp->blk, request.from + exp->dev_offset, request.len); if (ret < 0) { - LOG("discard failed"); + error_setg_errno(&local_err, -ret, "discard failed"); reply.error =3D -ret; } =20 break; default: - LOG("invalid request type (%" PRIu32 ") received", request.type); + error_setg(&local_err, "invalid request type (%" PRIu32 ") receive= d", + request.type); reply.error =3D EINVAL; } =20 reply: + if (local_err) { + /* If we are here local_err is not fatal error, already stored in + * reply.error */ + error_report_err(local_err); + local_err =3D NULL; + } + + if (nbd_co_send_reply(req, &reply, reply_data_len) < 0) { + error_setg(&local_err, "Failed to send reply"); + goto disconnect; + } + /* We must disconnect after NBD_CMD_WRITE if we did not * read the payload. */ - if (nbd_co_send_reply(req, &reply, reply_data_len) < 0 || !req->comple= te) { + if (!req->complete) { + error_setg(&local_err, "Request handling failed in intermediate st= ate"); goto disconnect; } =20 @@ -1240,6 +1287,9 @@ done: return; =20 disconnect: + if (local_err) { + error_reportf_err(local_err, "Disconnect client, due to: "); + } nbd_request_put(req); client_close(client, true); nbd_client_put(client); @@ -1258,6 +1308,7 @@ static coroutine_fn void nbd_co_client_start(void *op= aque) { NBDClient *client =3D opaque; NBDExport *exp =3D client->exp; + Error *local_err =3D NULL; =20 if (exp) { nbd_export_get(exp); @@ -1265,7 +1316,10 @@ static coroutine_fn void nbd_co_client_start(void *o= paque) } qemu_co_mutex_init(&client->send_lock); =20 - if (nbd_negotiate(client)) { + if (nbd_negotiate(client, &local_err)) { + if (local_err) { + error_report_err(local_err); + } client_close(client, false); return; } --=20 2.11.1