summaryrefslogtreecommitdiffstats
path: root/nbd/client.c
diff options
context:
space:
mode:
authorPeter Maydell2016-04-08 11:25:22 +0200
committerPeter Maydell2016-04-08 11:25:22 +0200
commit28ee01269e910c68fb75ff780c9d84e0c34e0d66 (patch)
treec875d6ec0887fba0e4d70e2d3d3b876331a97d7f /nbd/client.c
parentMerge remote-tracking branch 'remotes/mdroth/tags/qga-pull-2016-04-07-tag' in... (diff)
parenttarget-i386: check for PKU even for non-writable pages (diff)
downloadqemu-28ee01269e910c68fb75ff780c9d84e0c34e0d66.tar.gz
qemu-28ee01269e910c68fb75ff780c9d84e0c34e0d66.tar.xz
qemu-28ee01269e910c68fb75ff780c9d84e0c34e0d66.zip
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
* NBD fixes from Alex and Eric * Debug code bitrot from Emilio * HPET fix from Bill * ps2kbd fix from Hervé * PKU fix from myself * Coverity fixes from Gonglei * More memory.txt update from Jiangang * .gitignore maintenance from Changlong # gpg: Signature made Thu 07 Apr 2016 23:08:12 BST using RSA key ID 78C7AE83 # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" * remotes/bonzini/tags/for-upstream: target-i386: check for PKU even for non-writable pages tests: ignore test-logging translate-all: add missing fold of tb_ctx into tcg_ctx hostmem-file: fix memory leak spapr: fix possible Negative array index read nbd: do not hang nbd_wr_syncv if outside a coroutine and no available data nbd: Don't kill server when client requests unknown option nbd: Fix NBD unsupported options qemu-nbd: Document -x option nbd: Improve debug traces on little-endian nbd: Avoid bitrot in TRACE() usage nbd: Return correct error for write to read-only export docs: fix typo in memory.txt hw/timer: Revert "hpet: inverse polarity when pin above ISA_NUM_IRQS" ps2kbd: default to scancode_set 2, as with KBD_CMD_RESET Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'nbd/client.c')
-rw-r--r--nbd/client.c63
1 files changed, 49 insertions, 14 deletions
diff --git a/nbd/client.c b/nbd/client.c
index d9b7a9b07e..6777e589d1 100644
--- a/nbd/client.c
+++ b/nbd/client.c
@@ -73,16 +73,46 @@ static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports);
*/
-static int nbd_handle_reply_err(uint32_t opt, uint32_t type, Error **errp)
+/* If type represents success, return 1 without further action.
+ * If type represents an error reply, consume the rest of the packet on ioc.
+ * Then return 0 for unsupported (so the client can fall back to
+ * other approaches), or -1 with errp set for other errors.
+ */
+static int nbd_handle_reply_err(QIOChannel *ioc, uint32_t opt, uint32_t type,
+ Error **errp)
{
+ uint32_t len;
+ char *msg = NULL;
+ int result = -1;
+
if (!(type & (1 << 31))) {
- return 0;
+ return 1;
+ }
+
+ if (read_sync(ioc, &len, sizeof(len)) != sizeof(len)) {
+ error_setg(errp, "failed to read option length");
+ return -1;
+ }
+ len = be32_to_cpu(len);
+ if (len) {
+ if (len > NBD_MAX_BUFFER_SIZE) {
+ error_setg(errp, "server's error message is too long");
+ goto cleanup;
+ }
+ msg = g_malloc(len + 1);
+ if (read_sync(ioc, msg, len) != len) {
+ error_setg(errp, "failed to read option error message");
+ goto cleanup;
+ }
+ msg[len] = '\0';
}
switch (type) {
case NBD_REP_ERR_UNSUP:
- error_setg(errp, "Unsupported option type %x", opt);
- break;
+ TRACE("server doesn't understand request %d, attempting fallback",
+ opt);
+ result = 0;
+ goto cleanup;
case NBD_REP_ERR_POLICY:
error_setg(errp, "Denied by server for option %x", opt);
@@ -101,7 +131,13 @@ static int nbd_handle_reply_err(uint32_t opt, uint32_t type, Error **errp)
break;
}
- return -1;
+ if (msg) {
+ error_append_hint(errp, "%s\n", msg);
+ }
+
+ cleanup:
+ g_free(msg);
+ return result;
}
static int nbd_receive_list(QIOChannel *ioc, char **name, Error **errp)
@@ -111,6 +147,7 @@ static int nbd_receive_list(QIOChannel *ioc, char **name, Error **errp)
uint32_t type;
uint32_t len;
uint32_t namelen;
+ int error;
*name = NULL;
if (read_sync(ioc, &magic, sizeof(magic)) != sizeof(magic)) {
@@ -138,11 +175,9 @@ static int nbd_receive_list(QIOChannel *ioc, char **name, Error **errp)
return -1;
}
type = be32_to_cpu(type);
- if (type == NBD_REP_ERR_UNSUP) {
- return 0;
- }
- if (nbd_handle_reply_err(opt, type, errp) < 0) {
- return -1;
+ error = nbd_handle_reply_err(ioc, opt, type, errp);
+ if (error <= 0) {
+ return error;
}
if (read_sync(ioc, &len, sizeof(len)) != sizeof(len)) {
@@ -628,16 +663,16 @@ ssize_t nbd_send_request(QIOChannel *ioc, struct nbd_request *request)
uint8_t buf[NBD_REQUEST_SIZE];
ssize_t ret;
+ TRACE("Sending request to server: "
+ "{ .from = %" PRIu64", .len = %u, .handle = %" PRIu64", .type=%i}",
+ request->from, request->len, request->handle, request->type);
+
cpu_to_be32w((uint32_t*)buf, NBD_REQUEST_MAGIC);
cpu_to_be32w((uint32_t*)(buf + 4), request->type);
cpu_to_be64w((uint64_t*)(buf + 8), request->handle);
cpu_to_be64w((uint64_t*)(buf + 16), request->from);
cpu_to_be32w((uint32_t*)(buf + 24), request->len);
- TRACE("Sending request to server: "
- "{ .from = %" PRIu64", .len = %u, .handle = %" PRIu64", .type=%i}",
- request->from, request->len, request->handle, request->type);
-
ret = write_sync(ioc, buf, sizeof(buf));
if (ret < 0) {
return ret;