diff --git a/blockdev-nbd.c b/blockdev-nbd.c index 1fcfdb0997..213f226ac1 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -187,8 +187,7 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name, writable = false; } - exp = nbd_export_new(bs, 0, len, name, NULL, bitmap, - writable ? 0 : NBD_FLAG_READ_ONLY, !writable, + exp = nbd_export_new(bs, 0, len, name, NULL, bitmap, !writable, !writable, NULL, false, on_eject_blk, errp); if (!exp) { return; diff --git a/include/block/nbd.h b/include/block/nbd.h index 991fd52a51..2c87b42dfd 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -326,7 +326,7 @@ typedef struct NBDClient NBDClient; NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, uint64_t size, const char *name, const char *desc, - const char *bitmap, uint16_t nbdflags, bool shared, + const char *bitmap, bool readonly, bool shared, void (*close)(NBDExport *), bool writethrough, BlockBackend *on_eject_blk, Error **errp); void nbd_export_close(NBDExport *exp); diff --git a/nbd/server.c b/nbd/server.c index 74d205812f..d5078f7468 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -419,14 +419,14 @@ static void nbd_check_meta_export(NBDClient *client) /* Send a reply to NBD_OPT_EXPORT_NAME. * Return -errno on error, 0 on success. */ -static int nbd_negotiate_handle_export_name(NBDClient *client, - uint16_t myflags, bool no_zeroes, +static int nbd_negotiate_handle_export_name(NBDClient *client, bool no_zeroes, Error **errp) { char name[NBD_MAX_NAME_SIZE + 1]; char buf[NBD_REPLY_EXPORT_NAME_SIZE] = ""; size_t len; int ret; + uint16_t myflags; /* Client sends: [20 .. xx] export name (length bytes) @@ -454,10 +454,13 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, return -EINVAL; } - trace_nbd_negotiate_new_style_size_flags(client->exp->size, - client->exp->nbdflags | myflags); + myflags = client->exp->nbdflags; + if (client->structured_reply) { + myflags |= NBD_FLAG_SEND_DF; + } + trace_nbd_negotiate_new_style_size_flags(client->exp->size, myflags); stq_be_p(buf, client->exp->size); - stw_be_p(buf + 8, client->exp->nbdflags | myflags); + stw_be_p(buf + 8, myflags); len = no_zeroes ? 10 : sizeof(buf); ret = nbd_write(client->ioc, buf, len, errp); if (ret < 0) { @@ -522,8 +525,7 @@ static int nbd_reject_length(NBDClient *client, bool fatal, Error **errp) /* Handle NBD_OPT_INFO and NBD_OPT_GO. * Return -errno on error, 0 if ready for next option, and 1 to move * into transmission phase. */ -static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags, - Error **errp) +static int nbd_negotiate_handle_info(NBDClient *client, Error **errp) { int rc; char name[NBD_MAX_NAME_SIZE + 1]; @@ -536,6 +538,7 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags, uint32_t sizes[3]; char buf[sizeof(uint64_t) + sizeof(uint16_t)]; uint32_t check_align = 0; + uint16_t myflags; /* Client sends: 4 bytes: L, name length (can be 0) @@ -633,10 +636,13 @@ static int nbd_negotiate_handle_info(NBDClient *client, uint16_t myflags, } /* Send NBD_INFO_EXPORT always */ - trace_nbd_negotiate_new_style_size_flags(exp->size, - exp->nbdflags | myflags); + myflags = exp->nbdflags; + if (client->structured_reply) { + myflags |= NBD_FLAG_SEND_DF; + } + trace_nbd_negotiate_new_style_size_flags(exp->size, myflags); stq_be_p(buf, exp->size); - stw_be_p(buf + 8, exp->nbdflags | myflags); + stw_be_p(buf + 8, myflags); rc = nbd_negotiate_send_info(client, NBD_INFO_EXPORT, sizeof(buf), buf, errp); if (rc < 0) { @@ -1033,8 +1039,7 @@ static int nbd_negotiate_meta_queries(NBDClient *client, * 1 if client sent NBD_OPT_ABORT, i.e. on valid disconnect, * errp is not set */ -static int nbd_negotiate_options(NBDClient *client, uint16_t myflags, - Error **errp) +static int nbd_negotiate_options(NBDClient *client, Error **errp) { uint32_t flags; bool fixedNewstyle = false; @@ -1168,13 +1173,12 @@ static int nbd_negotiate_options(NBDClient *client, uint16_t myflags, return 1; case NBD_OPT_EXPORT_NAME: - return nbd_negotiate_handle_export_name(client, - myflags, no_zeroes, + return nbd_negotiate_handle_export_name(client, no_zeroes, errp); case NBD_OPT_INFO: case NBD_OPT_GO: - ret = nbd_negotiate_handle_info(client, myflags, errp); + ret = nbd_negotiate_handle_info(client, errp); if (ret == 1) { assert(option == NBD_OPT_GO); return 0; @@ -1205,7 +1209,6 @@ static int nbd_negotiate_options(NBDClient *client, uint16_t myflags, } else { ret = nbd_negotiate_send_rep(client, NBD_REP_ACK, errp); client->structured_reply = true; - myflags |= NBD_FLAG_SEND_DF; } break; @@ -1228,8 +1231,7 @@ static int nbd_negotiate_options(NBDClient *client, uint16_t myflags, */ switch (option) { case NBD_OPT_EXPORT_NAME: - return nbd_negotiate_handle_export_name(client, - myflags, no_zeroes, + return nbd_negotiate_handle_export_name(client, no_zeroes, errp); default: @@ -1255,9 +1257,6 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp) { char buf[NBD_OLDSTYLE_NEGOTIATE_SIZE] = ""; int ret; - const uint16_t myflags = (NBD_FLAG_HAS_FLAGS | NBD_FLAG_SEND_TRIM | - NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA | - NBD_FLAG_SEND_WRITE_ZEROES | NBD_FLAG_SEND_CACHE); /* Old style negotiation header, no room for options [ 0 .. 7] passwd ("NBDMAGIC") @@ -1285,7 +1284,7 @@ static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp) error_prepend(errp, "write failed: "); return -EINVAL; } - ret = nbd_negotiate_options(client, myflags, errp); + ret = nbd_negotiate_options(client, errp); if (ret != 0) { if (ret < 0) { error_prepend(errp, "option negotiation failed: "); @@ -1457,7 +1456,7 @@ static void nbd_eject_notifier(Notifier *n, void *data) NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, uint64_t size, const char *name, const char *desc, - const char *bitmap, uint16_t nbdflags, bool shared, + const char *bitmap, bool readonly, bool shared, void (*close)(NBDExport *), bool writethrough, BlockBackend *on_eject_blk, Error **errp) { @@ -1481,10 +1480,8 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, /* Don't allow resize while the NBD server is running, otherwise we don't * care what happens with the node. */ perm = BLK_PERM_CONSISTENT_READ; - if ((nbdflags & NBD_FLAG_READ_ONLY) == 0) { + if (!readonly) { perm |= BLK_PERM_WRITE; - } else if (shared) { - nbdflags |= NBD_FLAG_CAN_MULTI_CONN; } blk = blk_new(bdrv_get_aio_context(bs), perm, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED | @@ -1503,7 +1500,16 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, exp->dev_offset = dev_offset; exp->name = g_strdup(name); exp->description = g_strdup(desc); - exp->nbdflags = nbdflags; + exp->nbdflags = (NBD_FLAG_HAS_FLAGS | NBD_FLAG_SEND_FLUSH | + NBD_FLAG_SEND_FUA | NBD_FLAG_SEND_CACHE); + if (readonly) { + exp->nbdflags |= NBD_FLAG_READ_ONLY; + if (shared) { + exp->nbdflags |= NBD_FLAG_CAN_MULTI_CONN; + } + } else { + exp->nbdflags |= NBD_FLAG_SEND_TRIM | NBD_FLAG_SEND_WRITE_ZEROES; + } assert(size <= INT64_MAX - dev_offset); exp->size = QEMU_ALIGN_DOWN(size, BDRV_SECTOR_SIZE); @@ -1528,7 +1534,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset, goto fail; } - if ((nbdflags & NBD_FLAG_READ_ONLY) && bdrv_is_writable(bs) && + if (readonly && bdrv_is_writable(bs) && bdrv_dirty_bitmap_enabled(bm)) { error_setg(errp, "Enabled bitmap '%s' incompatible with readonly export", diff --git a/qemu-nbd.c b/qemu-nbd.c index 2403ef3d0f..ae84115076 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -600,7 +600,7 @@ int main(int argc, char **argv) BlockBackend *blk; BlockDriverState *bs; uint64_t dev_offset = 0; - uint16_t nbdflags = 0; + bool readonly = false; bool disconnect = false; const char *bindto = NULL; const char *port = NULL; @@ -782,7 +782,7 @@ int main(int argc, char **argv) } /* fall through */ case 'r': - nbdflags |= NBD_FLAG_READ_ONLY; + readonly = true; flags &= ~BDRV_O_RDWR; break; case 'P': @@ -1173,7 +1173,7 @@ int main(int argc, char **argv) } export = nbd_export_new(bs, dev_offset, fd_size, export_name, - export_description, bitmap, nbdflags, shared > 1, + export_description, bitmap, readonly, shared > 1, nbd_export_closed, writethrough, NULL, &error_fatal); diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out index 2bca28ae72..2db0dc991a 100644 --- a/tests/qemu-iotests/223.out +++ b/tests/qemu-iotests/223.out @@ -40,7 +40,7 @@ exports available: 0 exports available: 2 export: 'n' size: 4194304 - flags: 0x5ef ( readonly flush fua trim zeroes df multi cache ) + flags: 0x58f ( readonly flush fua df multi cache ) min block: 1 opt block: 4096 max block: 33554432