summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--include/block/nbd.h2
-rw-r--r--nbd/client.c41
2 files changed, 41 insertions, 2 deletions
diff --git a/include/block/nbd.h b/include/block/nbd.h
index 19332b4671..4faf394e34 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -284,6 +284,8 @@ struct NBDExportInfo {
 
     /* Set by server results during nbd_receive_export_list() */
     char *description;
+    int n_contexts;
+    char **contexts;
 };
 typedef struct NBDExportInfo NBDExportInfo;
 
diff --git a/nbd/client.c b/nbd/client.c
index 8a32169970..798b82f205 100644
--- a/nbd/client.c
+++ b/nbd/client.c
@@ -818,6 +818,36 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc,
 }
 
 /*
+ * nbd_list_meta_contexts:
+ * Request the server to list all meta contexts for export @info->name.
+ * return 0 if list is complete (even if empty),
+ *        -1 with errp set for any error
+ */
+static int nbd_list_meta_contexts(QIOChannel *ioc,
+                                  NBDExportInfo *info,
+                                  Error **errp)
+{
+    int ret;
+
+    if (nbd_send_meta_query(ioc, NBD_OPT_LIST_META_CONTEXT,
+                            info->name, NULL, errp) < 0) {
+        return -1;
+    }
+
+    while (1) {
+        char *context;
+
+        ret = nbd_receive_one_meta_context(ioc, NBD_OPT_LIST_META_CONTEXT,
+                                           &context, NULL, errp);
+        if (ret <= 0) {
+            return ret;
+        }
+        info->contexts = g_renew(char *, info->contexts, ++info->n_contexts);
+        info->contexts[info->n_contexts - 1] = context;
+    }
+}
+
+/*
  * nbd_start_negotiate:
  * Start the handshake to the server.  After a positive return, the server
  * is ready to accept additional NBD_OPT requests.
@@ -1066,7 +1096,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
 /* Clean up result of nbd_receive_export_list */
 void nbd_free_export_list(NBDExportInfo *info, int count)
 {
-    int i;
+    int i, j;
 
     if (!info) {
         return;
@@ -1075,6 +1105,10 @@ void nbd_free_export_list(NBDExportInfo *info, int count)
     for (i = 0; i < count; i++) {
         g_free(info[i].name);
         g_free(info[i].description);
+        for (j = 0; j < info[i].n_contexts; j++) {
+            g_free(info[i].contexts[j]);
+        }
+        g_free(info[i].contexts);
     }
     g_free(info);
 }
@@ -1144,7 +1178,10 @@ int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
                 break;
             }
 
-            /* TODO: Grab meta contexts */
+            if (result == 3 &&
+                nbd_list_meta_contexts(ioc, &array[i], errp) < 0) {
+                goto out;
+            }
         }
 
         /* Send NBD_OPT_ABORT as a courtesy before hanging up */