[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 19/27] nbd: Less allocation during NBD_OPT_LIST
From: |
Paolo Bonzini |
Subject: |
[Qemu-devel] [PULL 19/27] nbd: Less allocation during NBD_OPT_LIST |
Date: |
Mon, 31 Oct 2016 15:37:35 +0100 |
From: Eric Blake <address@hidden>
Since we know that the maximum name we are willing to accept
is small enough to stack-allocate, rework the iteration over
NBD_OPT_LIST responses to reuse a stack buffer rather than
allocating every time. Furthermore, we don't even have to
allocate if we know the server's length doesn't match what
we are searching for.
Signed-off-by: Eric Blake <address@hidden>
Message-Id: <address@hidden>
Signed-off-by: Paolo Bonzini <address@hidden>
---
nbd/client.c | 139 ++++++++++++++++++++++++++++-------------------------------
1 file changed, 67 insertions(+), 72 deletions(-)
diff --git a/nbd/client.c b/nbd/client.c
index 5d94e34..0afb8be 100644
--- a/nbd/client.c
+++ b/nbd/client.c
@@ -254,19 +254,28 @@ static int nbd_handle_reply_err(QIOChannel *ioc,
nbd_opt_reply *reply,
return result;
}
-static int nbd_receive_list(QIOChannel *ioc, char **name, Error **errp)
+/* Process another portion of the NBD_OPT_LIST reply. Set address@hidden if
+ * the current reply matches @want or if the server does not support
+ * NBD_OPT_LIST, otherwise leave @match alone. Return 0 if iteration
+ * is complete, positive if more replies are expected, or negative
+ * with @errp set if an unrecoverable error occurred. */
+static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
+ Error **errp)
{
nbd_opt_reply reply;
uint32_t len;
uint32_t namelen;
+ char name[NBD_MAX_NAME_SIZE + 1];
int error;
- *name = NULL;
if (nbd_receive_option_reply(ioc, NBD_OPT_LIST, &reply, errp) < 0) {
return -1;
}
error = nbd_handle_reply_err(ioc, &reply, errp);
if (error <= 0) {
+ /* The server did not support NBD_OPT_LIST, so set *match on
+ * the assumption that any name will be accepted. */
+ *match = true;
return error;
}
len = reply.length;
@@ -277,105 +286,91 @@ static int nbd_receive_list(QIOChannel *ioc, char
**name, Error **errp)
nbd_send_opt_abort(ioc);
return -1;
}
- } else if (reply.type == NBD_REP_SERVER) {
- if (len < sizeof(namelen) || len > NBD_MAX_BUFFER_SIZE) {
- error_setg(errp, "incorrect option length %" PRIu32, len);
- nbd_send_opt_abort(ioc);
- return -1;
- }
- if (read_sync(ioc, &namelen, sizeof(namelen)) != sizeof(namelen)) {
- error_setg(errp, "failed to read option name length");
- nbd_send_opt_abort(ioc);
- return -1;
- }
- namelen = be32_to_cpu(namelen);
- len -= sizeof(namelen);
- if (len < namelen) {
- error_setg(errp, "incorrect option name length");
- nbd_send_opt_abort(ioc);
- return -1;
- }
- if (namelen > NBD_MAX_NAME_SIZE) {
- error_setg(errp, "export name length too long %" PRIu32, namelen);
- nbd_send_opt_abort(ioc);
- return -1;
- }
+ return 0;
+ } else if (reply.type != NBD_REP_SERVER) {
+ error_setg(errp, "Unexpected reply type %" PRIx32 " expected %x",
+ reply.type, NBD_REP_SERVER);
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
- *name = g_new0(char, namelen + 1);
- if (read_sync(ioc, *name, namelen) != namelen) {
- error_setg(errp, "failed to read export name");
- g_free(*name);
- *name = NULL;
- nbd_send_opt_abort(ioc);
- return -1;
- }
- (*name)[namelen] = '\0';
- len -= namelen;
+ if (len < sizeof(namelen) || len > NBD_MAX_BUFFER_SIZE) {
+ error_setg(errp, "incorrect option length %" PRIu32, len);
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ if (read_sync(ioc, &namelen, sizeof(namelen)) != sizeof(namelen)) {
+ error_setg(errp, "failed to read option name length");
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ namelen = be32_to_cpu(namelen);
+ len -= sizeof(namelen);
+ if (len < namelen) {
+ error_setg(errp, "incorrect option name length");
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ if (namelen != strlen(want)) {
if (drop_sync(ioc, len) != len) {
- error_setg(errp, "failed to read export description");
- g_free(*name);
- *name = NULL;
+ error_setg(errp, "failed to skip export name with wrong length");
nbd_send_opt_abort(ioc);
return -1;
}
- } else {
- error_setg(errp, "Unexpected reply type %" PRIx32 " expected %x",
- reply.type, NBD_REP_SERVER);
+ return 1;
+ }
+
+ assert(namelen < sizeof(name));
+ if (read_sync(ioc, name, namelen) != namelen) {
+ error_setg(errp, "failed to read export name");
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ name[namelen] = '\0';
+ len -= namelen;
+ if (drop_sync(ioc, len) != len) {
+ error_setg(errp, "failed to read export description");
nbd_send_opt_abort(ioc);
return -1;
}
+ if (!strcmp(name, want)) {
+ *match = true;
+ }
return 1;
}
+/* Return -1 on failure, 0 if wantname is an available export. */
static int nbd_receive_query_exports(QIOChannel *ioc,
const char *wantname,
Error **errp)
{
bool foundExport = false;
- TRACE("Querying export list");
+ TRACE("Querying export list for '%s'", wantname);
if (nbd_send_option_request(ioc, NBD_OPT_LIST, 0, NULL, errp) < 0) {
return -1;
}
TRACE("Reading available export names");
while (1) {
- char *name = NULL;
- int ret = nbd_receive_list(ioc, &name, errp);
+ int ret = nbd_receive_list(ioc, wantname, &foundExport, errp);
if (ret < 0) {
- g_free(name);
- name = NULL;
+ /* Server gave unexpected reply */
return -1;
+ } else if (ret == 0) {
+ /* Done iterating. */
+ if (!foundExport) {
+ error_setg(errp, "No export with name '%s' available",
+ wantname);
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
+ TRACE("Found desired export name '%s'", wantname);
+ return 0;
}
- if (ret == 0) {
- /* Server doesn't support export listing, so
- * we will just assume an export with our
- * wanted name exists */
- foundExport = true;
- break;
- }
- if (name == NULL) {
- TRACE("End of export name list");
- break;
- }
- if (g_str_equal(name, wantname)) {
- foundExport = true;
- TRACE("Found desired export name '%s'", name);
- } else {
- TRACE("Ignored export name '%s'", name);
- }
- g_free(name);
}
-
- if (!foundExport) {
- error_setg(errp, "No export with name '%s' available", wantname);
- nbd_send_opt_abort(ioc);
- return -1;
- }
-
- return 0;
}
static QIOChannel *nbd_receive_starttls(QIOChannel *ioc,
--
2.7.4
- [Qemu-devel] [PULL 08/27] hostmem-file: make option 'size' optional, (continued)
- [Qemu-devel] [PULL 08/27] hostmem-file: make option 'size' optional, Paolo Bonzini, 2016/10/31
- [Qemu-devel] [PULL 09/27] nbd: Add qemu-nbd -D for human-readable description, Paolo Bonzini, 2016/10/31
- [Qemu-devel] [PULL 07/27] exec.c: check memory backend file size with 'size' option, Paolo Bonzini, 2016/10/31
- [Qemu-devel] [PULL 11/27] nbd: Rename NBDRequest to NBDRequestData, Paolo Bonzini, 2016/10/31
- [Qemu-devel] [PULL 10/27] nbd: Treat flags vs. command type as separate fields, Paolo Bonzini, 2016/10/31
- [Qemu-devel] [PULL 12/27] nbd: Rename NbdClientSession to NBDClientSession, Paolo Bonzini, 2016/10/31
- [Qemu-devel] [PULL 14/27] nbd: Share common reply-sending code in server, Paolo Bonzini, 2016/10/31
- [Qemu-devel] [PULL 13/27] nbd: Rename struct nbd_request and nbd_reply, Paolo Bonzini, 2016/10/31
- [Qemu-devel] [PULL 15/27] nbd: Send message along with server NBD_REP_ERR errors, Paolo Bonzini, 2016/10/31
- [Qemu-devel] [PULL 17/27] nbd: Let server know when client gives up negotiation, Paolo Bonzini, 2016/10/31
- [Qemu-devel] [PULL 19/27] nbd: Less allocation during NBD_OPT_LIST,
Paolo Bonzini <=
- [Qemu-devel] [PULL 21/27] nbd: Refactor conversion to errno to silence checkpatch, Paolo Bonzini, 2016/10/31
- [Qemu-devel] [PULL 18/27] nbd: Let client skip portions of server reply, Paolo Bonzini, 2016/10/31
- [Qemu-devel] [PULL 20/27] nbd: Support shorter handshake, Paolo Bonzini, 2016/10/31
- [Qemu-devel] [PULL 22/27] nbd: Improve server handling of shutdown requests, Paolo Bonzini, 2016/10/31
- [Qemu-devel] [PULL 23/27] nbd: Implement NBD_CMD_WRITE_ZEROES on server, Paolo Bonzini, 2016/10/31
- [Qemu-devel] [PULL 16/27] nbd: Share common option-sending code in client, Paolo Bonzini, 2016/10/31
- [Qemu-devel] [PULL 24/27] nbd: Implement NBD_CMD_WRITE_ZEROES on client, Paolo Bonzini, 2016/10/31
- [Qemu-devel] [PULL 25/27] qemu-char: do not forward events through the mux until QEMU has started, Paolo Bonzini, 2016/10/31
- [Qemu-devel] [PULL 26/27] slirp: fix CharDriver breakage, Paolo Bonzini, 2016/10/31