With the experimental x-nbd-server-add-bitmap command, there was
a window of time where a client could see the export but not the
associated dirty bitmap, which can cause a client that planned
on using the dirty bitmap to be forced to treat the entire image
as dirty as a safety fallback.  Furthermore, if the QMP client
successfully exports a disk but then fails to add the bitmap, it
has to take on the burden of removing the export.  Since we don't
allow changing a dirty bitmap once it is exported (whether to a
different bitmap, or removing advertisement of the bitmap), it is
nicer to make the bitmap tied to the export at the time the export
is created, and automatically failing to export if the bitmap is
not available.

Since there is working libvirt demo code that uses both the bitmap
export and the ability to specify an alternative name (rather than
exposing the private-use bitmap that libvirt created to merge in
several persistent bitmaps when doing a differential backup), the
two new parameters do not need to be marked experimental.  See
https://www.redhat.com/archives/libvir-list/2018-October/msg01254.html,
https://kvmforum2018.sched.com/event/FzuB/facilitating-incremental-backup-eric-blake-red-hat

This patch focuses on the user interface, and reduces (but does
not completely eliminate) the window where an NBD client can see
the export but not the dirty bitmap.  Later patches will add
further cleanups now that this interface is available.

Update test 223 to use the new interface.

Signed-off-by: Eric Blake <ebl...@redhat.com>
---
 qapi/block.json            | 12 +++++++++++-
 blockdev-nbd.c             | 27 ++++++++++++++++++++++++++-
 hmp.c                      |  6 ++++--
 tests/qemu-iotests/223     | 11 ++++-------
 tests/qemu-iotests/223.out |  2 --
 5 files changed, 45 insertions(+), 13 deletions(-)

diff --git a/qapi/block.json b/qapi/block.json
index 11f01f28efe..4b336303d21 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -246,6 +246,15 @@
 #
 # @writable: Whether clients should be able to write to the device via the
 #     NBD connection (default false).
+
+# @bitmap: Dirty bitmap to associate with the selected export. The export
+#          must be read-only, and the given bitmap is locked until the
+#          export is removed. (since 4.0)
+#
+# @bitmap-export-name: How the bitmap will be seen by nbd clients
+#                      (default @bitmap). The NBD client must use
+#                      NBD_OPT_SET_META_CONTEXT with "qemu:dirty-bitmap:NAME"
+#                      to access the exposed bitmap. (since 4.0)
 #
 # Returns: error if the server is not running, or export with the same name
 #          already exists.
@@ -253,7 +262,8 @@
 # Since: 1.3.0
 ##
 { 'command': 'nbd-server-add',
-  'data': {'device': 'str', '*name': 'str', '*writable': 'bool'} }
+  'data': {'device': 'str', '*name': 'str', '*writable': 'bool',
+           '*bitmap': 'str', '*bitmap-export-name': 'str' } }

 ##
 # @NbdServerRemoveMode:
