nbd: Create struct for tracking export info

The NBD Protocol is introducing some additional information
about exports, such as minimum request size and alignment, as
well as an advertised maximum request size.  It will be easier
to feed this information back to the block layer if we gather
all the information into a struct, rather than adding yet more
pointer parameters during negotiation.

Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20170707203049.534-2-eblake@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Eric Blake 2017-07-07 15:30:41 -05:00 committed by Paolo Bonzini
parent 1221a47467
commit 004a89fce9
6 changed files with 47 additions and 45 deletions

View File

@ -242,7 +242,7 @@ int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset,
ssize_t ret; ssize_t ret;
if (flags & BDRV_REQ_FUA) { if (flags & BDRV_REQ_FUA) {
assert(client->nbdflags & NBD_FLAG_SEND_FUA); assert(client->info.flags & NBD_FLAG_SEND_FUA);
request.flags |= NBD_CMD_FLAG_FUA; request.flags |= NBD_CMD_FLAG_FUA;
} }
@ -270,12 +270,12 @@ int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
}; };
NBDReply reply; NBDReply reply;
if (!(client->nbdflags & NBD_FLAG_SEND_WRITE_ZEROES)) { if (!(client->info.flags & NBD_FLAG_SEND_WRITE_ZEROES)) {
return -ENOTSUP; return -ENOTSUP;
} }
if (flags & BDRV_REQ_FUA) { if (flags & BDRV_REQ_FUA) {
assert(client->nbdflags & NBD_FLAG_SEND_FUA); assert(client->info.flags & NBD_FLAG_SEND_FUA);
request.flags |= NBD_CMD_FLAG_FUA; request.flags |= NBD_CMD_FLAG_FUA;
} }
if (!(flags & BDRV_REQ_MAY_UNMAP)) { if (!(flags & BDRV_REQ_MAY_UNMAP)) {
@ -299,7 +299,7 @@ int nbd_client_co_flush(BlockDriverState *bs)
NBDReply reply; NBDReply reply;
ssize_t ret; ssize_t ret;
if (!(client->nbdflags & NBD_FLAG_SEND_FLUSH)) { if (!(client->info.flags & NBD_FLAG_SEND_FLUSH)) {
return 0; return 0;
} }
@ -327,7 +327,7 @@ int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
NBDReply reply; NBDReply reply;
ssize_t ret; ssize_t ret;
if (!(client->nbdflags & NBD_FLAG_SEND_TRIM)) { if (!(client->info.flags & NBD_FLAG_SEND_TRIM)) {
return 0; return 0;
} }
@ -385,19 +385,17 @@ int nbd_client_init(BlockDriverState *bs,
qio_channel_set_blocking(QIO_CHANNEL(sioc), true, NULL); qio_channel_set_blocking(QIO_CHANNEL(sioc), true, NULL);
ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), export, ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), export,
&client->nbdflags,
tlscreds, hostname, tlscreds, hostname,
&client->ioc, &client->ioc, &client->info, errp);
&client->size, errp);
if (ret < 0) { if (ret < 0) {
logout("Failed to negotiate with the NBD server\n"); logout("Failed to negotiate with the NBD server\n");
return ret; return ret;
} }
if (client->nbdflags & NBD_FLAG_SEND_FUA) { if (client->info.flags & NBD_FLAG_SEND_FUA) {
bs->supported_write_flags = BDRV_REQ_FUA; bs->supported_write_flags = BDRV_REQ_FUA;
bs->supported_zero_flags |= BDRV_REQ_FUA; bs->supported_zero_flags |= BDRV_REQ_FUA;
} }
if (client->nbdflags & NBD_FLAG_SEND_WRITE_ZEROES) { if (client->info.flags & NBD_FLAG_SEND_WRITE_ZEROES) {
bs->supported_zero_flags |= BDRV_REQ_MAY_UNMAP; bs->supported_zero_flags |= BDRV_REQ_MAY_UNMAP;
} }

View File

