|
@@ -105,11 +105,13 @@ struct NBDExport {
|
|
|
|
|
|
static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports);
|
|
static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports);
|
|
|
|
|
|
-/* NBDExportMetaContexts represents a list of contexts to be exported,
|
|
|
|
|
|
+/*
|
|
|
|
+ * NBDMetaContexts represents a list of meta contexts in use,
|
|
* as selected by NBD_OPT_SET_META_CONTEXT. Also used for
|
|
* as selected by NBD_OPT_SET_META_CONTEXT. Also used for
|
|
- * NBD_OPT_LIST_META_CONTEXT. */
|
|
|
|
-typedef struct NBDExportMetaContexts {
|
|
|
|
- NBDExport *exp;
|
|
|
|
|
|
+ * NBD_OPT_LIST_META_CONTEXT.
|
|
|
|
+ */
|
|
|
|
+struct NBDMetaContexts {
|
|
|
|
+ const NBDExport *exp; /* associated export */
|
|
size_t count; /* number of negotiated contexts */
|
|
size_t count; /* number of negotiated contexts */
|
|
bool base_allocation; /* export base:allocation context (block status) */
|
|
bool base_allocation; /* export base:allocation context (block status) */
|
|
bool allocation_depth; /* export qemu:allocation-depth */
|
|
bool allocation_depth; /* export qemu:allocation-depth */
|
|
@@ -117,7 +119,7 @@ typedef struct NBDExportMetaContexts {
|
|
* export qemu:dirty-bitmap:<export bitmap name>,
|
|
* export qemu:dirty-bitmap:<export bitmap name>,
|
|
* sized by exp->nr_export_bitmaps
|
|
* sized by exp->nr_export_bitmaps
|
|
*/
|
|
*/
|
|
-} NBDExportMetaContexts;
|
|
|
|
|
|
+};
|
|
|
|
|
|
struct NBDClient {
|
|
struct NBDClient {
|
|
int refcount;
|
|
int refcount;
|
|
@@ -144,7 +146,7 @@ struct NBDClient {
|
|
uint32_t check_align; /* If non-zero, check for aligned client requests */
|
|
uint32_t check_align; /* If non-zero, check for aligned client requests */
|
|
|
|
|
|
NBDMode mode;
|
|
NBDMode mode;
|
|
- NBDExportMetaContexts export_meta;
|
|
|
|
|
|
+ NBDMetaContexts contexts; /* Negotiated meta contexts */
|
|
|
|
|
|
uint32_t opt; /* Current option being negotiated */
|
|
uint32_t opt; /* Current option being negotiated */
|
|
uint32_t optlen; /* remaining length of data in ioc for the option being
|
|
uint32_t optlen; /* remaining length of data in ioc for the option being
|
|
@@ -455,10 +457,10 @@ static int nbd_negotiate_handle_list(NBDClient *client, Error **errp)
|
|
return nbd_negotiate_send_rep(client, NBD_REP_ACK, errp);
|
|
return nbd_negotiate_send_rep(client, NBD_REP_ACK, errp);
|
|
}
|
|
}
|
|
|
|
|
|
-static void nbd_check_meta_export(NBDClient *client)
|
|
|
|
|
|
+static void nbd_check_meta_export(NBDClient *client, NBDExport *exp)
|
|
{
|
|
{
|
|
- if (client->exp != client->export_meta.exp) {
|
|
|
|
- client->export_meta.count = 0;
|
|
|
|
|
|
+ if (exp != client->contexts.exp) {
|
|
|
|
+ client->contexts.count = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -504,6 +506,7 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, bool no_zeroes,
|
|
error_setg(errp, "export not found");
|
|
error_setg(errp, "export not found");
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
+ nbd_check_meta_export(client, client->exp);
|
|
|
|
|
|
myflags = client->exp->nbdflags;
|
|
myflags = client->exp->nbdflags;
|
|
if (client->mode >= NBD_MODE_STRUCTURED) {
|
|
if (client->mode >= NBD_MODE_STRUCTURED) {
|
|
@@ -521,7 +524,6 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, bool no_zeroes,
|
|
|
|
|
|
QTAILQ_INSERT_TAIL(&client->exp->clients, client, next);
|
|
QTAILQ_INSERT_TAIL(&client->exp->clients, client, next);
|
|
blk_exp_ref(&client->exp->common);
|
|
blk_exp_ref(&client->exp->common);
|
|
- nbd_check_meta_export(client);
|
|
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -641,6 +643,9 @@ static int nbd_negotiate_handle_info(NBDClient *client, Error **errp)
|
|
errp, "export '%s' not present",
|
|
errp, "export '%s' not present",
|
|
sane_name);
|
|
sane_name);
|
|
}
|
|
}
|
|
|
|
+ if (client->opt == NBD_OPT_GO) {
|
|
|
|
+ nbd_check_meta_export(client, exp);
|
|
|
|
+ }
|
|
|
|
|
|
/* Don't bother sending NBD_INFO_NAME unless client requested it */
|
|
/* Don't bother sending NBD_INFO_NAME unless client requested it */
|
|
if (sendname) {
|
|
if (sendname) {
|
|
@@ -729,7 +734,6 @@ static int nbd_negotiate_handle_info(NBDClient *client, Error **errp)
|
|
client->check_align = check_align;
|
|
client->check_align = check_align;
|
|
QTAILQ_INSERT_TAIL(&client->exp->clients, client, next);
|
|
QTAILQ_INSERT_TAIL(&client->exp->clients, client, next);
|
|
blk_exp_ref(&client->exp->common);
|
|
blk_exp_ref(&client->exp->common);
|
|
- nbd_check_meta_export(client);
|
|
|
|
rc = 1;
|
|
rc = 1;
|
|
}
|
|
}
|
|
return rc;
|
|
return rc;
|
|
@@ -852,7 +856,7 @@ static bool nbd_strshift(const char **str, const char *prefix)
|
|
* Handle queries to 'base' namespace. For now, only the base:allocation
|
|
* Handle queries to 'base' namespace. For now, only the base:allocation
|
|
* context is available. Return true if @query has been handled.
|
|
* context is available. Return true if @query has been handled.
|
|
*/
|
|
*/
|
|
-static bool nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta,
|
|
|
|
|
|
+static bool nbd_meta_base_query(NBDClient *client, NBDMetaContexts *meta,
|
|
const char *query)
|
|
const char *query)
|
|
{
|
|
{
|
|
if (!nbd_strshift(&query, "base:")) {
|
|
if (!nbd_strshift(&query, "base:")) {
|
|
@@ -872,7 +876,7 @@ static bool nbd_meta_base_query(NBDClient *client, NBDExportMetaContexts *meta,
|
|
* and qemu:allocation-depth contexts are available. Return true if @query
|
|
* and qemu:allocation-depth contexts are available. Return true if @query
|
|
* has been handled.
|
|
* has been handled.
|
|
*/
|
|
*/
|
|
-static bool nbd_meta_qemu_query(NBDClient *client, NBDExportMetaContexts *meta,
|
|
|
|
|
|
+static bool nbd_meta_qemu_query(NBDClient *client, NBDMetaContexts *meta,
|
|
const char *query)
|
|
const char *query)
|
|
{
|
|
{
|
|
size_t i;
|
|
size_t i;
|
|
@@ -938,7 +942,7 @@ static bool nbd_meta_qemu_query(NBDClient *client, NBDExportMetaContexts *meta,
|
|
* Return -errno on I/O error, 0 if option was completely handled by
|
|
* Return -errno on I/O error, 0 if option was completely handled by
|
|
* sending a reply about inconsistent lengths, or 1 on success. */
|
|
* sending a reply about inconsistent lengths, or 1 on success. */
|
|
static int nbd_negotiate_meta_query(NBDClient *client,
|
|
static int nbd_negotiate_meta_query(NBDClient *client,
|
|
- NBDExportMetaContexts *meta, Error **errp)
|
|
|
|
|
|
+ NBDMetaContexts *meta, Error **errp)
|
|
{
|
|
{
|
|
int ret;
|
|
int ret;
|
|
g_autofree char *query = NULL;
|
|
g_autofree char *query = NULL;
|
|
@@ -977,14 +981,14 @@ static int nbd_negotiate_meta_query(NBDClient *client,
|
|
* Handle NBD_OPT_LIST_META_CONTEXT and NBD_OPT_SET_META_CONTEXT
|
|
* Handle NBD_OPT_LIST_META_CONTEXT and NBD_OPT_SET_META_CONTEXT
|
|
*
|
|
*
|
|
* Return -errno on I/O error, or 0 if option was completely handled. */
|
|
* Return -errno on I/O error, or 0 if option was completely handled. */
|
|
-static int nbd_negotiate_meta_queries(NBDClient *client,
|
|
|
|
- NBDExportMetaContexts *meta, Error **errp)
|
|
|
|
|
|
+static int nbd_negotiate_meta_queries(NBDClient *client, Error **errp)
|
|
{
|
|
{
|
|
int ret;
|
|
int ret;
|
|
g_autofree char *export_name = NULL;
|
|
g_autofree char *export_name = NULL;
|
|
/* Mark unused to work around https://bugs.llvm.org/show_bug.cgi?id=3888 */
|
|
/* Mark unused to work around https://bugs.llvm.org/show_bug.cgi?id=3888 */
|
|
g_autofree G_GNUC_UNUSED bool *bitmaps = NULL;
|
|
g_autofree G_GNUC_UNUSED bool *bitmaps = NULL;
|
|
- NBDExportMetaContexts local_meta = {0};
|
|
|
|
|
|
+ NBDMetaContexts local_meta = {0};
|
|
|
|
+ NBDMetaContexts *meta;
|
|
uint32_t nb_queries;
|
|
uint32_t nb_queries;
|
|
size_t i;
|
|
size_t i;
|
|
size_t count = 0;
|
|
size_t count = 0;
|
|
@@ -1000,6 +1004,8 @@ static int nbd_negotiate_meta_queries(NBDClient *client,
|
|
if (client->opt == NBD_OPT_LIST_META_CONTEXT) {
|
|
if (client->opt == NBD_OPT_LIST_META_CONTEXT) {
|
|
/* Only change the caller's meta on SET. */
|
|
/* Only change the caller's meta on SET. */
|
|
meta = &local_meta;
|
|
meta = &local_meta;
|
|
|
|
+ } else {
|
|
|
|
+ meta = &client->contexts;
|
|
}
|
|
}
|
|
|
|
|
|
g_free(meta->bitmaps);
|
|
g_free(meta->bitmaps);
|
|
@@ -1284,8 +1290,7 @@ static int nbd_negotiate_options(NBDClient *client, Error **errp)
|
|
|
|
|
|
case NBD_OPT_LIST_META_CONTEXT:
|
|
case NBD_OPT_LIST_META_CONTEXT:
|
|
case NBD_OPT_SET_META_CONTEXT:
|
|
case NBD_OPT_SET_META_CONTEXT:
|
|
- ret = nbd_negotiate_meta_queries(client, &client->export_meta,
|
|
|
|
- errp);
|
|
|
|
|
|
+ ret = nbd_negotiate_meta_queries(client, errp);
|
|
break;
|
|
break;
|
|
|
|
|
|
case NBD_OPT_EXTENDED_HEADERS:
|
|
case NBD_OPT_EXTENDED_HEADERS:
|
|
@@ -1512,7 +1517,7 @@ void nbd_client_put(NBDClient *client)
|
|
QTAILQ_REMOVE(&client->exp->clients, client, next);
|
|
QTAILQ_REMOVE(&client->exp->clients, client, next);
|
|
blk_exp_unref(&client->exp->common);
|
|
blk_exp_unref(&client->exp->common);
|
|
}
|
|
}
|
|
- g_free(client->export_meta.bitmaps);
|
|
|
|
|
|
+ g_free(client->contexts.bitmaps);
|
|
g_free(client);
|
|
g_free(client);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -2749,11 +2754,11 @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
|
|
}
|
|
}
|
|
assert(client->mode >= NBD_MODE_EXTENDED ||
|
|
assert(client->mode >= NBD_MODE_EXTENDED ||
|
|
request->len <= UINT32_MAX);
|
|
request->len <= UINT32_MAX);
|
|
- if (client->export_meta.count) {
|
|
|
|
|
|
+ if (client->contexts.count) {
|
|
bool dont_fragment = request->flags & NBD_CMD_FLAG_REQ_ONE;
|
|
bool dont_fragment = request->flags & NBD_CMD_FLAG_REQ_ONE;
|
|
- int contexts_remaining = client->export_meta.count;
|
|
|
|
|
|
+ int contexts_remaining = client->contexts.count;
|
|
|
|
|
|
- if (client->export_meta.base_allocation) {
|
|
|
|
|
|
+ if (client->contexts.base_allocation) {
|
|
ret = nbd_co_send_block_status(client, request,
|
|
ret = nbd_co_send_block_status(client, request,
|
|
exp->common.blk,
|
|
exp->common.blk,
|
|
request->from,
|
|
request->from,
|
|
@@ -2766,7 +2771,7 @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- if (client->export_meta.allocation_depth) {
|
|
|
|
|
|
+ if (client->contexts.allocation_depth) {
|
|
ret = nbd_co_send_block_status(client, request,
|
|
ret = nbd_co_send_block_status(client, request,
|
|
exp->common.blk,
|
|
exp->common.blk,
|
|
request->from, request->len,
|
|
request->from, request->len,
|
|
@@ -2780,7 +2785,7 @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
|
|
}
|
|
}
|
|
|
|
|
|
for (i = 0; i < client->exp->nr_export_bitmaps; i++) {
|
|
for (i = 0; i < client->exp->nr_export_bitmaps; i++) {
|
|
- if (!client->export_meta.bitmaps[i]) {
|
|
|
|
|
|
+ if (!client->contexts.bitmaps[i]) {
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
ret = nbd_co_send_bitmap(client, request,
|
|
ret = nbd_co_send_bitmap(client, request,
|