diff --git a/block/nbd-client.c b/block/nbd-client.c index 40b28ab00b..8ca503015c 100644 --- a/block/nbd-client.c +++ b/block/nbd-client.c @@ -1,6 +1,7 @@ /* * QEMU Block driver for NBD * + * Copyright (C) 2016 Red Hat, Inc. * Copyright (C) 2008 Bull S.A.S. * Author: Laurent Vivier * @@ -258,7 +259,7 @@ int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset, if (flags & BDRV_REQ_FUA) { assert(client->nbdflags & NBD_FLAG_SEND_FUA); - request.type |= NBD_CMD_FLAG_FUA; + request.flags |= NBD_CMD_FLAG_FUA; } assert(bytes <= NBD_MAX_BUFFER_SIZE); @@ -343,11 +344,7 @@ void nbd_client_attach_aio_context(BlockDriverState *bs, void nbd_client_close(BlockDriverState *bs) { NbdClientSession *client = nbd_get_client_session(bs); - struct nbd_request request = { - .type = NBD_CMD_DISC, - .from = 0, - .len = 0 - }; + struct nbd_request request = { .type = NBD_CMD_DISC }; if (client->ioc == NULL) { return; diff --git a/include/block/nbd.h b/include/block/nbd.h index fd58390d5d..5fe2670fdb 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2016 Red Hat, Inc. * Copyright (C) 2005 Anthony Liguori * * Network Block Device @@ -32,7 +33,8 @@ struct nbd_request { uint64_t handle; uint64_t from; uint32_t len; - uint32_t type; + uint16_t flags; + uint16_t type; }; struct nbd_reply { @@ -40,6 +42,8 @@ struct nbd_reply { uint32_t error; }; +/* Transmission (export) flags: sent from server to client during handshake, + but describe what will happen during transmission */ #define NBD_FLAG_HAS_FLAGS (1 << 0) /* Flags are there */ #define NBD_FLAG_READ_ONLY (1 << 1) /* Device is read-only */ #define NBD_FLAG_SEND_FLUSH (1 << 2) /* Send FLUSH */ @@ -47,10 +51,12 @@ struct nbd_reply { #define NBD_FLAG_ROTATIONAL (1 << 4) /* Use elevator algorithm - rotational media */ #define NBD_FLAG_SEND_TRIM (1 << 5) /* Send TRIM (discard) */ -/* New-style global flags. */ +/* New-style handshake (global) flags, sent from server to client, and + control what will happen during handshake phase. */ #define NBD_FLAG_FIXED_NEWSTYLE (1 << 0) /* Fixed newstyle protocol. */ -/* New-style client flags. */ +/* New-style client flags, sent from client to server to control what happens + during handshake phase. */ #define NBD_FLAG_C_FIXED_NEWSTYLE (1 << 0) /* Fixed newstyle protocol. */ /* Reply types. */ @@ -61,10 +67,10 @@ struct nbd_reply { #define NBD_REP_ERR_INVALID ((UINT32_C(1) << 31) | 3) /* Invalid length. */ #define NBD_REP_ERR_TLS_REQD ((UINT32_C(1) << 31) | 5) /* TLS required */ +/* Request flags, sent from client to server during transmission phase */ +#define NBD_CMD_FLAG_FUA (1 << 0) -#define NBD_CMD_MASK_COMMAND 0x0000ffff -#define NBD_CMD_FLAG_FUA (1 << 16) - +/* Supported request types */ enum { NBD_CMD_READ = 0, NBD_CMD_WRITE = 1, diff --git a/nbd/client.c b/nbd/client.c index f6db8369b3..4620e8dcba 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2016 Red Hat, Inc. * Copyright (C) 2005 Anthony Liguori * * Network Block Device Client Side @@ -714,11 +715,13 @@ ssize_t nbd_send_request(QIOChannel *ioc, struct nbd_request *request) TRACE("Sending request to server: " "{ .from = %" PRIu64", .len = %" PRIu32 ", .handle = %" PRIu64 - ", .type=%" PRIu32 " }", - request->from, request->len, request->handle, request->type); + ", .flags = %" PRIx16 ", .type = %" PRIu16 " }", + request->from, request->len, request->handle, + request->flags, request->type); stl_be_p(buf, NBD_REQUEST_MAGIC); - stl_be_p(buf + 4, request->type); + stw_be_p(buf + 4, request->flags); + stw_be_p(buf + 6, request->type); stq_be_p(buf + 8, request->handle); stq_be_p(buf + 16, request->from); stl_be_p(buf + 24, request->len); diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h index 7e78064021..99e51571a2 100644 --- a/nbd/nbd-internal.h +++ b/nbd/nbd-internal.h @@ -53,10 +53,10 @@ /* This is all part of the "official" NBD API. * * The most up-to-date documentation is available at: - * https://github.com/yoe/nbd/blob/master/doc/proto.txt + * https://github.com/yoe/nbd/blob/master/doc/proto.md */ -#define NBD_REQUEST_SIZE (4 + 4 + 8 + 8 + 4) +#define NBD_REQUEST_SIZE (4 + 2 + 2 + 8 + 8 + 4) #define NBD_REPLY_SIZE (4 + 4 + 8) #define NBD_REQUEST_MAGIC 0x25609513 #define NBD_REPLY_MAGIC 0x67446698 diff --git a/nbd/server.c b/nbd/server.c index ac42391b45..38a0fef4d9 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2016 Red Hat, Inc. * Copyright (C) 2005 Anthony Liguori * * Network Block Device Server Side @@ -652,21 +653,23 @@ static ssize_t nbd_receive_request(QIOChannel *ioc, struct nbd_request *request) /* Request [ 0 .. 3] magic (NBD_REQUEST_MAGIC) - [ 4 .. 7] type (0 == READ, 1 == WRITE) + [ 4 .. 5] flags (NBD_CMD_FLAG_FUA, ...) + [ 6 .. 7] type (NBD_CMD_READ, ...) [ 8 .. 15] handle [16 .. 23] from [24 .. 27] len */ magic = ldl_be_p(buf); - request->type = ldl_be_p(buf + 4); + request->flags = lduw_be_p(buf + 4); + request->type = lduw_be_p(buf + 6); request->handle = ldq_be_p(buf + 8); request->from = ldq_be_p(buf + 16); request->len = ldl_be_p(buf + 24); - TRACE("Got request: { magic = 0x%" PRIx32 ", .type = %" PRIx32 - ", from = %" PRIu64 " , len = %" PRIu32 " }", - magic, request->type, request->from, request->len); + TRACE("Got request: { magic = 0x%" PRIx32 ", .flags = %" PRIx16 + ", .type = %" PRIx16 ", from = %" PRIu64 ", len = %" PRIu32 " }", + magic, request->flags, request->type, request->from, request->len); if (magic != NBD_REQUEST_MAGIC) { LOG("invalid magic (got 0x%" PRIx32 ")", magic); @@ -1013,7 +1016,6 @@ static ssize_t nbd_co_receive_request(NBDRequest *req, struct nbd_request *request) { NBDClient *client = req->client; - uint32_t command; ssize_t rc; g_assert(qemu_in_coroutine()); @@ -1030,13 +1032,12 @@ static ssize_t nbd_co_receive_request(NBDRequest *req, TRACE("Decoding type"); - command = request->type & NBD_CMD_MASK_COMMAND; - if (command != NBD_CMD_WRITE) { + if (request->type != NBD_CMD_WRITE) { /* No payload, we are ready to read the next request. */ req->complete = true; } - if (command == NBD_CMD_DISC) { + if (request->type == NBD_CMD_DISC) { /* Special case: we're going to disconnect without a reply, * whether or not flags, from, or len are bogus */ TRACE("Request type is DISCONNECT"); @@ -1053,7 +1054,7 @@ static ssize_t nbd_co_receive_request(NBDRequest *req, goto out; } - if (command == NBD_CMD_READ || command == NBD_CMD_WRITE) { + if (request->type == NBD_CMD_READ || request->type == 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); @@ -1067,7 +1068,7 @@ static ssize_t nbd_co_receive_request(NBDRequest *req, goto out; } } - if (command == NBD_CMD_WRITE) { + if (request->type == NBD_CMD_WRITE) { TRACE("Reading %" PRIu32 " byte(s)", request->len); if (read_sync(client->ioc, req->data, request->len) != request->len) { @@ -1083,12 +1084,11 @@ static ssize_t nbd_co_receive_request(NBDRequest *req, LOG("operation past EOF; From: %" PRIu64 ", Len: %" PRIu32 ", Size: %" PRIu64, request->from, request->len, (uint64_t)client->exp->size); - rc = command == NBD_CMD_WRITE ? -ENOSPC : -EINVAL; + rc = request->type == NBD_CMD_WRITE ? -ENOSPC : -EINVAL; goto out; } - if (request->type & ~NBD_CMD_MASK_COMMAND & ~NBD_CMD_FLAG_FUA) { - LOG("unsupported flags (got 0x%x)", - request->type & ~NBD_CMD_MASK_COMMAND); + if (request->flags & ~NBD_CMD_FLAG_FUA) { + LOG("unsupported flags (got 0x%x)", request->flags); rc = -EINVAL; goto out; } @@ -1110,7 +1110,6 @@ static void nbd_trip(void *opaque) struct nbd_request request; struct nbd_reply reply; ssize_t ret; - uint32_t command; int flags; TRACE("Reading request."); @@ -1134,7 +1133,6 @@ static void nbd_trip(void *opaque) reply.error = -ret; goto error_reply; } - command = request.type & NBD_CMD_MASK_COMMAND; if (client->closing) { /* @@ -1144,11 +1142,12 @@ static void nbd_trip(void *opaque) goto done; } - switch (command) { + switch (request.type) { case NBD_CMD_READ: TRACE("Request type is READ"); - if (request.type & NBD_CMD_FLAG_FUA) { + /* XXX: NBD Protocol only documents use of FUA with WRITE */ + if (request.flags & NBD_CMD_FLAG_FUA) { ret = blk_co_flush(exp->blk); if (ret < 0) { LOG("flush failed"); @@ -1181,7 +1180,7 @@ static void nbd_trip(void *opaque) TRACE("Writing to device"); flags = 0; - if (request.type & NBD_CMD_FLAG_FUA) { + if (request.flags & NBD_CMD_FLAG_FUA) { flags |= BDRV_REQ_FUA; } ret = blk_pwrite(exp->blk, request.from + exp->dev_offset,