@ -20,8 +20,7 @@
typedef struct NBDClientSession { typedef struct NBDClientSession {
QIOChannelSocket *sioc; /* The master data channel */ QIOChannelSocket *sioc; /* The master data channel */
QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */ QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */
uint16_t nbdflags; NBDExportInfo info;
off_t size;
CoMutex send_mutex; CoMutex send_mutex;
CoQueue free_sema; CoQueue free_sema;

View File

@ -492,7 +492,7 @@ static int64_t nbd_getlength(BlockDriverState *bs)
{ {
BDRVNBDState *s = bs->opaque; BDRVNBDState *s = bs->opaque;
return s->client.size; return s->client.info.size;
} }
static void nbd_detach_aio_context(BlockDriverState *bs) static void nbd_detach_aio_context(BlockDriverState *bs)

View File

@ -123,13 +123,20 @@ enum {
* aren't overflowing some other buffer. */ * aren't overflowing some other buffer. */
#define NBD_MAX_NAME_SIZE 256 #define NBD_MAX_NAME_SIZE 256
/* Details collected by NBD_OPT_EXPORT_NAME and NBD_OPT_GO */
struct NBDExportInfo {
uint64_t size;
uint16_t flags;
};
typedef struct NBDExportInfo NBDExportInfo;
ssize_t nbd_rwv(QIOChannel *ioc, struct iovec *iov, size_t niov, size_t length, ssize_t nbd_rwv(QIOChannel *ioc, struct iovec *iov, size_t niov, size_t length,
bool do_read, Error **errp); bool do_read, Error **errp);
int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, int nbd_receive_negotiate(QIOChannel *ioc, const char *name,
QCryptoTLSCreds *tlscreds, const char *hostname, QCryptoTLSCreds *tlscreds, const char *hostname,
QIOChannel **outioc, QIOChannel **outioc, NBDExportInfo *info,
off_t *size, Error **errp); Error **errp);
int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size, int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info,
Error **errp); Error **errp);
ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request); ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request);
ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp); ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply, Error **errp);

View File