diff --git a/blockdev-nbd.c b/blockdev-nbd.c
index f5edbc27d88..cae9e802d48 100644
--- a/blockdev-nbd.c
+++ b/blockdev-nbd.c
@@ -140,7 +140,10 @@ void qmp_nbd_server_start(SocketAddressLegacy *addr,
 }

 void qmp_nbd_server_add(const char *device, bool has_name, const char *name,
-                        bool has_writable, bool writable, Error **errp)
+                        bool has_writable, bool writable,
+                        bool has_bitmap, const char *bitmap,
+                        bool has_bitmap_export_name,
+                        const char *bitmap_export_name, Error **errp)
 {
     BlockDriverState *bs = NULL;
     BlockBackend *on_eject_blk;
@@ -160,6 +163,17 @@ void qmp_nbd_server_add(const char *device, bool has_name, 
const char *name,
         return;
     }

+    if (has_bitmap_export_name && !has_bitmap) {
+        error_setg(errp, "Choosing bitmap export name '%s' requires a bitmap",
+                   bitmap_export_name);
+        return;
+    }
+    if (has_bitmap && writable) {
+        error_setg(errp, "Cannot export bitmap '%s' on writable export",
+                   bitmap);
+        return;
+    }
+
     on_eject_blk = blk_by_name(device);

     bs = bdrv_lookup_bs(device, device, errp);
@@ -185,6 +199,17 @@ void qmp_nbd_server_add(const char *device, bool has_name, 
const char *name,
      * our only way of accessing it is through nbd_export_find(), so we can 
drop
      * the strong reference that is @exp. */
     nbd_export_put(exp);
+
+    if (has_bitmap) {
+        Error *err = NULL;
+        nbd_export_bitmap(exp, bitmap,
+                          has_bitmap_export_name ? bitmap_export_name : bitmap,
+                          &err);
+        if (err) {
+            error_propagate(errp, err);
+            nbd_export_remove(exp, NBD_SERVER_REMOVE_MODE_HARD, NULL);
+        }
+    }
 }

 void qmp_nbd_server_remove(const char *name,
diff --git a/hmp.c b/hmp.c
index 80aa5ab504b..484a0000de1 100644
--- a/hmp.c
+++ b/hmp.c
@@ -2326,7 +2326,8 @@ void hmp_nbd_server_start(Monitor *mon, const QDict 
*qdict)
         }

         qmp_nbd_server_add(info->value->device, false, NULL,
-                           true, writable, &local_err);
+                           true, writable, false, NULL, false, NULL,
+                           &local_err);

         if (local_err != NULL) {
             qmp_nbd_server_stop(NULL);
@@ -2347,7 +2348,8 @@ void hmp_nbd_server_add(Monitor *mon, const QDict *qdict)
     bool writable = qdict_get_try_bool(qdict, "writable", false);
     Error *local_err = NULL;

-    qmp_nbd_server_add(device, !!name, name, true, writable, &local_err);
+    qmp_nbd_server_add(device, !!name, name, true, writable,
+                       false, NULL, false, NULL, &local_err);
     hmp_handle_error(mon, &local_err);
 }

diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223
index 5513dc62159..7a92c3018e2 100755
--- a/tests/qemu-iotests/223
+++ b/tests/qemu-iotests/223
@@ -120,13 +120,10 @@ _send_qemu_cmd $QEMU_HANDLE 
'{"execute":"nbd-server-start",
   "arguments":{"addr":{"type":"unix",
     "data":{"path":"'"$TEST_DIR/nbd"'"}}}}' "return"
 _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
-  "arguments":{"device":"n"}}' "return"
-_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-nbd-server-add-bitmap",
-  "arguments":{"name":"n", "bitmap":"b"}}' "return"
+  "arguments":{"device":"n", "bitmap":"b"}}' "return"
 _send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
-  "arguments":{"device":"n", "name":"n2"}}' "return"
-_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-nbd-server-add-bitmap",
-  "arguments":{"name":"n2", "bitmap":"b2"}}' "return"
+  "arguments":{"device":"n", "name":"n2", "bitmap":"b2",
+    "bitmap-export-name":"b3"}}' "return"

 echo
 echo "=== Contrast normal status to large granularity dirty-bitmap ==="
@@ -147,7 +144,7 @@ echo

 IMG="driver=nbd,export=n2,server.type=unix,server.path=$TEST_DIR/nbd"
 $QEMU_IMG map --output=json --image-opts \
-  "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b2" | _filter_qemu_img_map
+  "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b3" | _filter_qemu_img_map

 echo
 echo "=== End NBD server ==="
diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out
index 99ca172fbb8..0e467981bb8 100644
--- a/tests/qemu-iotests/223.out
+++ b/tests/qemu-iotests/223.out
@@ -31,8 +31,6 @@ wrote 2097152/2097152 bytes at offset 2097152
 {"return": {}}
 {"return": {}}
 {"return": {}}
-{"return": {}}
-{"return": {}}

 === Contrast normal status to large granularity dirty-bitmap ===

-- 
2.20.1


Reply via email to