@ -425,13 +425,13 @@ static QIOChannel *nbd_receive_starttls(QIOChannel *ioc,
} }
int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags, int nbd_receive_negotiate(QIOChannel *ioc, const char *name,
QCryptoTLSCreds *tlscreds, const char *hostname, QCryptoTLSCreds *tlscreds, const char *hostname,
QIOChannel **outioc, QIOChannel **outioc, NBDExportInfo *info,
off_t *size, Error **errp) Error **errp)
{ {
char buf[256]; char buf[256];
uint64_t magic, s; uint64_t magic;
int rc; int rc;
bool zeroes = true; bool zeroes = true;
@ -532,17 +532,17 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
} }
/* Read the response */ /* Read the response */
if (nbd_read(ioc, &s, sizeof(s), errp) < 0) { if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) {
error_prepend(errp, "Failed to read export length"); error_prepend(errp, "Failed to read export length");
goto fail; goto fail;
} }
*size = be64_to_cpu(s); be64_to_cpus(&info->size);
if (nbd_read(ioc, flags, sizeof(*flags), errp) < 0) { if (nbd_read(ioc, &info->flags, sizeof(info->flags), errp) < 0) {
error_prepend(errp, "Failed to read export flags"); error_prepend(errp, "Failed to read export flags");
goto fail; goto fail;
} }
be16_to_cpus(flags); be16_to_cpus(&info->flags);
} else if (magic == NBD_CLIENT_MAGIC) { } else if (magic == NBD_CLIENT_MAGIC) {
uint32_t oldflags; uint32_t oldflags;
@ -555,11 +555,11 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
goto fail; goto fail;
} }
if (nbd_read(ioc, &s, sizeof(s), errp) < 0) { if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) {
error_prepend(errp, "Failed to read export length"); error_prepend(errp, "Failed to read export length");
goto fail; goto fail;
} }
*size = be64_to_cpu(s); be64_to_cpus(&info->size);
if (nbd_read(ioc, &oldflags, sizeof(oldflags), errp) < 0) { if (nbd_read(ioc, &oldflags, sizeof(oldflags), errp) < 0) {
error_prepend(errp, "Failed to read export flags"); error_prepend(errp, "Failed to read export flags");
@ -570,13 +570,13 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
error_setg(errp, "Unexpected export flags %0x" PRIx32, oldflags); error_setg(errp, "Unexpected export flags %0x" PRIx32, oldflags);
goto fail; goto fail;
} }
*flags = oldflags; info->flags = oldflags;
} else { } else {
error_setg(errp, "Bad magic received"); error_setg(errp, "Bad magic received");
goto fail; goto fail;
} }
trace_nbd_receive_negotiate_size_flags(*size, *flags); trace_nbd_receive_negotiate_size_flags(info->size, info->flags);
if (zeroes && nbd_drop(ioc, 124, errp) < 0) { if (zeroes && nbd_drop(ioc, 124, errp) < 0) {
error_prepend(errp, "Failed to read reserved block"); error_prepend(errp, "Failed to read reserved block");
goto fail; goto fail;
@ -588,13 +588,13 @@ fail:
} }
#ifdef __linux__ #ifdef __linux__
int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size, int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info,
Error **errp) Error **errp)
{ {
unsigned long sectors = size / BDRV_SECTOR_SIZE; unsigned long sectors = info->size / BDRV_SECTOR_SIZE;
if (size / BDRV_SECTOR_SIZE != sectors) { if (info->size / BDRV_SECTOR_SIZE != sectors) {
error_setg(errp, "Export size %lld too large for 32-bit kernel", error_setg(errp, "Export size %" PRIu64 " too large for 32-bit kernel",
(long long) size); info->size);
return -E2BIG; return -E2BIG;
} }
@ -615,8 +615,8 @@ int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size,
} }
trace_nbd_init_set_size(sectors); trace_nbd_init_set_size(sectors);
if (size % BDRV_SECTOR_SIZE) { if (info->size % BDRV_SECTOR_SIZE) {
trace_nbd_init_trailing_bytes(size % BDRV_SECTOR_SIZE); trace_nbd_init_trailing_bytes(info->size % BDRV_SECTOR_SIZE);
} }
if (ioctl(fd, NBD_SET_SIZE_BLOCKS, sectors) < 0) { if (ioctl(fd, NBD_SET_SIZE_BLOCKS, sectors) < 0) {
@ -625,9 +625,9 @@ int nbd_init(int fd, QIOChannelSocket *sioc, uint16_t flags, off_t size,
return -serrno; return -serrno;
} }
if (ioctl(fd, NBD_SET_FLAGS, (unsigned long) flags) < 0) { if (ioctl(fd, NBD_SET_FLAGS, (unsigned long) info->flags) < 0) {
if (errno == ENOTTY) { if (errno == ENOTTY) {
int read_only = (flags & NBD_FLAG_READ_ONLY) != 0; int read_only = (info->flags & NBD_FLAG_READ_ONLY) != 0;
trace_nbd_init_set_readonly(); trace_nbd_init_set_readonly();
if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) { if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) {
@ -685,7 +685,7 @@ int nbd_disconnect(int fd)
} }
#else #else
int nbd_init(int fd, QIOChannelSocket *ioc, uint16_t flags, off_t size, int nbd_init(int fd, QIOChannelSocket *ioc, NBDExportInfo *info,
Error **errp) Error **errp)
{ {
error_setg(errp, "nbd_init is only supported on Linux"); error_setg(errp, "nbd_init is only supported on Linux");

View File

@ -255,8 +255,7 @@ static void *show_parts(void *arg)
static void *nbd_client_thread(void *arg) static void *nbd_client_thread(void *arg)
{ {
char *device = arg; char *device = arg;
off_t size; NBDExportInfo info;
uint16_t nbdflags;
QIOChannelSocket *sioc; QIOChannelSocket *sioc;
int fd; int fd;
int ret; int ret;
@ -271,9 +270,8 @@ static void *nbd_client_thread(void *arg)
goto out; goto out;
} }
ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), NULL, &nbdflags, ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), NULL,
NULL, NULL, NULL, NULL, NULL, NULL, &info, &local_error);
&size, &local_error);
if (ret < 0) { if (ret < 0) {
if (local_error) { if (local_error) {
error_report_err(local_error); error_report_err(local_error);
@ -288,7 +286,7 @@ static void *nbd_client_thread(void *arg)
goto out_socket; goto out_socket;
} }
ret = nbd_init(fd, sioc, nbdflags, size, &local_error); ret = nbd_init(fd, sioc, &info, &local_error);
if (ret < 0) { if (ret < 0) {
error_report_err(local_error); error_report_err(local_error);
goto out_fd; goto out_fd;