All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media
@ 2015-02-09 17:11 Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 01/37] blockdev: Allow creation of BDS trees without BB Max Reitz
                   ` (36 more replies)
  0 siblings, 37 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

This series reworks a lot regarding BlockBackend and media. It is
essentially a v3 to the "blockdev: Add blockdev-change-medium with
read-only option" series (which is in fact a part of this series), but
of course does a lot more.

Basically, this series allows empty BlockBackends, that is BBs without a
BDS tree.

Before this series, empty drives are represented by a BlockBackend with
an empty BDS attached to it (a BDS with a NULL driver). However, now we
have BlockBackends, thus an empty drive should be represented by a
BlockBackend without any BDS tree attached to it. This is what this
series does.


This series depends on v4 (or any later version) of my series
'block: Remove "growable", add blk_new_open()'.


v2:
- Patch 1: Make "node-name" obligatory for blockdev-add if "id" is not
  given [Eric]
- Patch 3: Conflict due to a test case not being removed in patch 1 in
  this version
- Patch 6: Added [Eric]
- Patch 8: Conflicts due to patch 6
- Patch 9: Trivial conflicts due to patch 6, kept Eric's R-b
- Patch 11: Rename wr_highest_sector to wr_highest_offset and let it
  store that highest offset, in the sense that qapi/block-core.json
  defines it; qmp-commands.hx is changed accordingly [Eric]
- Patch 12: Rebase conflicts due to Peter's multiwrite merge series
- Patch 16: Added a hunk for blk_nb_sectors() [Eric]; kept Eric's R-b
  because it is exactly the change he had envisioned
- Patch 17: Rebase conflict due to the new function
  blk_get_max_transfer_length()
- Patch 18: Changed commit title [Eric]
- Patch 20: Squashed together all of the following patches from v1
  (which where all very similar): 17, 18, 20, 21, 22, 23, 24, 25, 26,
  27, 28, 29, 30, 32, 33, and the patch
  "block: Guard remaining unsafe blk_bs() callers" from the
  "block: Rework bdrv_close_all()" series
  All of these patches have a R-b by Eric, but (for obvious reasons) I
  did not merge the R-bs to a single one for this patch
- Patch 21: The same conflict as in patch 3, only in this case it is for
  the builtin CD drive instead of the floppy drive
- Patch 25:
  - Added a note about this command being a no-op if the tray is already
    open [Eric]
  - s/Example (1)/Example/ [Eric]
- Patch 26:
  - Added a note about this command being a no-op if the tray is already
    closed [Eric]
  - s/Example (1)/Example/ [Eric]
- Patch 27:
  - Added a note about this command being a no-op if the tray is open
    and empty [Eric]
  - s/Example (1)/Example/ [Eric]
- Patch 28:
  - s/Example (1)/Example/ [Eric]
  - Removed the "id" option from the blockdev-add command [Eric]
- Patch 30:
  - Rebase conflicts due to the new bdrv_add_key() function
  - bdrv_unref() was missing from qmp_change_blockdev()
- Patch 32:
  - Changed the deprecation note [Eric]
  - More indentation for the blockdev-change-medium option descriptions
    ('read-only-mode' (introduced by patch 34) is longer than
    'read-only')
- Patch 34: 'read-only-mode' instead of 'read-only'; 'read-only' instead
  of 'ro'; and 'read-write' instead of 'rw' [Eric]
- Patch 35: The same as for patch 34 [Eric]
- Patch 36: "if not path is None" -> "if path is not None" [Eric]
- Patch 37: 'read-only' is now 'read-only-mode', etc.


git-backport-diff against v1:

Key:
[----] : patches are identical
[####] : number of functional differences between upstream/downstream patch
[down] : patch is downstream-only
The flags [FC] indicate (F)unctional and (C)ontextual differences, respectively

001/37:[0051] [FC] 'blockdev: Allow creation of BDS trees without BB'
002/37:[----] [--] 'iotests: Only create BB if necessary'
003/37:[0001] [FC] 'hw/block/fdc: Implement tray status'
004/37:[----] [--] 'hw/usb-storage: Check whether BB is inserted'
005/37:[----] [--] 'block: Fix BB AIOCB AioContext without BDS'
006/37:[down] 'block: Make bdrv_is_inserted() return a bool'
007/37:[----] [-C] 'block: Add blk_is_available()'
008/37:[0008] [FC] 'block: Make bdrv_is_inserted() recursive'
009/37:[0006] [FC] 'block/quorum: Implement bdrv_is_inserted()'
010/37:[----] [-C] 'block: Move guest_block_size into BlockBackend'
011/37:[down] 'block: Remove wr_highest_sector from BlockAcctStats'
        ^^^^ actually [0017] [FC] (or something like that)
012/37:[0009] [FC] 'block: Move BlockAcctStats into BlockBackend'
013/37:[----] [-C] 'block: Move I/O status and error actions into BB'
014/37:[----] [--] 'block: Add BlockBackendRootState'
015/37:[----] [-C] 'block: Make some BB functions fall back to BBRS'
016/37:[0004] [FC] 'block: Fail requests to empty BlockBackend'
017/37:[0006] [FC] 'block: Prepare remaining BB functions for NULL BDS'
018/37:[down] 'blockdev: Use BB for blockdev-backup transaction'
        ^^^^ actually [----] [--]
019/37:[----] [--] 'block: Add blk_insert_bs()'
020/37:[down] 'block: Prepare for NULL BDS'
021/37:[0001] [FC] 'blockdev: Do not create BDS for empty drive'
022/37:[----] [-C] 'blockdev: Pull out blockdev option extraction'
023/37:[----] [-C] 'blockdev: Allow more options for BB-less BDS tree'
024/37:[----] [--] 'block: Add blk_remove_bs()'
025/37:[0006] [FC] 'blockdev: Add blockdev-open-tray'
026/37:[0006] [FC] 'blockdev: Add blockdev-close-tray'
027/37:[0006] [FC] 'blockdev: Add blockdev-remove-medium'
028/37:[0005] [FC] 'blockdev: Add blockdev-insert-medium'
029/37:[----] [--] 'blockdev: Implement eject with basic operations'
030/37:[0044] [FC] 'blockdev: Implement change with basic operations'
031/37:[----] [--] 'block: Inquire tray state before tray-moved events'
032/37:[0015] [FC] 'qmp: Introduce blockdev-change-medium'
033/37:[----] [--] 'hmp: Use blockdev-change-medium for change command'
034/37:[down] 'blockdev: read-only-mode for blockdev-change-medium'
        ^^^^ actually [0028] [FC]
035/37:[down] 'hmp: Add read-only-mode option to change command'
        ^^^^ actually [0019] [FC]
036/37:[0002] [FC] 'iotests: More options for VM.add_drive()'
037/37:[0046] [FC] 'iotests: Add test for change-related QMP commands'


Max Reitz (37):
  blockdev: Allow creation of BDS trees without BB
  iotests: Only create BB if necessary
  hw/block/fdc: Implement tray status
  hw/usb-storage: Check whether BB is inserted
  block: Fix BB AIOCB AioContext without BDS
  block: Make bdrv_is_inserted() return a bool
  block: Add blk_is_available()
  block: Make bdrv_is_inserted() recursive
  block/quorum: Implement bdrv_is_inserted()
  block: Move guest_block_size into BlockBackend
  block: Remove wr_highest_sector from BlockAcctStats
  block: Move BlockAcctStats into BlockBackend
  block: Move I/O status and error actions into BB
  block: Add BlockBackendRootState
  block: Make some BB functions fall back to BBRS
  block: Fail requests to empty BlockBackend
  block: Prepare remaining BB functions for NULL BDS
  blockdev: Use BB for blockdev-backup transaction
  block: Add blk_insert_bs()
  block: Prepare for NULL BDS
  blockdev: Do not create BDS for empty drive
  blockdev: Pull out blockdev option extraction
  blockdev: Allow more options for BB-less BDS tree
  block: Add blk_remove_bs()
  blockdev: Add blockdev-open-tray
  blockdev: Add blockdev-close-tray
  blockdev: Add blockdev-remove-medium
  blockdev: Add blockdev-insert-medium
  blockdev: Implement eject with basic operations
  blockdev: Implement change with basic operations
  block: Inquire tray state before tray-moved events
  qmp: Introduce blockdev-change-medium
  hmp: Use blockdev-change-medium for change command
  blockdev: read-only-mode for blockdev-change-medium
  hmp: Add read-only-mode option to change command
  iotests: More options for VM.add_drive()
  iotests: Add test for change-related QMP commands

 block.c                        | 170 +-------
 block/accounting.c             |   8 -
 block/backup.c                 |  17 +-
 block/block-backend.c          | 368 +++++++++++++++--
 block/commit.c                 |   3 +-
 block/mirror.c                 |  17 +-
 block/qapi.c                   |  36 +-
 block/quorum.c                 |  16 +
 block/raw-posix.c              |  10 +-
 block/raw_bsd.c                |   2 +-
 block/stream.c                 |   3 +-
 blockdev.c                     | 919 +++++++++++++++++++++++++++++------------
 blockjob.c                     |   5 +-
 hmp-commands.hx                |  20 +-
 hmp.c                          |  47 ++-
 hw/block/fdc.c                 |  20 +-
 hw/block/xen_disk.c            |   4 +-
 hw/usb/dev-storage.c           |   2 +-
 include/block/accounting.h     |   3 -
 include/block/block.h          |  16 +-
 include/block/block_int.h      |  24 +-
 include/qemu/typedefs.h        |   1 +
 include/sysemu/block-backend.h |  14 +-
 include/sysemu/blockdev.h      |   2 -
 qapi-schema.json               |   6 +-
 qapi/block-core.json           | 129 +++++-
 qmp-commands.hx                | 213 +++++++++-
 qmp.c                          |   9 +-
 tests/fdc-test.c               |   4 +-
 tests/qemu-iotests/067.out     | 104 +----
 tests/qemu-iotests/071         |  50 ++-
 tests/qemu-iotests/071.out     |  16 +-
 tests/qemu-iotests/081         |  14 +-
 tests/qemu-iotests/081.out     |   7 +-
 tests/qemu-iotests/087         |   2 +-
 tests/qemu-iotests/087.out     |  16 +-
 tests/qemu-iotests/118         | 653 +++++++++++++++++++++++++++++
 tests/qemu-iotests/118.out     |   5 +
 tests/qemu-iotests/group       |   1 +
 tests/qemu-iotests/iotests.py  |   9 +-
 40 files changed, 2273 insertions(+), 692 deletions(-)
 create mode 100755 tests/qemu-iotests/118
 create mode 100644 tests/qemu-iotests/118.out

-- 
2.1.0

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 01/37] blockdev: Allow creation of BDS trees without BB
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 18:17   ` Eric Blake
  2015-03-04 13:39   ` Kevin Wolf
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 02/37] iotests: Only create BB if necessary Max Reitz
                   ` (35 subsequent siblings)
  36 siblings, 2 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

If the "id" field is missing from the options given to blockdev-add,
just omit the BlockBackend and create the BlockDriverState tree alone.

However, if "id" is missing, "node-name" must be specified; otherwise,
the BDS tree would no longer be accessible.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 blockdev.c                 | 44 +++++++++++++++++++++++++++++++-------------
 qapi/block-core.json       | 13 +++++++++----
 tests/qemu-iotests/087     |  2 +-
 tests/qemu-iotests/087.out |  4 ++--
 4 files changed, 43 insertions(+), 20 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 6eedcf5..6d67c80 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2822,17 +2822,12 @@ out:
 void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
 {
     QmpOutputVisitor *ov = qmp_output_visitor_new();
-    BlockBackend *blk;
+    BlockDriverState *bs;
+    BlockBackend *blk = NULL;
     QObject *obj;
     QDict *qdict;
     Error *local_err = NULL;
 
-    /* Require an ID in the top level */
-    if (!options->has_id) {
-        error_setg(errp, "Block device needs an ID");
-        goto fail;
-    }
-
     /* TODO Sort it out in raw-posix and drive_new(): Reject aio=native with
      * cache.direct=false instead of silently switching to aio=threads, except
      * when called from drive_new().
@@ -2860,14 +2855,37 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
 
     qdict_flatten(qdict);
 
-    blk = blockdev_init(NULL, qdict, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        goto fail;
+    if (options->has_id) {
+        blk = blockdev_init(NULL, qdict, &local_err);
+        if (local_err) {
+            error_propagate(errp, local_err);
+            goto fail;
+        }
+
+        bs = blk_bs(blk);
+    } else {
+        int ret;
+
+        if (!qdict_get_try_str(qdict, "node-name")) {
+            error_setg(errp, "'id' and/or 'node-name' need to be specified for "
+                       "the root node");
+            goto fail;
+        }
+
+        bs = NULL;
+        ret = bdrv_open(&bs, NULL, NULL, qdict, BDRV_O_RDWR | BDRV_O_CACHE_WB,
+                        NULL, errp);
+        if (ret < 0) {
+            goto fail;
+        }
     }
 
-    if (bdrv_key_required(blk_bs(blk))) {
-        blk_unref(blk);
+    if (bs && bdrv_key_required(bs)) {
+        if (blk) {
+            blk_unref(blk);
+        } else {
+            bdrv_unref(bs);
+        }
         error_setg(errp, "blockdev-add doesn't support encrypted devices");
         goto fail;
     }
diff --git a/qapi/block-core.json b/qapi/block-core.json
index a3fdaf0..e85ef40 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1260,9 +1260,12 @@
 #
 # @driver:        block driver name
 # @id:            #optional id by which the new block device can be referred to.
-#                 This is a required option on the top level of blockdev-add, and
-#                 currently not allowed on any other level.
-# @node-name:     #optional the name of a block driver state node (Since 2.0)
+#                 This option is only allowed on the top level of blockdev-add.
+#                 A BlockBackend will be created by blockdev-add if and only if
+#                 this option is given.
+# @node-name:     #optional the name of a block driver state node (Since 2.0).
+#                 This option is required on the top level of blockdev-add if
+#                 the @id option is not given there.
 # @discard:       #optional discard-related options (default: ignore)
 # @cache:         #optional cache-related options
 # @aio:           #optional AIO backend (default: threads)
@@ -1717,7 +1720,9 @@
 ##
 # @blockdev-add:
 #
-# Creates a new block device.
+# Creates a new block device. If the @id option is given at the top level, a
+# BlockBackend will be created; otherwise, @node-name is mandatory at the top
+# level and no BlockBackend will be created.
 #
 # @options: block device options for the new device
 #
diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087
index 8694749..af44299 100755
--- a/tests/qemu-iotests/087
+++ b/tests/qemu-iotests/087
@@ -54,7 +54,7 @@ size=128M
 _make_test_img $size
 
 echo
-echo === Missing ID ===
+echo === Missing ID and node-name ===
 echo
 
 run_qemu <<EOF
diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out
index 0ba2e43..b0aa06d 100644
--- a/tests/qemu-iotests/087.out
+++ b/tests/qemu-iotests/087.out
@@ -1,12 +1,12 @@
 QA output created by 087
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
 
-=== Missing ID ===
+=== Missing ID and node-name ===
 
 Testing:
 QMP_VERSION
 {"return": {}}
-{"error": {"class": "GenericError", "desc": "Block device needs an ID"}}
+{"error": {"class": "GenericError", "desc": "'id' and/or 'node-name' need to be specified for the root node"}}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 02/37] iotests: Only create BB if necessary
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 01/37] blockdev: Allow creation of BDS trees without BB Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 03/37] hw/block/fdc: Implement tray status Max Reitz
                   ` (34 subsequent siblings)
  36 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

Tests 071 and 081 test giving references in blockdev-add. It is not
necessary to create a BlockBackend here, so omit it.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 tests/qemu-iotests/071     | 50 ++++++++++++++++++++++++++++++++++++++++++----
 tests/qemu-iotests/071.out | 12 +++++++----
 tests/qemu-iotests/081     | 14 ++++++++++++-
 tests/qemu-iotests/081.out |  5 +++--
 4 files changed, 70 insertions(+), 11 deletions(-)

diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071
index 9eaa49b..68bedd4 100755
--- a/tests/qemu-iotests/071
+++ b/tests/qemu-iotests/071
@@ -104,11 +104,20 @@ echo
 echo "=== Testing blkdebug on existing block device ==="
 echo
 
-run_qemu -drive "file=$TEST_IMG,format=raw,if=none,id=drive0" <<EOF
+run_qemu <<EOF
 { "execute": "qmp_capabilities" }
 { "execute": "blockdev-add",
     "arguments": {
         "options": {
+            "node-name": "drive0",
+            "driver": "file",
+            "filename": "$TEST_IMG"
+        }
+    }
+}
+{ "execute": "blockdev-add",
+    "arguments": {
+        "options": {
             "driver": "$IMGFMT",
             "id": "drive0-debug",
             "file": {
@@ -133,11 +142,23 @@ echo
 echo "=== Testing blkverify on existing block device ==="
 echo
 
-run_qemu -drive "file=$TEST_IMG,format=$IMGFMT,if=none,id=drive0" <<EOF
+run_qemu <<EOF
 { "execute": "qmp_capabilities" }
 { "execute": "blockdev-add",
     "arguments": {
         "options": {
+            "node-name": "drive0",
+            "driver": "$IMGFMT",
+            "file": {
+                "driver": "file",
+                "filename": "$TEST_IMG"
+            }
+        }
+    }
+}
+{ "execute": "blockdev-add",
+    "arguments": {
+        "options": {
             "driver": "blkverify",
             "id": "drive0-verify",
             "test": "drive0",
@@ -163,11 +184,23 @@ echo
 echo "=== Testing blkverify on existing raw block device ==="
 echo
 
-run_qemu -drive "file=$TEST_IMG.base,format=raw,if=none,id=drive0" <<EOF
+run_qemu <<EOF
 { "execute": "qmp_capabilities" }
 { "execute": "blockdev-add",
     "arguments": {
         "options": {
+            "node-name": "drive0",
+            "driver": "raw",
+            "file": {
+                "driver": "file",
+                "filename": "$TEST_IMG.base"
+            }
+        }
+    }
+}
+{ "execute": "blockdev-add",
+    "arguments": {
+        "options": {
             "driver": "blkverify",
             "id": "drive0-verify",
             "test": {
@@ -193,11 +226,20 @@ echo
 echo "=== Testing blkdebug's set-state through QMP ==="
 echo
 
-run_qemu -drive "file=$TEST_IMG,format=raw,if=none,id=drive0" <<EOF
+run_qemu <<EOF
 { "execute": "qmp_capabilities" }
 { "execute": "blockdev-add",
     "arguments": {
         "options": {
+            "node-name": "drive0",
+            "driver": "file",
+            "filename": "$TEST_IMG"
+        }
+    }
+}
+{ "execute": "blockdev-add",
+    "arguments": {
+        "options": {
             "driver": "$IMGFMT",
             "id": "drive0-debug",
             "file": {
diff --git a/tests/qemu-iotests/071.out b/tests/qemu-iotests/071.out
index 9205ce2..c8ecfaf 100644
--- a/tests/qemu-iotests/071.out
+++ b/tests/qemu-iotests/071.out
@@ -42,10 +42,11 @@ read failed: Input/output error
 
 === Testing blkdebug on existing block device ===
 
-Testing: -drive file=TEST_DIR/t.IMGFMT,format=raw,if=none,id=drive0
+Testing:
 QMP_VERSION
 {"return": {}}
 {"return": {}}
+{"return": {}}
 read failed: Input/output error
 {"return": ""}
 {"return": {}}
@@ -58,28 +59,31 @@ QEMU_PROG: Failed to flush the refcount block cache: Input/output error
 
 === Testing blkverify on existing block device ===
 
-Testing: -drive file=TEST_DIR/t.IMGFMT,format=IMGFMT,if=none,id=drive0
+Testing:
 QMP_VERSION
 {"return": {}}
 {"return": {}}
+{"return": {}}
 blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0
 
 
 === Testing blkverify on existing raw block device ===
 
-Testing: -drive file=TEST_DIR/t.IMGFMT.base,format=raw,if=none,id=drive0
+Testing:
 QMP_VERSION
 {"return": {}}
 {"return": {}}
+{"return": {}}
 blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0
 
 
 === Testing blkdebug's set-state through QMP ===
 
-Testing: -drive file=TEST_DIR/t.IMGFMT,format=raw,if=none,id=drive0
+Testing:
 QMP_VERSION
 {"return": {}}
 {"return": {}}
+{"return": {}}
 read 512/512 bytes at offset 0
 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 {"return": ""}
diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081
index d9b042c..5c8a8fa 100755
--- a/tests/qemu-iotests/081
+++ b/tests/qemu-iotests/081
@@ -101,11 +101,23 @@ $QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io
 echo
 echo "== checking mixed reference/option specification =="
 
-run_qemu -drive "file=$TEST_DIR/2.raw,format=$IMGFMT,if=none,id=drive2" <<EOF
+run_qemu <<EOF
 { "execute": "qmp_capabilities" }
 { "execute": "blockdev-add",
     "arguments": {
         "options": {
+            "node-name": "drive2",
+            "driver": "raw",
+            "file": {
+                "driver": "file",
+                "filename": "$TEST_DIR/2.raw"
+            }
+        }
+    }
+}
+{ "execute": "blockdev-add",
+    "arguments": {
+        "options": {
             "driver": "quorum",
             "id": "drive0-quorum",
             "vote-threshold": 2,
diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out
index 9f57d9d..2375916 100644
--- a/tests/qemu-iotests/081.out
+++ b/tests/qemu-iotests/081.out
@@ -26,11 +26,12 @@ read 10485760/10485760 bytes at offset 0
 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 
 == checking mixed reference/option specification ==
-Testing: -drive file=TEST_DIR/2.IMGFMT,format=IMGFMT,if=none,id=drive2
+Testing:
 QMP_VERSION
 {"return": {}}
 {"return": {}}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "QUORUM_REPORT_BAD", "data": {"node-name": "", "sectors-count": 20480, "sector-num": 0}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "QUORUM_REPORT_BAD", "data": {"node-name": "drive2", "sectors-count": 20480, "sector-num": 0}}
 read 10485760/10485760 bytes at offset 0
 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 {"return": ""}
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 03/37] hw/block/fdc: Implement tray status
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 01/37] blockdev: Allow creation of BDS trees without BB Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 02/37] iotests: Only create BB if necessary Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 18:23   ` Eric Blake
  2015-03-04 14:00   ` Kevin Wolf
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 04/37] hw/usb-storage: Check whether BB is inserted Max Reitz
                   ` (33 subsequent siblings)
  36 siblings, 2 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

The tray of an FDD is open iff there is no medium inserted (there are
only two states for an FDD: "medium inserted" or "no medium inserted").

This results in the tray being reported as open if qemu has been started
with the default floppy drive, which breaks some tests. Fix them.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 hw/block/fdc.c             | 20 +++++++++++++---
 tests/fdc-test.c           |  4 +---
 tests/qemu-iotests/067.out | 60 +++++++---------------------------------------
 tests/qemu-iotests/071.out |  2 --
 tests/qemu-iotests/081.out |  1 -
 tests/qemu-iotests/087.out |  6 -----
 6 files changed, 26 insertions(+), 67 deletions(-)

diff --git a/hw/block/fdc.c b/hw/block/fdc.c
index 2bf87c9..0c5a6b4 100644
--- a/hw/block/fdc.c
+++ b/hw/block/fdc.c
@@ -192,6 +192,8 @@ typedef struct FDrive {
     uint8_t ro;               /* Is read-only           */
     uint8_t media_changed;    /* Is media changed       */
     uint8_t media_rate;       /* Data rate of medium    */
+
+    bool media_inserted;      /* Is there a medium in the tray */
 } FDrive;
 
 static void fd_init(FDrive *drv)
@@ -261,7 +263,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
 #endif
         drv->head = head;
         if (drv->track != track) {
-            if (drv->blk != NULL && blk_is_inserted(drv->blk)) {
+            if (drv->media_inserted) {
                 drv->media_changed = 0;
             }
             ret = 1;
@@ -270,7 +272,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
         drv->sect = sect;
     }
 
-    if (drv->blk == NULL || !blk_is_inserted(drv->blk)) {
+    if (!drv->media_inserted) {
         ret = 2;
     }
 
@@ -296,7 +298,7 @@ static void fd_revalidate(FDrive *drv)
         ro = blk_is_read_only(drv->blk);
         pick_geometry(drv->blk, &nb_heads, &max_track,
                       &last_sect, drv->drive, &drive, &rate);
-        if (!blk_is_inserted(drv->blk)) {
+        if (!drv->media_inserted) {
             FLOPPY_DPRINTF("No disk in drive\n");
         } else {
             FLOPPY_DPRINTF("Floppy disk (%d h %d t %d s) %s\n", nb_heads,
@@ -2062,12 +2064,21 @@ static void fdctrl_change_cb(void *opaque, bool load)
 {
     FDrive *drive = opaque;
 
+    drive->media_inserted = load && drive->blk && blk_is_inserted(drive->blk);
+
     drive->media_changed = 1;
     fd_revalidate(drive);
 }
 
+static bool fdctrl_is_tray_open(void *opaque)
+{
+    FDrive *drive = opaque;
+    return !drive->media_inserted;
+}
+
 static const BlockDevOps fdctrl_block_ops = {
     .change_media_cb = fdctrl_change_cb,
+    .is_tray_open = fdctrl_is_tray_open,
 };
 
 /* Init functions */
@@ -2095,6 +2106,9 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, Error **errp)
         fdctrl_change_cb(drive, 0);
         if (drive->blk) {
             blk_set_dev_ops(drive->blk, &fdctrl_block_ops, drive);
+            if (blk_is_inserted(drive->blk)) {
+                drive->media_inserted = true;
+            }
         }
     }
 }
diff --git a/tests/fdc-test.c b/tests/fdc-test.c
index 3c6c83c..f287c10 100644
--- a/tests/fdc-test.c
+++ b/tests/fdc-test.c
@@ -293,9 +293,7 @@ static void test_media_insert(void)
     qmp_discard_response("{'execute':'change', 'arguments':{"
                          " 'device':'floppy0', 'target': %s, 'arg': 'raw' }}",
                          test_image);
-    qmp_discard_response(""); /* ignore event
-                                 (FIXME open -> open transition?!) */
-    qmp_discard_response(""); /* ignore event */
+    qmp_discard_response(""); /* ignore event (open -> close) */
 
     dir = inb(FLOPPY_BASE + reg_dir);
     assert_bit_set(dir, DSKCHG);
diff --git a/tests/qemu-iotests/067.out b/tests/qemu-iotests/067.out
index 00b3eae..42bae32 100644
--- a/tests/qemu-iotests/067.out
+++ b/tests/qemu-iotests/067.out
@@ -69,7 +69,7 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti
             "device": "floppy0",
             "locked": false,
             "removable": true,
-            "tray_open": false,
+            "tray_open": true,
             "type": "unknown"
         },
         {
@@ -131,7 +131,7 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti
             "device": "floppy0",
             "locked": false,
             "removable": true,
-            "tray_open": false,
+            "tray_open": true,
             "type": "unknown"
         },
         {
@@ -165,17 +165,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti
         "tray-open": true
     }
 }
-{
-    "timestamp": {
-        "seconds":  TIMESTAMP,
-        "microseconds":  TIMESTAMP
-    },
-    "event": "DEVICE_TRAY_MOVED",
-    "data": {
-        "device": "floppy0",
-        "tray-open": true
-    }
-}
 
 
 === -drive/device_add and device_del ===
@@ -246,7 +235,7 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
             "device": "floppy0",
             "locked": false,
             "removable": true,
-            "tray_open": false,
+            "tray_open": true,
             "type": "unknown"
         },
         {
@@ -312,7 +301,7 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
             "device": "floppy0",
             "locked": false,
             "removable": true,
-            "tray_open": false,
+            "tray_open": true,
             "type": "unknown"
         },
         {
@@ -346,17 +335,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
         "tray-open": true
     }
 }
-{
-    "timestamp": {
-        "seconds":  TIMESTAMP,
-        "microseconds":  TIMESTAMP
-    },
-    "event": "DEVICE_TRAY_MOVED",
-    "data": {
-        "device": "floppy0",
-        "tray-open": true
-    }
-}
 
 
 === drive_add/device_add and device_del ===
@@ -386,7 +364,7 @@ Testing:
             "device": "floppy0",
             "locked": false,
             "removable": true,
-            "tray_open": false,
+            "tray_open": true,
             "type": "unknown"
         },
         {
@@ -496,7 +474,7 @@ Testing:
             "device": "floppy0",
             "locked": false,
             "removable": true,
-            "tray_open": false,
+            "tray_open": true,
             "type": "unknown"
         },
         {
@@ -530,17 +508,6 @@ Testing:
         "tray-open": true
     }
 }
-{
-    "timestamp": {
-        "seconds":  TIMESTAMP,
-        "microseconds":  TIMESTAMP
-    },
-    "event": "DEVICE_TRAY_MOVED",
-    "data": {
-        "device": "floppy0",
-        "tray-open": true
-    }
-}
 
 
 === blockdev_add/device_add and device_del ===
@@ -571,7 +538,7 @@ Testing:
             "device": "floppy0",
             "locked": false,
             "removable": true,
-            "tray_open": false,
+            "tray_open": true,
             "type": "unknown"
         },
         {
@@ -681,7 +648,7 @@ Testing:
             "device": "floppy0",
             "locked": false,
             "removable": true,
-            "tray_open": false,
+            "tray_open": true,
             "type": "unknown"
         },
         {
@@ -760,16 +727,5 @@ Testing:
         "tray-open": true
     }
 }
-{
-    "timestamp": {
-        "seconds":  TIMESTAMP,
-        "microseconds":  TIMESTAMP
-    },
-    "event": "DEVICE_TRAY_MOVED",
-    "data": {
-        "device": "floppy0",
-        "tray-open": true
-    }
-}
 
 *** done
diff --git a/tests/qemu-iotests/071.out b/tests/qemu-iotests/071.out
index c8ecfaf..904ce15 100644
--- a/tests/qemu-iotests/071.out
+++ b/tests/qemu-iotests/071.out
@@ -52,7 +52,6 @@ read failed: Input/output error
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
 QEMU_PROG: Failed to flush the L2 table cache: Input/output error
 QEMU_PROG: Failed to flush the refcount block cache: Input/output error
 
@@ -95,7 +94,6 @@ read failed: Input/output error
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
 QEMU_PROG: Failed to flush the L2 table cache: Input/output error
 QEMU_PROG: Failed to flush the refcount block cache: Input/output error
 
diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out
index 2375916..b1e4909 100644
--- a/tests/qemu-iotests/081.out
+++ b/tests/qemu-iotests/081.out
@@ -38,7 +38,6 @@ read 10485760/10485760 bytes at offset 0
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
 
 
 == using quorum rewrite corrupted mode ==
diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out
index b0aa06d..55f4951 100644
--- a/tests/qemu-iotests/087.out
+++ b/tests/qemu-iotests/087.out
@@ -10,7 +10,6 @@ QMP_VERSION
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
 
 
 === Duplicate ID ===
@@ -27,7 +26,6 @@ QMP_VERSION
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
 
 
 === aio=native without O_DIRECT ===
@@ -39,7 +37,6 @@ QMP_VERSION
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
 
 
 === Encrypted image ===
@@ -52,7 +49,6 @@ QMP_VERSION
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
 
 Testing:
 QMP_VERSION
@@ -61,7 +57,6 @@ QMP_VERSION
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
 
 
 === Missing driver ===
@@ -74,6 +69,5 @@ QMP_VERSION
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
 
 *** done
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 04/37] hw/usb-storage: Check whether BB is inserted
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (2 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 03/37] hw/block/fdc: Implement tray status Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-03-04 14:02   ` Kevin Wolf
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 05/37] block: Fix BB AIOCB AioContext without BDS Max Reitz
                   ` (32 subsequent siblings)
  36 siblings, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

Only call bdrv_key_required() on the BlockDriverState if the
BlockBackend has an inserted medium.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 hw/usb/dev-storage.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index 4539733..3123baf 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -638,7 +638,7 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
     usb_msd_handle_reset(dev);
     s->scsi_dev = scsi_dev;
 
-    if (bdrv_key_required(blk_bs(blk))) {
+    if (blk_is_inserted(blk) && bdrv_key_required(blk_bs(blk))) {
         if (cur_mon) {
             monitor_read_bdrv_key_start(cur_mon, blk_bs(blk),
                                         usb_msd_password_cb, s);
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 05/37] block: Fix BB AIOCB AioContext without BDS
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (3 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 04/37] hw/usb-storage: Check whether BB is inserted Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 06/37] block: Make bdrv_is_inserted() return a bool Max Reitz
                   ` (31 subsequent siblings)
  36 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

Fix the BlockBackend's AIOCB AioContext for aborting AIO in case there
is no BDS. If there is no implementation of AIOCBInfo::get_aio_context()
the AioContext is derived from the BDS the AIOCB belongs to. If that BDS
is NULL (because it has been removed from the BB) this will not work.

This patch makes blk_get_aio_context() fall back to the main loop
context if the BDS pointer is NULL and implements
AIOCBInfo::get_aio_context() (blk_aiocb_get_aio_context()) which invokes
blk_get_aio_context().

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/block-backend.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index c0a39bb..ff21610 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -18,6 +18,8 @@
 /* Number of coroutines to reserve per attached device model */
 #define COROUTINE_POOL_RESERVATION 64
 
+static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb);
+
 struct BlockBackend {
     char *name;
     int refcnt;
@@ -34,10 +36,12 @@ struct BlockBackend {
 typedef struct BlockBackendAIOCB {
     BlockAIOCB common;
     QEMUBH *bh;
+    BlockBackend *blk;
     int ret;
 } BlockBackendAIOCB;
 
 static const AIOCBInfo block_backend_aiocb_info = {
+    .get_aio_context = blk_aiocb_get_aio_context,
     .aiocb_size = sizeof(BlockBackendAIOCB),
 };
 
@@ -530,6 +534,7 @@ static BlockAIOCB *abort_aio_request(BlockBackend *blk, BlockCompletionFunc *cb,
     QEMUBH *bh;
 
     acb = blk_aio_get(&block_backend_aiocb_info, blk, cb, opaque);
+    acb->blk = blk;
     acb->ret = ret;
 
     bh = aio_bh_new(blk_get_aio_context(blk), error_callback_bh, acb);
@@ -793,7 +798,17 @@ void blk_op_unblock_all(BlockBackend *blk, Error *reason)
 
 AioContext *blk_get_aio_context(BlockBackend *blk)
 {
-    return bdrv_get_aio_context(blk->bs);
+    if (blk->bs) {
+        return bdrv_get_aio_context(blk->bs);
+    } else {
+        return qemu_get_aio_context();
+    }
+}
+
+static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
+{
+    BlockBackendAIOCB *blk_acb = DO_UPCAST(BlockBackendAIOCB, common, acb);
+    return blk_get_aio_context(blk_acb->blk);
 }
 
 void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 06/37] block: Make bdrv_is_inserted() return a bool
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (4 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 05/37] block: Fix BB AIOCB AioContext without BDS Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 18:29   ` Eric Blake
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 07/37] block: Add blk_is_available() Max Reitz
                   ` (30 subsequent siblings)
  36 siblings, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

Make bdrv_is_inserted(), blk_is_inserted(), and the callback
BlockDriver.bdrv_is_inserted() return a bool.

Suggested-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 block.c                        | 12 +++++++-----
 block/block-backend.c          |  2 +-
 block/raw-posix.c              | 10 ++++------
 block/raw_bsd.c                |  2 +-
 include/block/block.h          |  2 +-
 include/block/block_int.h      |  2 +-
 include/sysemu/block-backend.h |  2 +-
 7 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/block.c b/block.c
index 9b707e3..ee7dfba 100644
--- a/block.c
+++ b/block.c
@@ -5230,14 +5230,16 @@ int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors)
 /**
  * Return TRUE if the media is present
  */
-int bdrv_is_inserted(BlockDriverState *bs)
+bool bdrv_is_inserted(BlockDriverState *bs)
 {
     BlockDriver *drv = bs->drv;
 
-    if (!drv)
-        return 0;
-    if (!drv->bdrv_is_inserted)
-        return 1;
+    if (!drv) {
+        return false;
+    }
+    if (!drv->bdrv_is_inserted) {
+        return true;
+    }
     return drv->bdrv_is_inserted(bs);
 }
 
diff --git a/block/block-backend.c b/block/block-backend.c
index ff21610..5cec6d9 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -741,7 +741,7 @@ void blk_invalidate_cache(BlockBackend *blk, Error **errp)
     bdrv_invalidate_cache(blk->bs, errp);
 }
 
-int blk_is_inserted(BlockBackend *blk)
+bool blk_is_inserted(BlockBackend *blk)
 {
     return bdrv_is_inserted(blk->bs);
 }
diff --git a/block/raw-posix.c b/block/raw-posix.c
index b5f077a..4034300 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -2274,7 +2274,7 @@ out:
 }
 
 
-static int floppy_is_inserted(BlockDriverState *bs)
+static bool floppy_is_inserted(BlockDriverState *bs)
 {
     return fd_open(bs) >= 0;
 }
@@ -2408,15 +2408,13 @@ out:
     return prio;
 }
 
-static int cdrom_is_inserted(BlockDriverState *bs)
+static bool cdrom_is_inserted(BlockDriverState *bs)
 {
     BDRVRawState *s = bs->opaque;
     int ret;
 
     ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
-    if (ret == CDS_DISC_OK)
-        return 1;
-    return 0;
+    return ret == CDS_DISC_OK;
 }
 
 static void cdrom_eject(BlockDriverState *bs, bool eject_flag)
@@ -2542,7 +2540,7 @@ static int cdrom_reopen(BlockDriverState *bs)
     return 0;
 }
 
-static int cdrom_is_inserted(BlockDriverState *bs)
+static bool cdrom_is_inserted(BlockDriverState *bs)
 {
     return raw_getlength(bs) > 0;
 }
diff --git a/block/raw_bsd.c b/block/raw_bsd.c
index 05b02c7..0a76cbc 100644
--- a/block/raw_bsd.c
+++ b/block/raw_bsd.c
@@ -154,7 +154,7 @@ static int raw_truncate(BlockDriverState *bs, int64_t offset)
     return bdrv_truncate(bs->file, offset);
 }
 
-static int raw_is_inserted(BlockDriverState *bs)
+static bool raw_is_inserted(BlockDriverState *bs)
 {
     return bdrv_is_inserted(bs->file);
 }
diff --git a/include/block/block.h b/include/block/block.h
index 471d11d..e0eec19 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -365,7 +365,7 @@ int bdrv_is_read_only(BlockDriverState *bs);
 int bdrv_is_sg(BlockDriverState *bs);
 int bdrv_enable_write_cache(BlockDriverState *bs);
 void bdrv_set_enable_write_cache(BlockDriverState *bs, bool wce);
-int bdrv_is_inserted(BlockDriverState *bs);
+bool bdrv_is_inserted(BlockDriverState *bs);
 int bdrv_media_changed(BlockDriverState *bs);
 void bdrv_lock_medium(BlockDriverState *bs, bool locked);
 void bdrv_eject(BlockDriverState *bs, bool eject_flag);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index b340e7e..7dc0c91 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -213,7 +213,7 @@ struct BlockDriver {
         const char *backing_file, const char *backing_fmt);
 
     /* removable device specific */
-    int (*bdrv_is_inserted)(BlockDriverState *bs);
+    bool (*bdrv_is_inserted)(BlockDriverState *bs);
     int (*bdrv_media_changed)(BlockDriverState *bs);
     void (*bdrv_eject)(BlockDriverState *bs, bool eject_flag);
     void (*bdrv_lock_medium)(BlockDriverState *bs, bool locked);
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 2e8ebb2..f60949a 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -127,7 +127,7 @@ int blk_is_sg(BlockBackend *blk);
 int blk_enable_write_cache(BlockBackend *blk);
 void blk_set_enable_write_cache(BlockBackend *blk, bool wce);
 void blk_invalidate_cache(BlockBackend *blk, Error **errp);
-int blk_is_inserted(BlockBackend *blk);
+bool blk_is_inserted(BlockBackend *blk);
 void blk_lock_medium(BlockBackend *blk, bool locked);
 void blk_eject(BlockBackend *blk, bool eject_flag);
 int blk_get_flags(BlockBackend *blk);
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 07/37] block: Add blk_is_available()
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (5 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 06/37] block: Make bdrv_is_inserted() return a bool Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 08/37] block: Make bdrv_is_inserted() recursive Max Reitz
                   ` (29 subsequent siblings)
  36 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

blk_is_available() returns true iff the BDS is inserted (which means
blk_bs() is not NULL and bdrv_is_inserted() returns true) and if the
tray of the guest device is closed.

blk_is_inserted() is changed to return true only if blk_bs() is not
NULL.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/block-backend.c          | 7 ++++++-
 include/sysemu/block-backend.h | 1 +
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 5cec6d9..9299697 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -743,7 +743,12 @@ void blk_invalidate_cache(BlockBackend *blk, Error **errp)
 
 bool blk_is_inserted(BlockBackend *blk)
 {
-    return bdrv_is_inserted(blk->bs);
+    return blk->bs && bdrv_is_inserted(blk->bs);
+}
+
+bool blk_is_available(BlockBackend *blk)
+{
+    return blk_is_inserted(blk) && !blk_dev_is_tray_open(blk);
 }
 
 void blk_lock_medium(BlockBackend *blk, bool locked)
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index f60949a..ce96912 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -128,6 +128,7 @@ int blk_enable_write_cache(BlockBackend *blk);
 void blk_set_enable_write_cache(BlockBackend *blk, bool wce);
 void blk_invalidate_cache(BlockBackend *blk, Error **errp);
 bool blk_is_inserted(BlockBackend *blk);
+bool blk_is_available(BlockBackend *blk);
 void blk_lock_medium(BlockBackend *blk, bool locked);
 void blk_eject(BlockBackend *blk, bool eject_flag);
 int blk_get_flags(BlockBackend *blk);
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 08/37] block: Make bdrv_is_inserted() recursive
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (6 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 07/37] block: Add blk_is_available() Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 19:16   ` Eric Blake
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 09/37] block/quorum: Implement bdrv_is_inserted() Max Reitz
                   ` (28 subsequent siblings)
  36 siblings, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

If bdrv_is_inserted() is called on the top level BDS, it should make
sure all nodes in the BDS tree are actually inserted.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 block.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/block.c b/block.c
index ee7dfba..dafa4b7 100644
--- a/block.c
+++ b/block.c
@@ -5237,10 +5237,9 @@ bool bdrv_is_inserted(BlockDriverState *bs)
     if (!drv) {
         return false;
     }
-    if (!drv->bdrv_is_inserted) {
-        return true;
-    }
-    return drv->bdrv_is_inserted(bs);
+    return (!drv->bdrv_is_inserted || drv->bdrv_is_inserted(bs)) &&
+           (!bs->file              || bdrv_is_inserted(bs->file)) &&
+           (!bs->backing_hd        || bdrv_is_inserted(bs->backing_hd));
 }
 
 /**
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 09/37] block/quorum: Implement bdrv_is_inserted()
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (7 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 08/37] block: Make bdrv_is_inserted() recursive Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 10/37] block: Move guest_block_size into BlockBackend Max Reitz
                   ` (27 subsequent siblings)
  36 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

bdrv_is_inserted() should be invoked recursively on the children of
quorum.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/quorum.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/block/quorum.c b/block/quorum.c
index 437b122..7a75cea 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -1064,6 +1064,20 @@ static void quorum_refresh_filename(BlockDriverState *bs)
     bs->full_open_options = opts;
 }
 
+static bool quorum_is_inserted(BlockDriverState *bs)
+{
+    BDRVQuorumState *s = bs->opaque;
+    int i;
+
+    for (i = 0; i < s->num_children; i++) {
+        if (!bdrv_is_inserted(s->bs[i])) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
 static BlockDriver bdrv_quorum = {
     .format_name                        = "quorum",
     .protocol_name                      = "quorum",
@@ -1087,6 +1101,8 @@ static BlockDriver bdrv_quorum = {
 
     .is_filter                          = true,
     .bdrv_recurse_is_first_non_filter   = quorum_recurse_is_first_non_filter,
+
+    .bdrv_is_inserted                   = quorum_is_inserted,
 };
 
 static void bdrv_quorum_init(void)
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 10/37] block: Move guest_block_size into BlockBackend
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (8 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 09/37] block/quorum: Implement bdrv_is_inserted() Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 11/37] block: Remove wr_highest_sector from BlockAcctStats Max Reitz
                   ` (26 subsequent siblings)
  36 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

guest_block_size is a guest device property so it should be moved into
the interface between block layer and guest devices, which is the
BlockBackend.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block.c                   | 7 -------
 block/block-backend.c     | 7 +++++--
 include/block/block.h     | 1 -
 include/block/block_int.h | 3 ---
 4 files changed, 5 insertions(+), 13 deletions(-)

diff --git a/block.c b/block.c
index dafa4b7..7de03e5 100644
--- a/block.c
+++ b/block.c
@@ -967,7 +967,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
     }
 
     bs->open_flags = flags;
-    bs->guest_block_size = 512;
     bs->request_alignment = 512;
     bs->zero_beyond_eof = true;
     open_flags = bdrv_open_flags(bs, flags);
@@ -2040,7 +2039,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
     /* move some fields that need to stay attached to the device */
 
     /* dev info */
-    bs_dest->guest_block_size   = bs_src->guest_block_size;
     bs_dest->copy_on_read       = bs_src->copy_on_read;
 
     bs_dest->enable_write_cache = bs_src->enable_write_cache;
@@ -5312,11 +5310,6 @@ BlockAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
     return NULL;
 }
 
-void bdrv_set_guest_block_size(BlockDriverState *bs, int align)
-{
-    bs->guest_block_size = align;
-}
-
 void *qemu_blockalign(BlockDriverState *bs, size_t size)
 {
     return qemu_memalign(bdrv_opt_mem_align(bs), size);
diff --git a/block/block-backend.c b/block/block-backend.c
index 9299697..bcea1f2 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -31,6 +31,9 @@ struct BlockBackend {
     /* TODO change to DeviceState when all users are qdevified */
     const BlockDevOps *dev_ops;
     void *dev_opaque;
+
+    /* the block size for which the guest device expects atomicity */
+    int guest_block_size;
 };
 
 typedef struct BlockBackendAIOCB {
@@ -334,7 +337,7 @@ void blk_detach_dev(BlockBackend *blk, void *dev)
     blk->dev = NULL;
     blk->dev_ops = NULL;
     blk->dev_opaque = NULL;
-    bdrv_set_guest_block_size(blk->bs, 512);
+    blk->guest_block_size = 512;
     blk_unref(blk);
 }
 
@@ -773,7 +776,7 @@ int blk_get_max_transfer_length(BlockBackend *blk)
 
 void blk_set_guest_block_size(BlockBackend *blk, int align)
 {
-    bdrv_set_guest_block_size(blk->bs, align);
+    blk->guest_block_size = align;
 }
 
 void *blk_blockalign(BlockBackend *blk, size_t size)
diff --git a/include/block/block.h b/include/block/block.h
index e0eec19..859e539 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -430,7 +430,6 @@ void bdrv_img_create(const char *filename, const char *fmt,
 /* Returns the alignment in bytes that is required so that no bounce buffer
  * is required throughout the stack */
 size_t bdrv_opt_mem_align(BlockDriverState *bs);
-void bdrv_set_guest_block_size(BlockDriverState *bs, int align);
 void *qemu_blockalign(BlockDriverState *bs, size_t size);
 void *qemu_blockalign0(BlockDriverState *bs, size_t size);
 void *qemu_try_blockalign(BlockDriverState *bs, size_t size);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 7dc0c91..4e7945c 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -375,9 +375,6 @@ struct BlockDriverState {
     /* Alignment requirement for offset/length of I/O requests */
     unsigned int request_alignment;
 
-    /* the block size for which the guest device expects atomicity */
-    int guest_block_size;
-
     /* do we need to tell the quest if we have a volatile write cache? */
     int enable_write_cache;
 
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 11/37] block: Remove wr_highest_sector from BlockAcctStats
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (9 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 10/37] block: Move guest_block_size into BlockBackend Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 19:20   ` Eric Blake
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 12/37] block: Move BlockAcctStats into BlockBackend Max Reitz
                   ` (25 subsequent siblings)
  36 siblings, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

BlockAcctStats contains statistics about the data transferred from and
to the device; wr_highest_sector does not fit in with the rest.

Furthermore, those statistics are supposed to be specific for a certain
device and not necessarily for a BDS (see the comment above
bdrv_get_stats()); on the other hand, wr_highest_sector may be a rather
important information to know for each BDS. When BlockAcctStats is
finally removed from the BDS, we will want to keep wr_highest_sector in
the BDS.

Finally, wr_highest_sector is renamed to wr_highest_offset and given the
appropriate meaning. Externally, it is represented as an offset so there
is no point in doing something different internally. Its definition is
changed to match that in qapi/block-core.json which is "the offset after
the greatest byte written to". Doing so should not cause any harm since
if external programs tried to calculate the volume usage by
(wr_highest_offset + 512) / volume_size, after this patch they will just
assume the volume to be full slightly earlier than before.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 block.c                    | 4 +++-
 block/accounting.c         | 8 --------
 block/qapi.c               | 4 ++--
 include/block/accounting.h | 3 ---
 include/block/block_int.h  | 3 +++
 qmp-commands.hx            | 4 ++--
 6 files changed, 10 insertions(+), 16 deletions(-)

diff --git a/block.c b/block.c
index 7de03e5..4f924c6 100644
--- a/block.c
+++ b/block.c
@@ -3311,7 +3311,9 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
 
     bdrv_set_dirty(bs, sector_num, nb_sectors);
 
-    block_acct_highest_sector(&bs->stats, sector_num, nb_sectors);
+    if (bs->wr_highest_offset < offset + bytes) {
+        bs->wr_highest_offset = offset + bytes;
+    }
 
     if (ret >= 0) {
         bs->total_sectors = MAX(bs->total_sectors, sector_num + nb_sectors);
diff --git a/block/accounting.c b/block/accounting.c
index 01d594f..a423560 100644
--- a/block/accounting.c
+++ b/block/accounting.c
@@ -47,14 +47,6 @@ void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie)
 }
 
 
-void block_acct_highest_sector(BlockAcctStats *stats, int64_t sector_num,
-                               unsigned int nb_sectors)
-{
-    if (stats->wr_highest_sector < sector_num + nb_sectors - 1) {
-        stats->wr_highest_sector = sector_num + nb_sectors - 1;
-    }
-}
-
 void block_acct_merge_done(BlockAcctStats *stats, enum BlockAcctType type,
                       int num_requests)
 {
diff --git a/block/qapi.c b/block/qapi.c
index 1808e67..9b27658 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -340,13 +340,13 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs,
     s->stats->wr_operations = bs->stats.nr_ops[BLOCK_ACCT_WRITE];
     s->stats->rd_merged = bs->stats.merged[BLOCK_ACCT_READ];
     s->stats->wr_merged = bs->stats.merged[BLOCK_ACCT_WRITE];
-    s->stats->wr_highest_offset =
-        bs->stats.wr_highest_sector * BDRV_SECTOR_SIZE;
     s->stats->flush_operations = bs->stats.nr_ops[BLOCK_ACCT_FLUSH];
     s->stats->wr_total_time_ns = bs->stats.total_time_ns[BLOCK_ACCT_WRITE];
     s->stats->rd_total_time_ns = bs->stats.total_time_ns[BLOCK_ACCT_READ];
     s->stats->flush_total_time_ns = bs->stats.total_time_ns[BLOCK_ACCT_FLUSH];
 
+    s->stats->wr_highest_offset = bs->wr_highest_offset;
+
     if (bs->file) {
         s->has_parent = true;
         s->parent = bdrv_query_stats(bs->file, query_backing);
diff --git a/include/block/accounting.h b/include/block/accounting.h
index 4c406cf..66637cd 100644
--- a/include/block/accounting.h
+++ b/include/block/accounting.h
@@ -40,7 +40,6 @@ typedef struct BlockAcctStats {
     uint64_t nr_ops[BLOCK_MAX_IOTYPE];
     uint64_t total_time_ns[BLOCK_MAX_IOTYPE];
     uint64_t merged[BLOCK_MAX_IOTYPE];
-    uint64_t wr_highest_sector;
 } BlockAcctStats;
 
 typedef struct BlockAcctCookie {
@@ -52,8 +51,6 @@ typedef struct BlockAcctCookie {
 void block_acct_start(BlockAcctStats *stats, BlockAcctCookie *cookie,
                       int64_t bytes, enum BlockAcctType type);
 void block_acct_done(BlockAcctStats *stats, BlockAcctCookie *cookie);
-void block_acct_highest_sector(BlockAcctStats *stats, int64_t sector_num,
-                               unsigned int nb_sectors);
 void block_acct_merge_done(BlockAcctStats *stats, enum BlockAcctType type,
                            int num_requests);
 
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 4e7945c..098d1ab 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -366,6 +366,9 @@ struct BlockDriverState {
     /* I/O stats (display with "info blockstats"). */
     BlockAcctStats stats;
 
+    /* Offset after the highest byte written to */
+    uint64_t wr_highest_offset;
+
     /* I/O Limits */
     BlockLimits bl;
 
diff --git a/qmp-commands.hx b/qmp-commands.hx
index a85d847..9001792 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2304,8 +2304,8 @@ Each json-object contain the following:
     - "wr_total_time_ns": total time spend on writes in nano-seconds (json-int)
     - "rd_total_time_ns": total time spend on reads in nano-seconds (json-int)
     - "flush_total_time_ns": total time spend on cache flushes in nano-seconds (json-int)
-    - "wr_highest_offset": Highest offset of a sector written since the
-                           BlockDriverState has been opened (json-int)
+    - "wr_highest_offset": The offset after the greatest byte written to the
+                           BlockDriverState since it has been opened (json-int)
     - "rd_merged": number of read requests that have been merged into
                    another request (json-int)
     - "wr_merged": number of write requests that have been merged into
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 12/37] block: Move BlockAcctStats into BlockBackend
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (10 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 11/37] block: Remove wr_highest_sector from BlockAcctStats Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 13/37] block: Move I/O status and error actions into BB Max Reitz
                   ` (24 subsequent siblings)
  36 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

As the comment above bdrv_get_stats() says, BlockAcctStats is something
which belongs to the device instead of each BlockDriverState. This patch
therefore moves it into the BlockBackend.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block.c                   | 16 ++++------------
 block/block-backend.c     |  5 ++++-
 block/qapi.c              | 24 ++++++++++++++----------
 include/block/block.h     |  2 --
 include/block/block_int.h |  3 ---
 5 files changed, 22 insertions(+), 28 deletions(-)

diff --git a/block.c b/block.c
index 4f924c6..6a1e791 100644
--- a/block.c
+++ b/block.c
@@ -4587,7 +4587,10 @@ static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs,
         }
     }
 
-    block_acct_merge_done(&bs->stats, BLOCK_ACCT_WRITE, num_reqs - outidx - 1);
+    if (bs->blk) {
+        block_acct_merge_done(blk_get_stats(bs->blk), BLOCK_ACCT_WRITE,
+                              num_reqs - outidx - 1);
+    }
 
     return outidx + 1;
 }
@@ -6144,14 +6147,3 @@ void bdrv_refresh_filename(BlockDriverState *bs)
         QDECREF(json);
     }
 }
-
-/* This accessor function purpose is to allow the device models to access the
- * BlockAcctStats structure embedded inside a BlockDriverState without being
- * aware of the BlockDriverState structure layout.
- * It will go away when the BlockAcctStats structure will be moved inside
- * the device models.
- */
-BlockAcctStats *bdrv_get_stats(BlockDriverState *bs)
-{
-    return &bs->stats;
-}
diff --git a/block/block-backend.c b/block/block-backend.c
index bcea1f2..3168c7b 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -34,6 +34,9 @@ struct BlockBackend {
 
     /* the block size for which the guest device expects atomicity */
     int guest_block_size;
+
+    /* I/O stats (display with "info blockstats"). */
+    BlockAcctStats stats;
 };
 
 typedef struct BlockBackendAIOCB {
@@ -859,7 +862,7 @@ void blk_io_unplug(BlockBackend *blk)
 
 BlockAcctStats *blk_get_stats(BlockBackend *blk)
 {
-    return bdrv_get_stats(blk->bs);
+    return &blk->stats;
 }
 
 void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk,
diff --git a/block/qapi.c b/block/qapi.c
index 9b27658..25715ab 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -334,16 +334,20 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs,
     }
 
     s->stats = g_malloc0(sizeof(*s->stats));
-    s->stats->rd_bytes = bs->stats.nr_bytes[BLOCK_ACCT_READ];
-    s->stats->wr_bytes = bs->stats.nr_bytes[BLOCK_ACCT_WRITE];
-    s->stats->rd_operations = bs->stats.nr_ops[BLOCK_ACCT_READ];
-    s->stats->wr_operations = bs->stats.nr_ops[BLOCK_ACCT_WRITE];
-    s->stats->rd_merged = bs->stats.merged[BLOCK_ACCT_READ];
-    s->stats->wr_merged = bs->stats.merged[BLOCK_ACCT_WRITE];
-    s->stats->flush_operations = bs->stats.nr_ops[BLOCK_ACCT_FLUSH];
-    s->stats->wr_total_time_ns = bs->stats.total_time_ns[BLOCK_ACCT_WRITE];
-    s->stats->rd_total_time_ns = bs->stats.total_time_ns[BLOCK_ACCT_READ];
-    s->stats->flush_total_time_ns = bs->stats.total_time_ns[BLOCK_ACCT_FLUSH];
+    if (bs->blk) {
+        BlockAcctStats *stats = blk_get_stats(bs->blk);
+
+        s->stats->rd_bytes = stats->nr_bytes[BLOCK_ACCT_READ];
+        s->stats->wr_bytes = stats->nr_bytes[BLOCK_ACCT_WRITE];
+        s->stats->rd_operations = stats->nr_ops[BLOCK_ACCT_READ];
+        s->stats->wr_operations = stats->nr_ops[BLOCK_ACCT_WRITE];
+        s->stats->rd_merged = stats->merged[BLOCK_ACCT_READ];
+        s->stats->wr_merged = stats->merged[BLOCK_ACCT_WRITE];
+        s->stats->flush_operations = stats->nr_ops[BLOCK_ACCT_FLUSH];
+        s->stats->wr_total_time_ns = stats->total_time_ns[BLOCK_ACCT_WRITE];
+        s->stats->rd_total_time_ns = stats->total_time_ns[BLOCK_ACCT_READ];
+        s->stats->flush_total_time_ns = stats->total_time_ns[BLOCK_ACCT_FLUSH];
+    }
 
     s->stats->wr_highest_offset = bs->wr_highest_offset;
 
diff --git a/include/block/block.h b/include/block/block.h
index 859e539..358bfb9 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -555,6 +555,4 @@ void bdrv_io_plug(BlockDriverState *bs);
 void bdrv_io_unplug(BlockDriverState *bs);
 void bdrv_flush_io_queue(BlockDriverState *bs);
 
-BlockAcctStats *bdrv_get_stats(BlockDriverState *bs);
-
 #endif
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 098d1ab..fd3a54c 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -363,9 +363,6 @@ struct BlockDriverState {
     CoQueue      throttled_reqs[2];
     bool         io_limits_enabled;
 
-    /* I/O stats (display with "info blockstats"). */
-    BlockAcctStats stats;
-
     /* Offset after the highest byte written to */
     uint64_t wr_highest_offset;
 
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 13/37] block: Move I/O status and error actions into BB
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (11 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 12/37] block: Move BlockAcctStats into BlockBackend Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 14/37] block: Add BlockBackendRootState Max Reitz
                   ` (23 subsequent siblings)
  36 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

These options are only relevant for the user of a whole BDS tree (like a
guest device or a block job) and should thus be moved into the
BlockBackend.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block.c                        | 125 -----------------------------------------
 block/backup.c                 |  17 ++++--
 block/block-backend.c          | 116 ++++++++++++++++++++++++++++++++++++--
 block/commit.c                 |   3 +-
 block/mirror.c                 |  17 ++++--
 block/qapi.c                   |   4 +-
 block/stream.c                 |   3 +-
 blockdev.c                     |   6 +-
 blockjob.c                     |   5 +-
 include/block/block.h          |  11 ----
 include/block/block_int.h      |   6 --
 include/sysemu/block-backend.h |   7 +++
 qmp.c                          |   6 +-
 13 files changed, 158 insertions(+), 168 deletions(-)

diff --git a/block.c b/block.c
index 6a1e791..06e334a 100644
--- a/block.c
+++ b/block.c
@@ -371,7 +371,6 @@ BlockDriverState *bdrv_new(void)
     for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
         QLIST_INIT(&bs->op_blockers[i]);
     }
-    bdrv_iostatus_disable(bs);
     notifier_list_init(&bs->close_notifiers);
     notifier_with_return_list_init(&bs->before_write_notifiers);
     qemu_co_queue_init(&bs->throttled_reqs[0]);
@@ -2051,14 +2050,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
     bs_dest->throttled_reqs[1]  = bs_src->throttled_reqs[1];
     bs_dest->io_limits_enabled  = bs_src->io_limits_enabled;
 
-    /* r/w error */
-    bs_dest->on_read_error      = bs_src->on_read_error;
-    bs_dest->on_write_error     = bs_src->on_write_error;
-
-    /* i/o status */
-    bs_dest->iostatus_enabled   = bs_src->iostatus_enabled;
-    bs_dest->iostatus           = bs_src->iostatus;
-
     /* dirty bitmap */
     bs_dest->dirty_bitmaps      = bs_src->dirty_bitmaps;
 
@@ -3561,82 +3552,6 @@ void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr)
     *nb_sectors_ptr = nb_sectors < 0 ? 0 : nb_sectors;
 }
 
-void bdrv_set_on_error(BlockDriverState *bs, BlockdevOnError on_read_error,
-                       BlockdevOnError on_write_error)
-{
-    bs->on_read_error = on_read_error;
-    bs->on_write_error = on_write_error;
-}
-
-BlockdevOnError bdrv_get_on_error(BlockDriverState *bs, bool is_read)
-{
-    return is_read ? bs->on_read_error : bs->on_write_error;
-}
-
-BlockErrorAction bdrv_get_error_action(BlockDriverState *bs, bool is_read, int error)
-{
-    BlockdevOnError on_err = is_read ? bs->on_read_error : bs->on_write_error;
-
-    switch (on_err) {
-    case BLOCKDEV_ON_ERROR_ENOSPC:
-        return (error == ENOSPC) ?
-               BLOCK_ERROR_ACTION_STOP : BLOCK_ERROR_ACTION_REPORT;
-    case BLOCKDEV_ON_ERROR_STOP:
-        return BLOCK_ERROR_ACTION_STOP;
-    case BLOCKDEV_ON_ERROR_REPORT:
-        return BLOCK_ERROR_ACTION_REPORT;
-    case BLOCKDEV_ON_ERROR_IGNORE:
-        return BLOCK_ERROR_ACTION_IGNORE;
-    default:
-        abort();
-    }
-}
-
-static void send_qmp_error_event(BlockDriverState *bs,
-                                 BlockErrorAction action,
-                                 bool is_read, int error)
-{
-    IoOperationType optype;
-
-    optype = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE;
-    qapi_event_send_block_io_error(bdrv_get_device_name(bs), optype, action,
-                                   bdrv_iostatus_is_enabled(bs),
-                                   error == ENOSPC, strerror(error),
-                                   &error_abort);
-}
-
-/* This is done by device models because, while the block layer knows
- * about the error, it does not know whether an operation comes from
- * the device or the block layer (from a job, for example).
- */
-void bdrv_error_action(BlockDriverState *bs, BlockErrorAction action,
-                       bool is_read, int error)
-{
-    assert(error >= 0);
-
-    if (action == BLOCK_ERROR_ACTION_STOP) {
-        /* First set the iostatus, so that "info block" returns an iostatus
-         * that matches the events raised so far (an additional error iostatus
-         * is fine, but not a lost one).
-         */
-        bdrv_iostatus_set_err(bs, error);
-
-        /* Then raise the request to stop the VM and the event.
-         * qemu_system_vmstop_request_prepare has two effects.  First,
-         * it ensures that the STOP event always comes after the
-         * BLOCK_IO_ERROR event.  Second, it ensures that even if management
-         * can observe the STOP event and do a "cont" before the STOP
-         * event is issued, the VM will not stop.  In this case, vm_start()
-         * also ensures that the STOP/RESUME pair of events is emitted.
-         */
-        qemu_system_vmstop_request_prepare();
-        send_qmp_error_event(bs, action, is_read, error);
-        qemu_system_vmstop_request(RUN_STATE_IO_ERROR);
-    } else {
-        send_qmp_error_event(bs, action, is_read, error);
-    }
-}
-
 int bdrv_is_read_only(BlockDriverState *bs)
 {
     return bs->read_only;
@@ -5565,46 +5480,6 @@ bool bdrv_op_blocker_is_empty(BlockDriverState *bs)
     return true;
 }
 
-void bdrv_iostatus_enable(BlockDriverState *bs)
-{
-    bs->iostatus_enabled = true;
-    bs->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
-}
-
-/* The I/O status is only enabled if the drive explicitly
- * enables it _and_ the VM is configured to stop on errors */
-bool bdrv_iostatus_is_enabled(const BlockDriverState *bs)
-{
-    return (bs->iostatus_enabled &&
-           (bs->on_write_error == BLOCKDEV_ON_ERROR_ENOSPC ||
-            bs->on_write_error == BLOCKDEV_ON_ERROR_STOP   ||
-            bs->on_read_error == BLOCKDEV_ON_ERROR_STOP));
-}
-
-void bdrv_iostatus_disable(BlockDriverState *bs)
-{
-    bs->iostatus_enabled = false;
-}
-
-void bdrv_iostatus_reset(BlockDriverState *bs)
-{
-    if (bdrv_iostatus_is_enabled(bs)) {
-        bs->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
-        if (bs->job) {
-            block_job_iostatus_reset(bs->job);
-        }
-    }
-}
-
-void bdrv_iostatus_set_err(BlockDriverState *bs, int error)
-{
-    assert(bdrv_iostatus_is_enabled(bs));
-    if (bs->iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
-        bs->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE :
-                                         BLOCK_DEVICE_IO_STATUS_FAILED;
-    }
-}
-
 void bdrv_img_create(const char *filename, const char *fmt,
                      const char *base_filename, const char *base_fmt,
                      char *options, uint64_t img_size, int flags,
diff --git a/block/backup.c b/block/backup.c
index 1c535b1..014694f 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -20,6 +20,7 @@
 #include "block/block_int.h"
 #include "block/blockjob.h"
 #include "qemu/ratelimit.h"
+#include "sysemu/block-backend.h"
 
 #define BACKUP_CLUSTER_BITS 16
 #define BACKUP_CLUSTER_SIZE (1 << BACKUP_CLUSTER_BITS)
@@ -205,7 +206,9 @@ static void backup_iostatus_reset(BlockJob *job)
 {
     BackupBlockJob *s = container_of(job, BackupBlockJob, common);
 
-    bdrv_iostatus_reset(s->target);
+    if (s->target->blk) {
+        blk_iostatus_reset(s->target->blk);
+    }
 }
 
 static const BlockJobDriver backup_job_driver = {
@@ -265,8 +268,10 @@ static void coroutine_fn backup_run(void *opaque)
     job->bitmap = hbitmap_alloc(end, 0);
 
     bdrv_set_enable_write_cache(target, true);
-    bdrv_set_on_error(target, on_target_error, on_target_error);
-    bdrv_iostatus_enable(target);
+    if (target->blk) {
+        blk_set_on_error(target->blk, on_target_error, on_target_error);
+        blk_iostatus_enable(target->blk);
+    }
 
     bdrv_add_before_write_notifier(bs, &before_write);
 
@@ -359,7 +364,9 @@ static void coroutine_fn backup_run(void *opaque)
 
     hbitmap_free(job->bitmap);
 
-    bdrv_iostatus_disable(target);
+    if (target->blk) {
+        blk_iostatus_disable(target->blk);
+    }
     bdrv_op_unblock_all(target, job->common.blocker);
 
     data = g_malloc(sizeof(*data));
@@ -387,7 +394,7 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
 
     if ((on_source_error == BLOCKDEV_ON_ERROR_STOP ||
          on_source_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
-        !bdrv_iostatus_is_enabled(bs)) {
+        (!bs->blk || !blk_iostatus_is_enabled(bs->blk))) {
         error_set(errp, QERR_INVALID_PARAMETER, "on-source-error");
         return;
     }
diff --git a/block/block-backend.c b/block/block-backend.c
index 3168c7b..1813fff 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -12,7 +12,9 @@
 
 #include "sysemu/block-backend.h"
 #include "block/block_int.h"
+#include "block/blockjob.h"
 #include "sysemu/blockdev.h"
+#include "sysemu/sysemu.h"
 #include "qapi-event.h"
 
 /* Number of coroutines to reserve per attached device model */
@@ -37,6 +39,10 @@ struct BlockBackend {
 
     /* I/O stats (display with "info blockstats"). */
     BlockAcctStats stats;
+
+    BlockdevOnError on_read_error, on_write_error;
+    bool iostatus_enabled;
+    BlockDeviceIoStatus iostatus;
 };
 
 typedef struct BlockBackendAIOCB {
@@ -313,7 +319,7 @@ int blk_attach_dev(BlockBackend *blk, void *dev)
     }
     blk_ref(blk);
     blk->dev = dev;
-    bdrv_iostatus_reset(blk->bs);
+    blk_iostatus_reset(blk);
     return 0;
 }
 
@@ -445,7 +451,47 @@ void blk_dev_resize_cb(BlockBackend *blk)
 
 void blk_iostatus_enable(BlockBackend *blk)
 {
-    bdrv_iostatus_enable(blk->bs);
+    blk->iostatus_enabled = true;
+    blk->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
+}
+
+/* The I/O status is only enabled if the drive explicitly
+ * enables it _and_ the VM is configured to stop on errors */
+bool blk_iostatus_is_enabled(const BlockBackend *blk)
+{
+    return (blk->iostatus_enabled &&
+           (blk->on_write_error == BLOCKDEV_ON_ERROR_ENOSPC ||
+            blk->on_write_error == BLOCKDEV_ON_ERROR_STOP   ||
+            blk->on_read_error == BLOCKDEV_ON_ERROR_STOP));
+}
+
+BlockDeviceIoStatus blk_iostatus(const BlockBackend *blk)
+{
+    return blk->iostatus;
+}
+
+void blk_iostatus_disable(BlockBackend *blk)
+{
+    blk->iostatus_enabled = false;
+}
+
+void blk_iostatus_reset(BlockBackend *blk)
+{
+    if (blk_iostatus_is_enabled(blk)) {
+        blk->iostatus = BLOCK_DEVICE_IO_STATUS_OK;
+        if (blk->bs && blk->bs->job) {
+            block_job_iostatus_reset(blk->bs->job);
+        }
+    }
+}
+
+void blk_iostatus_set_err(BlockBackend *blk, int error)
+{
+    assert(blk_iostatus_is_enabled(blk));
+    if (blk->iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
+        blk->iostatus = error == ENOSPC ? BLOCK_DEVICE_IO_STATUS_NOSPACE :
+                                          BLOCK_DEVICE_IO_STATUS_FAILED;
+    }
 }
 
 static int blk_check_byte_request(BlockBackend *blk, int64_t offset,
@@ -705,21 +751,81 @@ void blk_drain_all(void)
     bdrv_drain_all();
 }
 
+void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error,
+                      BlockdevOnError on_write_error)
+{
+    blk->on_read_error = on_read_error;
+    blk->on_write_error = on_write_error;
+}
+
 BlockdevOnError blk_get_on_error(BlockBackend *blk, bool is_read)
 {
-    return bdrv_get_on_error(blk->bs, is_read);
+    return is_read ? blk->on_read_error : blk->on_write_error;
 }
 
 BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read,
                                       int error)
 {
-    return bdrv_get_error_action(blk->bs, is_read, error);
+    BlockdevOnError on_err = blk_get_on_error(blk, is_read);
+
+    switch (on_err) {
+    case BLOCKDEV_ON_ERROR_ENOSPC:
+        return (error == ENOSPC) ?
+               BLOCK_ERROR_ACTION_STOP : BLOCK_ERROR_ACTION_REPORT;
+    case BLOCKDEV_ON_ERROR_STOP:
+        return BLOCK_ERROR_ACTION_STOP;
+    case BLOCKDEV_ON_ERROR_REPORT:
+        return BLOCK_ERROR_ACTION_REPORT;
+    case BLOCKDEV_ON_ERROR_IGNORE:
+        return BLOCK_ERROR_ACTION_IGNORE;
+    default:
+        abort();
+    }
 }
 
+static void send_qmp_error_event(BlockBackend *blk,
+                                 BlockErrorAction action,
+                                 bool is_read, int error)
+{
+    IoOperationType optype;
+
+    optype = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE;
+    qapi_event_send_block_io_error(blk_name(blk), optype, action,
+                                   blk_iostatus_is_enabled(blk),
+                                   error == ENOSPC, strerror(error),
+                                   &error_abort);
+}
+
+/* This is done by device models because, while the block layer knows
+ * about the error, it does not know whether an operation comes from
+ * the device or the block layer (from a job, for example).
+ */
 void blk_error_action(BlockBackend *blk, BlockErrorAction action,
                       bool is_read, int error)
 {
-    bdrv_error_action(blk->bs, action, is_read, error);
+    assert(error >= 0);
+
+    if (action == BLOCK_ERROR_ACTION_STOP) {
+        /* First set the iostatus, so that "info block" returns an iostatus
+         * that matches the events raised so far (an additional error iostatus
+         * is fine, but not a lost one).
+         */
+        blk_iostatus_set_err(blk, error);
+
+        /* Then raise the request to stop the VM and the event.
+         * qemu_system_vmstop_request_prepare has two effects.  First,
+         * it ensures that the STOP event always comes after the
+         * BLOCK_IO_ERROR event.  Second, it ensures that even if management
+         * can observe the STOP event and do a "cont" before the STOP
+         * event is issued, the VM will not stop.  In this case, vm_start()
+         * also ensures that the STOP/RESUME pair of events is emitted.
+         */
+        qemu_system_vmstop_request_prepare();
+        send_qmp_error_event(blk, action, is_read, error);
+        qemu_system_vmstop_request(RUN_STATE_IO_ERROR);
+    } else {
+        send_qmp_error_event(blk, action, is_read, error);
+    }
 }
 
 int blk_is_read_only(BlockBackend *blk)
diff --git a/block/commit.c b/block/commit.c
index cfa2bbe..77c7267 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -16,6 +16,7 @@
 #include "block/block_int.h"
 #include "block/blockjob.h"
 #include "qemu/ratelimit.h"
+#include "sysemu/block-backend.h"
 
 enum {
     /*
@@ -212,7 +213,7 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base,
 
     if ((on_error == BLOCKDEV_ON_ERROR_STOP ||
          on_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
-        !bdrv_iostatus_is_enabled(bs)) {
+        (!bs->blk || !blk_iostatus_is_enabled(bs->blk))) {
         error_setg(errp, "Invalid parameter combination");
         return;
     }
diff --git a/block/mirror.c b/block/mirror.c
index 4056164..dc19d55 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -14,6 +14,7 @@
 #include "trace.h"
 #include "block/blockjob.h"
 #include "block/block_int.h"
+#include "sysemu/block-backend.h"
 #include "qemu/ratelimit.h"
 #include "qemu/bitmap.h"
 
@@ -570,7 +571,9 @@ immediate_exit:
     g_free(s->cow_bitmap);
     g_free(s->in_flight_bitmap);
     bdrv_release_dirty_bitmap(bs, s->dirty_bitmap);
-    bdrv_iostatus_disable(s->target);
+    if (s->target->blk) {
+        blk_iostatus_disable(s->target->blk);
+    }
 
     data = g_malloc(sizeof(*data));
     data->ret = ret;
@@ -592,7 +595,9 @@ static void mirror_iostatus_reset(BlockJob *job)
 {
     MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
 
-    bdrv_iostatus_reset(s->target);
+    if (s->target->blk) {
+        blk_iostatus_reset(s->target->blk);
+    }
 }
 
 static void mirror_complete(BlockJob *job, Error **errp)
@@ -683,7 +688,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
 
     if ((on_source_error == BLOCKDEV_ON_ERROR_STOP ||
          on_source_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
-        !bdrv_iostatus_is_enabled(bs)) {
+        (!bs->blk || !blk_iostatus_is_enabled(bs->blk))) {
         error_set(errp, QERR_INVALID_PARAMETER, "on-source-error");
         return;
     }
@@ -708,8 +713,10 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
         return;
     }
     bdrv_set_enable_write_cache(s->target, true);
-    bdrv_set_on_error(s->target, on_target_error, on_target_error);
-    bdrv_iostatus_enable(s->target);
+    if (s->target->blk) {
+        blk_set_on_error(s->target->blk, on_target_error, on_target_error);
+        blk_iostatus_enable(s->target->blk);
+    }
     s->common.co = qemu_coroutine_create(mirror_run);
     trace_mirror_start(bs, s, s->common.co, opaque);
     qemu_coroutine_enter(s->common.co, s);
diff --git a/block/qapi.c b/block/qapi.c
index 25715ab..1dc415a 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -277,9 +277,9 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
         info->tray_open = blk_dev_is_tray_open(blk);
     }
 
-    if (bdrv_iostatus_is_enabled(bs)) {
+    if (blk_iostatus_is_enabled(blk)) {
         info->has_io_status = true;
-        info->io_status = bs->iostatus;
+        info->io_status = blk_iostatus(blk);
     }
 
     if (!QLIST_EMPTY(&bs->dirty_bitmaps)) {
diff --git a/block/stream.c b/block/stream.c
index a628901..728a3e9 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -15,6 +15,7 @@
 #include "block/block_int.h"
 #include "block/blockjob.h"
 #include "qemu/ratelimit.h"
+#include "sysemu/block-backend.h"
 
 enum {
     /*
@@ -249,7 +250,7 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base,
 
     if ((on_error == BLOCKDEV_ON_ERROR_STOP ||
          on_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
-        !bdrv_iostatus_is_enabled(bs)) {
+        (!bs->blk || !blk_iostatus_is_enabled(bs->blk))) {
         error_set(errp, QERR_INVALID_PARAMETER, "on-error");
         return;
     }
diff --git a/blockdev.c b/blockdev.c
index 6d67c80..c4059cc 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -545,7 +545,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
 
     bs->detect_zeroes = detect_zeroes;
 
-    bdrv_set_on_error(bs, on_read_error, on_write_error);
+    blk_set_on_error(blk, on_read_error, on_write_error);
 
     /* disk I/O throttling */
     if (throttle_enabled(&cfg)) {
@@ -1989,8 +1989,8 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
     if (blk_get_attached_dev(blk)) {
         blk_hide_on_behalf_of_do_drive_del(blk);
         /* Further I/O must not pause the guest */
-        bdrv_set_on_error(bs, BLOCKDEV_ON_ERROR_REPORT,
-                          BLOCKDEV_ON_ERROR_REPORT);
+        blk_set_on_error(blk, BLOCKDEV_ON_ERROR_REPORT,
+                         BLOCKDEV_ON_ERROR_REPORT);
     } else {
         blk_unref(blk);
     }
diff --git a/blockjob.c b/blockjob.c
index ba2255d..fa60924 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -29,6 +29,7 @@
 #include "block/block.h"
 #include "block/blockjob.h"
 #include "block/block_int.h"
+#include "sysemu/block-backend.h"
 #include "qapi/qmp/qjson.h"
 #include "block/coroutine.h"
 #include "qmp-commands.h"
@@ -337,8 +338,8 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs,
     if (action == BLOCK_ERROR_ACTION_STOP) {
         block_job_pause(job);
         block_job_iostatus_set_err(job, error);
-        if (bs != job->bs) {
-            bdrv_iostatus_set_err(bs, error);
+        if (bs->blk && bs != job->bs) {
+            blk_iostatus_set_err(bs->blk, error);
         }
     }
     return action;
diff --git a/include/block/block.h b/include/block/block.h
index 358bfb9..9e33c54 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -151,11 +151,6 @@ typedef enum BlockOpType {
     BLOCK_OP_TYPE_MAX,
 } BlockOpType;
 
-void bdrv_iostatus_enable(BlockDriverState *bs);
-void bdrv_iostatus_reset(BlockDriverState *bs);
-void bdrv_iostatus_disable(BlockDriverState *bs);
-bool bdrv_iostatus_is_enabled(const BlockDriverState *bs);
-void bdrv_iostatus_set_err(BlockDriverState *bs, int error);
 void bdrv_info_print(Monitor *mon, const QObject *data);
 void bdrv_info(Monitor *mon, QObject **ret_data);
 void bdrv_stats_print(Monitor *mon, const QObject *data);
@@ -355,12 +350,6 @@ int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
 int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
                             int64_t sector_num, int nb_sectors, int *pnum);
 
-void bdrv_set_on_error(BlockDriverState *bs, BlockdevOnError on_read_error,
-                       BlockdevOnError on_write_error);
-BlockdevOnError bdrv_get_on_error(BlockDriverState *bs, bool is_read);
-BlockErrorAction bdrv_get_error_action(BlockDriverState *bs, bool is_read, int error);
-void bdrv_error_action(BlockDriverState *bs, BlockErrorAction action,
-                       bool is_read, int error);
 int bdrv_is_read_only(BlockDriverState *bs);
 int bdrv_is_sg(BlockDriverState *bs);
 int bdrv_enable_write_cache(BlockDriverState *bs);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index fd3a54c..6441182 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -378,12 +378,6 @@ struct BlockDriverState {
     /* do we need to tell the quest if we have a volatile write cache? */
     int enable_write_cache;
 
-    /* NOTE: the following infos are only hints for real hardware
-       drivers. They are not used by the block driver */
-    BlockdevOnError on_read_error, on_write_error;
-    bool iostatus_enabled;
-    BlockDeviceIoStatus iostatus;
-
     /* the following member gives a name to every node on the bs graph. */
     char node_name[32];
     /* element of the list of named nodes building the graph */
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index ce96912..02f59dd 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -76,6 +76,11 @@ BlockDriverState *blk_bs(BlockBackend *blk);
 void blk_hide_on_behalf_of_do_drive_del(BlockBackend *blk);
 
 void blk_iostatus_enable(BlockBackend *blk);
+bool blk_iostatus_is_enabled(const BlockBackend *blk);
+BlockDeviceIoStatus blk_iostatus(const BlockBackend *blk);
+void blk_iostatus_disable(BlockBackend *blk);
+void blk_iostatus_reset(BlockBackend *blk);
+void blk_iostatus_set_err(BlockBackend *blk, int error);
 int blk_attach_dev(BlockBackend *blk, void *dev);
 void blk_attach_dev_nofail(BlockBackend *blk, void *dev);
 void blk_detach_dev(BlockBackend *blk, void *dev);
@@ -117,6 +122,8 @@ int blk_co_flush(BlockBackend *blk);
 int blk_flush(BlockBackend *blk);
 int blk_flush_all(void);
 void blk_drain_all(void);
+void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error,
+                      BlockdevOnError on_write_error);
 BlockdevOnError blk_get_on_error(BlockBackend *blk, bool is_read);
 BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read,
                                       int error);
diff --git a/qmp.c b/qmp.c
index 20a9e97..6028529 100644
--- a/qmp.c
+++ b/qmp.c
@@ -23,6 +23,7 @@
 #include "sysemu/arch_init.h"
 #include "hw/qdev.h"
 #include "sysemu/blockdev.h"
+#include "sysemu/block-backend.h"
 #include "qom/qom-qobject.h"
 #include "qapi/qmp/qobject.h"
 #include "qapi/qmp-input-visitor.h"
@@ -155,6 +156,7 @@ SpiceInfo *qmp_query_spice(Error **errp)
 void qmp_cont(Error **errp)
 {
     Error *local_err = NULL;
+    BlockBackend *blk;
     BlockDriverState *bs;
 
     if (runstate_needs_reset()) {
@@ -164,8 +166,8 @@ void qmp_cont(Error **errp)
         return;
     }
 
-    for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) {
-        bdrv_iostatus_reset(bs);
+    for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
+        blk_iostatus_reset(blk);
     }
     for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) {
         bdrv_add_key(bs, NULL, &local_err);
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 14/37] block: Add BlockBackendRootState
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (12 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 13/37] block: Move I/O status and error actions into BB Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 15/37] block: Make some BB functions fall back to BBRS Max Reitz
                   ` (22 subsequent siblings)
  36 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

This structure will store some of the state of the root BDS if the BDS
tree is removed, so that state can be restored once a new BDS tree is
inserted.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/block-backend.c          | 26 ++++++++++++++++++++++++++
 include/block/block_int.h      |  9 +++++++++
 include/qemu/typedefs.h        |  1 +
 include/sysemu/block-backend.h |  2 ++
 4 files changed, 38 insertions(+)

diff --git a/block/block-backend.c b/block/block-backend.c
index 1813fff..3ce50ea 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -37,6 +37,10 @@ struct BlockBackend {
     /* the block size for which the guest device expects atomicity */
     int guest_block_size;
 
+    /* If the BDS tree is removed, some of its options are stored here (which
+     * can be used to restore those options in the new BDS on insert) */
+    BlockBackendRootState root_state;
+
     /* I/O stats (display with "info blockstats"). */
     BlockAcctStats stats;
 
@@ -1024,3 +1028,25 @@ int blk_load_vmstate(BlockBackend *blk, uint8_t *buf, int64_t pos, int size)
 {
     return bdrv_load_vmstate(blk->bs, buf, pos, size);
 }
+
+/*
+ * Updates the BlockBackendRootState object with data from the currently
+ * attached BlockDriverState.
+ */
+void blk_update_root_state(BlockBackend *blk)
+{
+    assert(blk->bs);
+
+    blk->root_state.open_flags    = blk->bs->open_flags;
+    blk->root_state.read_only     = blk->bs->read_only;
+    blk->root_state.detect_zeroes = blk->bs->detect_zeroes;
+
+    blk->root_state.io_limits_enabled = blk->bs->io_limits_enabled;
+    throttle_get_config(&blk->bs->throttle_state,
+                        &blk->root_state.throttle_config);
+}
+
+BlockBackendRootState *blk_get_root_state(BlockBackend *blk)
+{
+    return &blk->root_state;
+}
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 6441182..8a40309 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -406,6 +406,15 @@ struct BlockDriverState {
     NotifierWithReturn write_threshold_notifier;
 };
 
+struct BlockBackendRootState {
+    int open_flags;
+    bool read_only;
+    BlockdevDetectZeroesOptions detect_zeroes;
+
+    bool io_limits_enabled;
+    ThrottleConfig throttle_config;
+};
+
 
 /* Essential block drivers which must always be statically linked into qemu, and
  * which therefore can be accessed without using bdrv_find_format() */
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index cde3314..39a95dd 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -11,6 +11,7 @@ typedef struct AddressSpace AddressSpace;
 typedef struct AioContext AioContext;
 typedef struct AudioState AudioState;
 typedef struct BlockBackend BlockBackend;
+typedef struct BlockBackendRootState BlockBackendRootState;
 typedef struct BlockDriverState BlockDriverState;
 typedef struct BusClass BusClass;
 typedef struct BusState BusState;
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 02f59dd..53fb697 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -160,6 +160,8 @@ void blk_add_close_notifier(BlockBackend *blk, Notifier *notify);
 void blk_io_plug(BlockBackend *blk);
 void blk_io_unplug(BlockBackend *blk);
 BlockAcctStats *blk_get_stats(BlockBackend *blk);
+BlockBackendRootState *blk_get_root_state(BlockBackend *blk);
+void blk_update_root_state(BlockBackend *blk);
 
 void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk,
                   BlockCompletionFunc *cb, void *opaque);
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 15/37] block: Make some BB functions fall back to BBRS
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (13 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 14/37] block: Add BlockBackendRootState Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 16/37] block: Fail requests to empty BlockBackend Max Reitz
                   ` (21 subsequent siblings)
  36 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

If there is no BDS tree attached to a BlockBackend, functions that can
do so should fall back to the BlockBackendRootState structure (which are
blk_is_read_only() and blk_get_flags(), because the read-only status and
the "open flags" are part of the BBRS).

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/block-backend.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 3ce50ea..8206360 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -834,7 +834,11 @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action,
 
 int blk_is_read_only(BlockBackend *blk)
 {
-    return bdrv_is_read_only(blk->bs);
+    if (blk->bs) {
+        return bdrv_is_read_only(blk->bs);
+    } else {
+        return blk->root_state.read_only;
+    }
 }
 
 int blk_is_sg(BlockBackend *blk)
@@ -879,7 +883,11 @@ void blk_eject(BlockBackend *blk, bool eject_flag)
 
 int blk_get_flags(BlockBackend *blk)
 {
-    return bdrv_get_flags(blk->bs);
+    if (blk->bs) {
+        return bdrv_get_flags(blk->bs);
+    } else {
+        return blk->root_state.open_flags;
+    }
 }
 
 int blk_get_max_transfer_length(BlockBackend *blk)
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 16/37] block: Fail requests to empty BlockBackend
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (14 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 15/37] block: Make some BB functions fall back to BBRS Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-25 18:18   ` Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 17/37] block: Prepare remaining BB functions for NULL BDS Max Reitz
                   ` (20 subsequent siblings)
  36 siblings, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

If there is no BlockDriverState in a BlockBackend or if the tray of the
guest device is open, fail all requests (where that is possible) with
-ENOMEDIUM.

The reason the status of the guest device is taken into account is
because once the guest device's tray is opened, any request on the same
BlockBackend as the guest uses should fail. If the BDS tree is supposed
to be usable even after ejecting it from the guest, a different
BlockBackend must be used.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/block-backend.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 46 insertions(+), 1 deletion(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 8206360..524cf59 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -507,7 +507,7 @@ static int blk_check_byte_request(BlockBackend *blk, int64_t offset,
         return -EIO;
     }
 
-    if (!blk_is_inserted(blk)) {
+    if (!blk_is_available(blk)) {
         return -ENOMEDIUM;
     }
 
@@ -635,6 +635,10 @@ int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int count)
 
 int64_t blk_getlength(BlockBackend *blk)
 {
+    if (!blk_is_available(blk)) {
+        return -ENOMEDIUM;
+    }
+
     return bdrv_getlength(blk->bs);
 }
 
@@ -645,6 +649,10 @@ void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr)
 
 int64_t blk_nb_sectors(BlockBackend *blk)
 {
+    if (!blk_is_available(blk)) {
+        return -ENOMEDIUM;
+    }
+
     return bdrv_nb_sectors(blk->bs);
 }
 
@@ -675,6 +683,10 @@ BlockAIOCB *blk_aio_writev(BlockBackend *blk, int64_t sector_num,
 BlockAIOCB *blk_aio_flush(BlockBackend *blk,
                           BlockCompletionFunc *cb, void *opaque)
 {
+    if (!blk_is_available(blk)) {
+        return abort_aio_request(blk, cb, opaque, -ENOMEDIUM);
+    }
+
     return bdrv_aio_flush(blk->bs, cb, opaque);
 }
 
@@ -716,12 +728,20 @@ int blk_aio_multiwrite(BlockBackend *blk, BlockRequest *reqs, int num_reqs)
 
 int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
 {
+    if (!blk_is_available(blk)) {
+        return -ENOMEDIUM;
+    }
+
     return bdrv_ioctl(blk->bs, req, buf);
 }
 
 BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
                           BlockCompletionFunc *cb, void *opaque)
 {
+    if (!blk_is_available(blk)) {
+        return abort_aio_request(blk, cb, opaque, -ENOMEDIUM);
+    }
+
     return bdrv_aio_ioctl(blk->bs, req, buf, cb, opaque);
 }
 
@@ -737,11 +757,19 @@ int blk_co_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors)
 
 int blk_co_flush(BlockBackend *blk)
 {
+    if (!blk_is_available(blk)) {
+        return -ENOMEDIUM;
+    }
+
     return bdrv_co_flush(blk->bs);
 }
 
 int blk_flush(BlockBackend *blk)
 {
+    if (!blk_is_available(blk)) {
+        return -ENOMEDIUM;
+    }
+
     return bdrv_flush(blk->bs);
 }
 
@@ -858,6 +886,11 @@ void blk_set_enable_write_cache(BlockBackend *blk, bool wce)
 
 void blk_invalidate_cache(BlockBackend *blk, Error **errp)
 {
+    if (!blk->bs) {
+        error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, blk->name);
+        return;
+    }
+
     bdrv_invalidate_cache(blk->bs, errp);
 }
 
@@ -1013,6 +1046,10 @@ int blk_write_compressed(BlockBackend *blk, int64_t sector_num,
 
 int blk_truncate(BlockBackend *blk, int64_t offset)
 {
+    if (!blk_is_available(blk)) {
+        return -ENOMEDIUM;
+    }
+
     return bdrv_truncate(blk->bs, offset);
 }
 
@@ -1029,11 +1066,19 @@ int blk_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors)
 int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
                      int64_t pos, int size)
 {
+    if (!blk_is_available(blk)) {
+        return -ENOMEDIUM;
+    }
+
     return bdrv_save_vmstate(blk->bs, buf, pos, size);
 }
 
 int blk_load_vmstate(BlockBackend *blk, uint8_t *buf, int64_t pos, int size)
 {
+    if (!blk_is_available(blk)) {
+        return -ENOMEDIUM;
+    }
+
     return bdrv_load_vmstate(blk->bs, buf, pos, size);
 }
 
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 17/37] block: Prepare remaining BB functions for NULL BDS
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (15 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 16/37] block: Fail requests to empty BlockBackend Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 20:47   ` Eric Blake
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 18/37] blockdev: Use BB for blockdev-backup transaction Max Reitz
                   ` (19 subsequent siblings)
  36 siblings, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

There are several BlockBackend functions which, in theory, cannot fail.
This patch makes them cope with the BlockDriverState pointer being NULL
by making them fall back to some default action like ignoring the value
in setters and returning the default in getters.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 block/block-backend.c | 76 ++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 60 insertions(+), 16 deletions(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 524cf59..c3418f7 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -644,7 +644,11 @@ int64_t blk_getlength(BlockBackend *blk)
 
 void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr)
 {
-    bdrv_get_geometry(blk->bs, nb_sectors_ptr);
+    if (!blk->bs) {
+        *nb_sectors_ptr = 0;
+    } else {
+        bdrv_get_geometry(blk->bs, nb_sectors_ptr);
+    }
 }
 
 int64_t blk_nb_sectors(BlockBackend *blk)
@@ -871,17 +875,27 @@ int blk_is_read_only(BlockBackend *blk)
 
 int blk_is_sg(BlockBackend *blk)
 {
+    if (!blk->bs) {
+        return 0;
+    }
+
     return bdrv_is_sg(blk->bs);
 }
 
 int blk_enable_write_cache(BlockBackend *blk)
 {
+    if (!blk->bs) {
+        return 0;
+    }
+
     return bdrv_enable_write_cache(blk->bs);
 }
 
 void blk_set_enable_write_cache(BlockBackend *blk, bool wce)
 {
-    bdrv_set_enable_write_cache(blk->bs, wce);
+    if (blk->bs) {
+        bdrv_set_enable_write_cache(blk->bs, wce);
+    }
 }
 
 void blk_invalidate_cache(BlockBackend *blk, Error **errp)
@@ -906,12 +920,16 @@ bool blk_is_available(BlockBackend *blk)
 
 void blk_lock_medium(BlockBackend *blk, bool locked)
 {
-    bdrv_lock_medium(blk->bs, locked);
+    if (blk->bs) {
+        bdrv_lock_medium(blk->bs, locked);
+    }
 }
 
 void blk_eject(BlockBackend *blk, bool eject_flag)
 {
-    bdrv_eject(blk->bs, eject_flag);
+    if (blk->bs) {
+        bdrv_eject(blk->bs, eject_flag);
+    }
 }
 
 int blk_get_flags(BlockBackend *blk)
@@ -925,7 +943,11 @@ int blk_get_flags(BlockBackend *blk)
 
 int blk_get_max_transfer_length(BlockBackend *blk)
 {
-    return blk->bs->bl.max_transfer_length;
+    if (blk->bs) {
+        return blk->bs->bl.max_transfer_length;
+    } else {
+        return 0;
+    }
 }
 
 void blk_set_guest_block_size(BlockBackend *blk, int align)
@@ -940,22 +962,32 @@ void *blk_blockalign(BlockBackend *blk, size_t size)
 
 bool blk_op_is_blocked(BlockBackend *blk, BlockOpType op, Error **errp)
 {
+    if (!blk->bs) {
+        return false;
+    }
+
     return bdrv_op_is_blocked(blk->bs, op, errp);
 }
 
 void blk_op_unblock(BlockBackend *blk, BlockOpType op, Error *reason)
 {
-    bdrv_op_unblock(blk->bs, op, reason);
+    if (blk->bs) {
+        bdrv_op_unblock(blk->bs, op, reason);
+    }
 }
 
 void blk_op_block_all(BlockBackend *blk, Error *reason)
 {
-    bdrv_op_block_all(blk->bs, reason);
+    if (blk->bs) {
+        bdrv_op_block_all(blk->bs, reason);
+    }
 }
 
 void blk_op_unblock_all(BlockBackend *blk, Error *reason)
 {
-    bdrv_op_unblock_all(blk->bs, reason);
+    if (blk->bs) {
+        bdrv_op_unblock_all(blk->bs, reason);
+    }
 }
 
 AioContext *blk_get_aio_context(BlockBackend *blk)
@@ -975,15 +1007,19 @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
 
 void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
 {
-    bdrv_set_aio_context(blk->bs, new_context);
+    if (blk->bs) {
+        bdrv_set_aio_context(blk->bs, new_context);
+    }
 }
 
 void blk_add_aio_context_notifier(BlockBackend *blk,
         void (*attached_aio_context)(AioContext *new_context, void *opaque),
         void (*detach_aio_context)(void *opaque), void *opaque)
 {
-    bdrv_add_aio_context_notifier(blk->bs, attached_aio_context,
-                                  detach_aio_context, opaque);
+    if (blk->bs) {
+        bdrv_add_aio_context_notifier(blk->bs, attached_aio_context,
+                                      detach_aio_context, opaque);
+    }
 }
 
 void blk_remove_aio_context_notifier(BlockBackend *blk,
@@ -992,23 +1028,31 @@ void blk_remove_aio_context_notifier(BlockBackend *blk,
                                      void (*detach_aio_context)(void *),
                                      void *opaque)
 {
-    bdrv_remove_aio_context_notifier(blk->bs, attached_aio_context,
-                                     detach_aio_context, opaque);
+    if (blk->bs) {
+        bdrv_remove_aio_context_notifier(blk->bs, attached_aio_context,
+                                         detach_aio_context, opaque);
+    }
 }
 
 void blk_add_close_notifier(BlockBackend *blk, Notifier *notify)
 {
-    bdrv_add_close_notifier(blk->bs, notify);
+    if (blk->bs) {
+        bdrv_add_close_notifier(blk->bs, notify);
+    }
 }
 
 void blk_io_plug(BlockBackend *blk)
 {
-    bdrv_io_plug(blk->bs);
+    if (blk->bs) {
+        bdrv_io_plug(blk->bs);
+    }
 }
 
 void blk_io_unplug(BlockBackend *blk)
 {
-    bdrv_io_unplug(blk->bs);
+    if (blk->bs) {
+        bdrv_io_unplug(blk->bs);
+    }
 }
 
 BlockAcctStats *blk_get_stats(BlockBackend *blk)
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 18/37] blockdev: Use BB for blockdev-backup transaction
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (16 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 17/37] block: Prepare remaining BB functions for NULL BDS Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 19/37] block: Add blk_insert_bs() Max Reitz
                   ` (18 subsequent siblings)
  36 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

When preparing a blockdev-backup transaction, the BlockBackend should be
used because there may be no medium associated to the BB (which would
make bdrv_find() fail, whereas blk_by_name() does not).

This does not make a real difference because blockdev-backup will fail
without a medium anyway; however, it will have an impact on the error
returned ("device not found" vs. "no medium").

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 blockdev.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index c4059cc..f669974 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1562,27 +1562,27 @@ static void blockdev_backup_prepare(BlkTransactionState *common, Error **errp)
 {
     BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
     BlockdevBackup *backup;
-    BlockDriverState *bs, *target;
+    BlockBackend *blk, *target;
     Error *local_err = NULL;
 
     assert(common->action->kind == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
     backup = common->action->blockdev_backup;
 
-    bs = bdrv_find(backup->device);
-    if (!bs) {
+    blk = blk_by_name(backup->device);
+    if (!blk) {
         error_set(errp, QERR_DEVICE_NOT_FOUND, backup->device);
         return;
     }
 
-    target = bdrv_find(backup->target);
+    target = blk_by_name(backup->target);
     if (!target) {
         error_set(errp, QERR_DEVICE_NOT_FOUND, backup->target);
         return;
     }
 
     /* AioContext is released in .clean() */
-    state->aio_context = bdrv_get_aio_context(bs);
-    if (state->aio_context != bdrv_get_aio_context(target)) {
+    state->aio_context = blk_get_aio_context(blk);
+    if (state->aio_context != blk_get_aio_context(target)) {
         state->aio_context = NULL;
         error_setg(errp, "Backup between two IO threads is not implemented");
         return;
@@ -1600,7 +1600,10 @@ static void blockdev_backup_prepare(BlkTransactionState *common, Error **errp)
         return;
     }
 
-    state->bs = bs;
+    /* qmp_blockdev_backup() would have failed otherwise */
+    assert(blk_bs(blk));
+
+    state->bs = blk_bs(blk);
     state->job = state->bs->job;
 }
 
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 19/37] block: Add blk_insert_bs()
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (17 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 18/37] blockdev: Use BB for blockdev-backup transaction Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 20/37] block: Prepare for NULL BDS Max Reitz
                   ` (17 subsequent siblings)
  36 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

This function associates the given BlockDriverState with the given
BlockBackend.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/block-backend.c          | 16 ++++++++++++++++
 include/sysemu/block-backend.h |  1 +
 2 files changed, 17 insertions(+)

diff --git a/block/block-backend.c b/block/block-backend.c
index c3418f7..0202923 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -312,6 +312,22 @@ void blk_hide_on_behalf_of_do_drive_del(BlockBackend *blk)
 }
 
 /*
+ * Associates a new BlockDriverState with @blk.
+ */
+void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs)
+{
+    if (bs->blk == blk) {
+        return;
+    }
+
+    assert(!blk->bs);
+    assert(!bs->blk);
+    bdrv_ref(bs);
+    blk->bs = bs;
+    bs->blk = blk;
+}
+
+/*
  * Attach device model @dev to @blk.
  * Return 0 on success, -EBUSY when a device model is attached already.
  */
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 53fb697..6a4a6ba 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -72,6 +72,7 @@ BlockBackend *blk_by_name(const char *name);
 BlockBackend *blk_next(BlockBackend *blk);
 
 BlockDriverState *blk_bs(BlockBackend *blk);
+void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs);
 
 void blk_hide_on_behalf_of_do_drive_del(BlockBackend *blk);
 
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 20/37] block: Prepare for NULL BDS
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (18 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 19/37] block: Add blk_insert_bs() Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 21:21   ` Eric Blake
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 21/37] blockdev: Do not create BDS for empty drive Max Reitz
                   ` (16 subsequent siblings)
  36 siblings, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

blk_bs() will not necessarily return a non-NULL value any more (unless
blk_is_available() is true or it can be assumed to otherwise, e.g.
because it is called immediately after a successful blk_new_with_bs() or
blk_new_open()).

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 block.c             |   5 ++
 block/qapi.c        |   4 +-
 blockdev.c          | 222 ++++++++++++++++++++++++++++++++++++----------------
 hw/block/xen_disk.c |   4 +-
 4 files changed, 163 insertions(+), 72 deletions(-)

diff --git a/block.c b/block.c
index 06e334a..99d9955 100644
--- a/block.c
+++ b/block.c
@@ -3747,6 +3747,11 @@ BlockDriverState *bdrv_lookup_bs(const char *device,
         blk = blk_by_name(device);
 
         if (blk) {
+            if (!blk_bs(blk)) {
+                error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
+                return NULL;
+            }
+
             return blk_bs(blk);
         }
     }
diff --git a/block/qapi.c b/block/qapi.c
index 1dc415a..43b0be2 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -282,12 +282,12 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
         info->io_status = blk_iostatus(blk);
     }
 
-    if (!QLIST_EMPTY(&bs->dirty_bitmaps)) {
+    if (bs && !QLIST_EMPTY(&bs->dirty_bitmaps)) {
         info->has_dirty_bitmaps = true;
         info->dirty_bitmaps = bdrv_query_dirty_bitmaps(bs);
     }
 
-    if (bs->drv) {
+    if (bs && bs->drv) {
         info->has_inserted = true;
         info->inserted = bdrv_block_device_info(bs);
 
diff --git a/blockdev.c b/blockdev.c
index f669974..d0e1079 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -121,14 +121,16 @@ void blockdev_mark_auto_del(BlockBackend *blk)
         return;
     }
 
-    aio_context = bdrv_get_aio_context(bs);
-    aio_context_acquire(aio_context);
+    if (bs) {
+        aio_context = bdrv_get_aio_context(bs);
+        aio_context_acquire(aio_context);
 
-    if (bs->job) {
-        block_job_cancel(bs->job);
-    }
+        if (bs->job) {
+            block_job_cancel(bs->job);
+        }
 
-    aio_context_release(aio_context);
+        aio_context_release(aio_context);
+    }
 
     dinfo->auto_del = 1;
 }
@@ -228,8 +230,8 @@ bool drive_check_orphaned(void)
             dinfo->type != IF_NONE) {
             fprintf(stderr, "Warning: Orphaned drive without device: "
                     "id=%s,file=%s,if=%s,bus=%d,unit=%d\n",
-                    blk_name(blk), blk_bs(blk)->filename, if_name[dinfo->type],
-                    dinfo->bus, dinfo->unit);
+                    blk_name(blk), blk_bs(blk) ? blk_bs(blk)->filename : "",
+                    if_name[dinfo->type], dinfo->bus, dinfo->unit);
             rs = true;
         }
     }
@@ -1096,18 +1098,23 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
                                                          const char *name,
                                                          Error **errp)
 {
-    BlockDriverState *bs = bdrv_find(device);
+    BlockBackend *blk;
+    BlockDriverState *bs;
     AioContext *aio_context;
     QEMUSnapshotInfo sn;
     Error *local_err = NULL;
     SnapshotInfo *info = NULL;
     int ret;
 
-    if (!bs) {
+    blk = blk_by_name(device);
+    if (!blk) {
         error_set(errp, QERR_DEVICE_NOT_FOUND, device);
         return NULL;
     }
 
+    aio_context = blk_get_aio_context(blk);
+    aio_context_acquire(aio_context);
+
     if (!has_id) {
         id = NULL;
     }
@@ -1118,11 +1125,14 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
 
     if (!id && !name) {
         error_setg(errp, "Name or id must be provided");
-        return NULL;
+        goto out_aio_context;
     }
 
-    aio_context = bdrv_get_aio_context(bs);
-    aio_context_acquire(aio_context);
+    if (!blk_is_available(blk)) {
+        error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
+        goto out_aio_context;
+    }
+    bs = blk_bs(blk);
 
     if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE, errp)) {
         goto out_aio_context;
@@ -1209,6 +1219,7 @@ static void internal_snapshot_prepare(BlkTransactionState *common,
     Error *local_err = NULL;
     const char *device;
     const char *name;
+    BlockBackend *blk;
     BlockDriverState *bs;
     QEMUSnapshotInfo old_sn, *sn;
     bool ret;
@@ -1227,20 +1238,21 @@ static void internal_snapshot_prepare(BlkTransactionState *common,
     name = internal->name;
 
     /* 2. check for validation */
-    bs = bdrv_find(device);
-    if (!bs) {
+    blk = blk_by_name(device);
+    if (!blk) {
         error_set(errp, QERR_DEVICE_NOT_FOUND, device);
         return;
     }
 
     /* AioContext is released in .clean() */
-    state->aio_context = bdrv_get_aio_context(bs);
+    state->aio_context = blk_get_aio_context(blk);
     aio_context_acquire(state->aio_context);
 
-    if (!bdrv_is_inserted(bs)) {
+    if (!blk_is_available(blk)) {
         error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
         return;
     }
+    bs = blk_bs(blk);
 
     if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, errp)) {
         return;
@@ -1497,23 +1509,28 @@ typedef struct DriveBackupState {
 static void drive_backup_prepare(BlkTransactionState *common, Error **errp)
 {
     DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
-    BlockDriverState *bs;
+    BlockBackend *blk;
     DriveBackup *backup;
     Error *local_err = NULL;
 
     assert(common->action->kind == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
     backup = common->action->drive_backup;
 
-    bs = bdrv_find(backup->device);
-    if (!bs) {
+    blk = blk_by_name(backup->device);
+    if (!blk) {
         error_set(errp, QERR_DEVICE_NOT_FOUND, backup->device);
         return;
     }
 
     /* AioContext is released in .clean() */
-    state->aio_context = bdrv_get_aio_context(bs);
+    state->aio_context = blk_get_aio_context(blk);
     aio_context_acquire(state->aio_context);
 
+    if (!blk_is_available(blk)) {
+        error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, backup->device);
+        return;
+    }
+
     qmp_drive_backup(backup->device, backup->target,
                      backup->has_format, backup->format,
                      backup->sync,
@@ -1527,7 +1544,7 @@ static void drive_backup_prepare(BlkTransactionState *common, Error **errp)
         return;
     }
 
-    state->bs = bs;
+    state->bs = blk_bs(blk);
     state->job = state->bs->job;
 }
 
@@ -1741,10 +1758,10 @@ static void eject_device(BlockBackend *blk, int force, Error **errp)
     BlockDriverState *bs = blk_bs(blk);
     AioContext *aio_context;
 
-    aio_context = bdrv_get_aio_context(bs);
+    aio_context = blk_get_aio_context(blk);
     aio_context_acquire(aio_context);
 
-    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
+    if (bs && bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
         goto out;
     }
     if (!blk_dev_has_removable_media(blk)) {
@@ -1762,7 +1779,9 @@ static void eject_device(BlockBackend *blk, int force, Error **errp)
         }
     }
 
-    bdrv_close(bs);
+    if (bs) {
+        bdrv_close(bs);
+    }
 
 out:
     aio_context_release(aio_context);
@@ -1806,18 +1825,21 @@ void qmp_block_passwd(bool has_device, const char *device,
 }
 
 /* Assumes AioContext is held */
-static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
+static void qmp_bdrv_open_encrypted(BlockDriverState **pbs,
+                                    const char *filename,
                                     int bdrv_flags, BlockDriver *drv,
                                     const char *password, Error **errp)
 {
+    BlockDriverState *bs;
     Error *local_err = NULL;
     int ret;
 
-    ret = bdrv_open(&bs, filename, NULL, NULL, bdrv_flags, drv, &local_err);
+    ret = bdrv_open(pbs, filename, NULL, NULL, bdrv_flags, drv, &local_err);
     if (ret < 0) {
         error_propagate(errp, local_err);
         return;
     }
+    bs = *pbs;
 
     bdrv_add_key(bs, password, errp);
 }
@@ -1830,6 +1852,7 @@ void qmp_change_blockdev(const char *device, const char *filename,
     AioContext *aio_context;
     BlockDriver *drv = NULL;
     int bdrv_flags;
+    bool new_bs;
     Error *err = NULL;
 
     blk = blk_by_name(device);
@@ -1838,12 +1861,13 @@ void qmp_change_blockdev(const char *device, const char *filename,
         return;
     }
     bs = blk_bs(blk);
+    new_bs = !bs;
 
-    aio_context = bdrv_get_aio_context(bs);
+    aio_context = blk_get_aio_context(blk);
     aio_context_acquire(aio_context);
 
     if (format) {
-        drv = bdrv_find_whitelisted_format(format, bs->read_only);
+        drv = bdrv_find_whitelisted_format(format, blk_is_read_only(blk));
         if (!drv) {
             error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
             goto out;
@@ -1856,10 +1880,18 @@ void qmp_change_blockdev(const char *device, const char *filename,
         goto out;
     }
 
-    bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR;
-    bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0;
+    bdrv_flags = blk_is_read_only(blk) ? 0 : BDRV_O_RDWR;
+    bdrv_flags |= blk_get_root_state(blk)->open_flags & ~BDRV_O_RDWR;
 
-    qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, drv, NULL, errp);
+    qmp_bdrv_open_encrypted(&bs, filename, bdrv_flags, drv, NULL, &err);
+    if (err) {
+        error_propagate(errp, err);
+    } else if (new_bs) {
+        blk_insert_bs(blk, bs);
+        /* Has been sent automatically by bdrv_open() if blk_bs(blk) was not
+         * NULL */
+        blk_dev_change_media_cb(blk, true);
+    }
 
 out:
     aio_context_release(aio_context);
@@ -1887,15 +1919,25 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
                                int64_t iops_size, Error **errp)
 {
     ThrottleConfig cfg;
+    BlockBackend *blk;
     BlockDriverState *bs;
     AioContext *aio_context;
 
-    bs = bdrv_find(device);
-    if (!bs) {
+    blk = blk_by_name(device);
+    if (!blk) {
         error_set(errp, QERR_DEVICE_NOT_FOUND, device);
         return;
     }
 
+    aio_context = blk_get_aio_context(blk);
+    aio_context_acquire(aio_context);
+
+    bs = blk_bs(blk);
+    if (!bs) {
+        error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
+        goto out;
+    }
+
     memset(&cfg, 0, sizeof(cfg));
     cfg.buckets[THROTTLE_BPS_TOTAL].avg = bps;
     cfg.buckets[THROTTLE_BPS_READ].avg  = bps_rd;
@@ -1929,12 +1971,9 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
     }
 
     if (!check_throttle_config(&cfg, errp)) {
-        return;
+        goto out;
     }
 
-    aio_context = bdrv_get_aio_context(bs);
-    aio_context_acquire(aio_context);
-
     if (!bs->io_limits_enabled && throttle_enabled(&cfg)) {
         bdrv_io_limits_enable(bs);
     } else if (bs->io_limits_enabled && !throttle_enabled(&cfg)) {
@@ -1945,6 +1984,7 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
         bdrv_set_io_limits(bs, &cfg);
     }
 
+out:
     aio_context_release(aio_context);
 }
 
@@ -1961,7 +2001,6 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
         error_report("Device '%s' not found", id);
         return -1;
     }
-    bs = blk_bs(blk);
 
     if (!blk_legacy_dinfo(blk)) {
         error_report("Deleting device added with blockdev-add"
@@ -1969,10 +2008,11 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
         return -1;
     }
 
-    aio_context = bdrv_get_aio_context(bs);
+    aio_context = blk_get_aio_context(blk);
     aio_context_acquire(aio_context);
 
-    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &local_err)) {
+    bs = blk_bs(blk);
+    if (bs && bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_DRIVE_DEL, &local_err)) {
         error_report("%s", error_get_pretty(local_err));
         error_free(local_err);
         aio_context_release(aio_context);
@@ -1981,8 +2021,10 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
 
     /* quiesce block driver; prevent further io */
     bdrv_drain_all();
-    bdrv_flush(bs);
-    bdrv_close(bs);
+    if (bs) {
+        bdrv_flush(bs);
+        bdrv_close(bs);
+    }
 
     /* if we have a device attached to this BlockDriverState
      * then we need to make the drive anonymous until the device
@@ -2099,6 +2141,7 @@ void qmp_block_stream(const char *device,
                       bool has_on_error, BlockdevOnError on_error,
                       Error **errp)
 {
+    BlockBackend *blk;
     BlockDriverState *bs;
     BlockDriverState *base_bs = NULL;
     AioContext *aio_context;
@@ -2109,15 +2152,21 @@ void qmp_block_stream(const char *device,
         on_error = BLOCKDEV_ON_ERROR_REPORT;
     }
 
-    bs = bdrv_find(device);
-    if (!bs) {
+    blk = blk_by_name(device);
+    if (!blk) {
         error_set(errp, QERR_DEVICE_NOT_FOUND, device);
         return;
     }
 
-    aio_context = bdrv_get_aio_context(bs);
+    aio_context = blk_get_aio_context(blk);
     aio_context_acquire(aio_context);
 
+    if (!blk_is_available(blk)) {
+        error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
+        goto out;
+    }
+    bs = blk_bs(blk);
+
     if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_STREAM, errp)) {
         goto out;
     }
@@ -2163,6 +2212,7 @@ void qmp_block_commit(const char *device,
                       bool has_speed, int64_t speed,
                       Error **errp)
 {
+    BlockBackend *blk;
     BlockDriverState *bs;
     BlockDriverState *base_bs, *top_bs;
     AioContext *aio_context;
@@ -2181,15 +2231,21 @@ void qmp_block_commit(const char *device,
      *  live commit feature versions; for this to work, we must make sure to
      *  perform the device lookup before any generic errors that may occur in a
      *  scenario in which all optional arguments are omitted. */
-    bs = bdrv_find(device);
-    if (!bs) {
+    blk = blk_by_name(device);
+    if (!blk) {
         error_set(errp, QERR_DEVICE_NOT_FOUND, device);
         return;
     }
 
-    aio_context = bdrv_get_aio_context(bs);
+    aio_context = blk_get_aio_context(blk);
     aio_context_acquire(aio_context);
 
+    if (!blk_is_available(blk)) {
+        error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
+        goto out;
+    }
+    bs = blk_bs(blk);
+
     /* drain all i/o before commits */
     bdrv_drain_all();
 
@@ -2266,6 +2322,7 @@ void qmp_drive_backup(const char *device, const char *target,
                       bool has_on_target_error, BlockdevOnError on_target_error,
                       Error **errp)
 {
+    BlockBackend *blk;
     BlockDriverState *bs;
     BlockDriverState *target_bs;
     BlockDriverState *source = NULL;
@@ -2289,21 +2346,22 @@ void qmp_drive_backup(const char *device, const char *target,
         mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
     }
 
-    bs = bdrv_find(device);
-    if (!bs) {
+    blk = blk_by_name(device);
+    if (!blk) {
         error_set(errp, QERR_DEVICE_NOT_FOUND, device);
         return;
     }
 
-    aio_context = bdrv_get_aio_context(bs);
+    aio_context = blk_get_aio_context(blk);
     aio_context_acquire(aio_context);
 
     /* Although backup_run has this check too, we need to use bs->drv below, so
      * do an early check redundantly. */
-    if (!bdrv_is_inserted(bs)) {
+    if (!blk_is_available(blk)) {
         error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
         goto out;
     }
+    bs = blk_bs(blk);
 
     if (!has_format) {
         format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name;
@@ -2393,6 +2451,7 @@ void qmp_blockdev_backup(const char *device, const char *target,
                          BlockdevOnError on_target_error,
                          Error **errp)
 {
+    BlockBackend *blk;
     BlockDriverState *bs;
     BlockDriverState *target_bs;
     Error *local_err = NULL;
@@ -2408,15 +2467,21 @@ void qmp_blockdev_backup(const char *device, const char *target,
         on_target_error = BLOCKDEV_ON_ERROR_REPORT;
     }
 
-    bs = bdrv_find(device);
-    if (!bs) {
+    blk = blk_by_name(device);
+    if (!blk) {
         error_set(errp, QERR_DEVICE_NOT_FOUND, device);
         return;
     }
 
-    aio_context = bdrv_get_aio_context(bs);
+    aio_context = blk_get_aio_context(blk);
     aio_context_acquire(aio_context);
 
+    if (!blk_is_available(blk)) {
+        error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
+        goto out;
+    }
+    bs = blk_bs(blk);
+
     target_bs = bdrv_find(target);
     if (!target_bs) {
         error_set(errp, QERR_DEVICE_NOT_FOUND, target);
@@ -2450,6 +2515,7 @@ void qmp_drive_mirror(const char *device, const char *target,
                       bool has_on_target_error, BlockdevOnError on_target_error,
                       Error **errp)
 {
+    BlockBackend *blk;
     BlockDriverState *bs;
     BlockDriverState *source, *target_bs;
     AioContext *aio_context;
@@ -2489,19 +2555,20 @@ void qmp_drive_mirror(const char *device, const char *target,
         return;
     }
 
-    bs = bdrv_find(device);
-    if (!bs) {
+    blk = blk_by_name(device);
+    if (!blk) {
         error_set(errp, QERR_DEVICE_NOT_FOUND, device);
         return;
     }
 
-    aio_context = bdrv_get_aio_context(bs);
+    aio_context = blk_get_aio_context(blk);
     aio_context_acquire(aio_context);
 
-    if (!bdrv_is_inserted(bs)) {
+    if (!blk_is_available(blk)) {
         error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
         goto out;
     }
+    bs = blk_bs(blk);
 
     if (!has_format) {
         format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name;
@@ -2631,18 +2698,25 @@ out:
 static BlockJob *find_block_job(const char *device, AioContext **aio_context,
                                 Error **errp)
 {
+    BlockBackend *blk;
     BlockDriverState *bs;
 
-    bs = bdrv_find(device);
-    if (!bs) {
+    *aio_context = NULL;
+
+    blk = blk_by_name(device);
+    if (!blk) {
         goto notfound;
     }
 
-    *aio_context = bdrv_get_aio_context(bs);
+    *aio_context = blk_get_aio_context(blk);
     aio_context_acquire(*aio_context);
 
+    if (!blk_is_available(blk)) {
+        goto notfound;
+    }
+    bs = blk_bs(blk);
+
     if (!bs->job) {
-        aio_context_release(*aio_context);
         goto notfound;
     }
 
@@ -2651,7 +2725,10 @@ static BlockJob *find_block_job(const char *device, AioContext **aio_context,
 notfound:
     error_set(errp, ERROR_CLASS_DEVICE_NOT_ACTIVE,
               "No active block job on device '%s'", device);
-    *aio_context = NULL;
+    if (*aio_context) {
+        aio_context_release(*aio_context);
+        *aio_context = NULL;
+    }
     return NULL;
 }
 
@@ -2741,7 +2818,8 @@ void qmp_change_backing_file(const char *device,
                              const char *backing_file,
                              Error **errp)
 {
-    BlockDriverState *bs = NULL;
+    BlockBackend *blk;
+    BlockDriverState *bs;
     AioContext *aio_context;
     BlockDriverState *image_bs = NULL;
     Error *local_err = NULL;
@@ -2750,15 +2828,21 @@ void qmp_change_backing_file(const char *device,
     int ret;
 
     /* find the top layer BDS of the chain */
-    bs = bdrv_find(device);
-    if (!bs) {
+    blk = blk_by_name(device);
+    if (!blk) {
         error_set(errp, QERR_DEVICE_NOT_FOUND, device);
         return;
     }
 
-    aio_context = bdrv_get_aio_context(bs);
+    aio_context = blk_get_aio_context(blk);
     aio_context_acquire(aio_context);
 
+    if (!blk_is_available(blk)) {
+        error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
+        goto out;
+    }
+    bs = blk_bs(blk);
+
     image_bs = bdrv_lookup_bs(NULL, image_node_name, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
index 267d8a8..2f59b5b 100644
--- a/hw/block/xen_disk.c
+++ b/hw/block/xen_disk.c
@@ -932,9 +932,11 @@ static int blk_connect(struct XenDevice *xendev)
     blk_attach_dev_nofail(blkdev->blk, blkdev);
     blkdev->file_size = blk_getlength(blkdev->blk);
     if (blkdev->file_size < 0) {
+        BlockDriverState *bs = blk_bs(blkdev->blk);
+        const char *drv_name = bs ? bdrv_get_format_name(bs) : NULL;
         xen_be_printf(&blkdev->xendev, 1, "blk_getlength: %d (%s) | drv %s\n",
                       (int)blkdev->file_size, strerror(-blkdev->file_size),
-                      bdrv_get_format_name(blk_bs(blkdev->blk)) ?: "-");
+                      drv_name ?: "-");
         blkdev->file_size = 0;
     }
 
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 21/37] blockdev: Do not create BDS for empty drive
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (19 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 20/37] block: Prepare for NULL BDS Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 21:32   ` Eric Blake
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 22/37] blockdev: Pull out blockdev option extraction Max Reitz
                   ` (15 subsequent siblings)
  36 siblings, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

Do not use "rudimentary" BDSs for empty drives any longer (for
freshly created drives).

With this change, bdrv_close_all() has no effect on empty drives (whose
media were not changed) any longer. This breaks some test outputs, fix
them.

After a follow-up patch, empty drives will generally use a NULL BDS, not
only the freshly created drives.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 blockdev.c                 | 68 ++++++++++++++++++++++++++--------------------
 tests/qemu-iotests/067.out | 44 ------------------------------
 tests/qemu-iotests/071.out |  2 --
 tests/qemu-iotests/081.out |  1 -
 tests/qemu-iotests/087.out |  6 ----
 5 files changed, 38 insertions(+), 83 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index d0e1079..5319bb0 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -504,16 +504,40 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
         goto early_err;
     }
 
+    if (snapshot) {
+        /* always use cache=unsafe with snapshot */
+        bdrv_flags &= ~BDRV_O_CACHE_MASK;
+        bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB|BDRV_O_NO_FLUSH);
+    }
+
+    if (copy_on_read) {
+        bdrv_flags |= BDRV_O_COPY_ON_READ;
+    }
+
+    if (runstate_check(RUN_STATE_INMIGRATE)) {
+        bdrv_flags |= BDRV_O_INCOMING;
+    }
+
+    bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
+
     /* init */
     if ((!file || !*file) && !has_driver_specific_opts) {
-        blk = blk_new_with_bs(qemu_opts_id(opts), errp);
+        BlockBackendRootState *blk_rs;
+
+        blk = blk_new(qemu_opts_id(opts), errp);
         if (!blk) {
             goto early_err;
         }
 
-        bs = blk_bs(blk);
-        bs->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
-        bs->read_only = ro;
+        blk_rs = blk_get_root_state(blk);
+        blk_rs->open_flags    = bdrv_flags;
+        blk_rs->read_only     = ro;
+        blk_rs->detect_zeroes = detect_zeroes;
+
+        if (throttle_enabled(&cfg)) {
+            blk_rs->io_limits_enabled = true;
+            blk_rs->throttle_config = cfg;
+        }
 
         QDECREF(bs_opts);
     } else {
@@ -521,43 +545,27 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
             file = NULL;
         }
 
-        if (snapshot) {
-            /* always use cache=unsafe with snapshot */
-            bdrv_flags &= ~BDRV_O_CACHE_MASK;
-            bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB|BDRV_O_NO_FLUSH);
-        }
-
-        if (copy_on_read) {
-            bdrv_flags |= BDRV_O_COPY_ON_READ;
-        }
-
-        if (runstate_check(RUN_STATE_INMIGRATE)) {
-            bdrv_flags |= BDRV_O_INCOMING;
-        }
-
-        bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
-
         blk = blk_new_open(qemu_opts_id(opts), file, NULL, bs_opts, bdrv_flags,
                            errp);
         if (!blk) {
             goto err_no_bs_opts;
         }
         bs = blk_bs(blk);
-    }
 
-    bs->detect_zeroes = detect_zeroes;
+        bs->detect_zeroes = detect_zeroes;
 
-    blk_set_on_error(blk, on_read_error, on_write_error);
+        /* disk I/O throttling */
+        if (throttle_enabled(&cfg)) {
+            bdrv_io_limits_enable(bs);
+            bdrv_set_io_limits(bs, &cfg);
+        }
 
-    /* disk I/O throttling */
-    if (throttle_enabled(&cfg)) {
-        bdrv_io_limits_enable(bs);
-        bdrv_set_io_limits(bs, &cfg);
+        if (bdrv_key_required(bs)) {
+            autostart = 0;
+        }
     }
 
-    if (bdrv_key_required(bs)) {
-        autostart = 0;
-    }
+    blk_set_on_error(blk, on_read_error, on_write_error);
 
 err_no_bs_opts:
     qemu_opts_del(opts);
diff --git a/tests/qemu-iotests/067.out b/tests/qemu-iotests/067.out
index 42bae32..47b0b68 100644
--- a/tests/qemu-iotests/067.out
+++ b/tests/qemu-iotests/067.out
@@ -154,17 +154,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti
     },
     "event": "SHUTDOWN"
 }
-{
-    "timestamp": {
-        "seconds":  TIMESTAMP,
-        "microseconds":  TIMESTAMP
-    },
-    "event": "DEVICE_TRAY_MOVED",
-    "data": {
-        "device": "ide1-cd0",
-        "tray-open": true
-    }
-}
 
 
 === -drive/device_add and device_del ===
@@ -324,17 +313,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
     },
     "event": "SHUTDOWN"
 }
-{
-    "timestamp": {
-        "seconds":  TIMESTAMP,
-        "microseconds":  TIMESTAMP
-    },
-    "event": "DEVICE_TRAY_MOVED",
-    "data": {
-        "device": "ide1-cd0",
-        "tray-open": true
-    }
-}
 
 
 === drive_add/device_add and device_del ===
@@ -497,17 +475,6 @@ Testing:
     },
     "event": "SHUTDOWN"
 }
-{
-    "timestamp": {
-        "seconds":  TIMESTAMP,
-        "microseconds":  TIMESTAMP
-    },
-    "event": "DEVICE_TRAY_MOVED",
-    "data": {
-        "device": "ide1-cd0",
-        "tray-open": true
-    }
-}
 
 
 === blockdev_add/device_add and device_del ===
@@ -716,16 +683,5 @@ Testing:
     },
     "event": "SHUTDOWN"
 }
-{
-    "timestamp": {
-        "seconds":  TIMESTAMP,
-        "microseconds":  TIMESTAMP
-    },
-    "event": "DEVICE_TRAY_MOVED",
-    "data": {
-        "device": "ide1-cd0",
-        "tray-open": true
-    }
-}
 
 *** done
diff --git a/tests/qemu-iotests/071.out b/tests/qemu-iotests/071.out
index 904ce15..2b40ead 100644
--- a/tests/qemu-iotests/071.out
+++ b/tests/qemu-iotests/071.out
@@ -51,7 +51,6 @@ read failed: Input/output error
 {"return": ""}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
 QEMU_PROG: Failed to flush the L2 table cache: Input/output error
 QEMU_PROG: Failed to flush the refcount block cache: Input/output error
 
@@ -93,7 +92,6 @@ read failed: Input/output error
 {"return": ""}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
 QEMU_PROG: Failed to flush the L2 table cache: Input/output error
 QEMU_PROG: Failed to flush the refcount block cache: Input/output error
 
diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out
index b1e4909..7063231 100644
--- a/tests/qemu-iotests/081.out
+++ b/tests/qemu-iotests/081.out
@@ -37,7 +37,6 @@ read 10485760/10485760 bytes at offset 0
 {"return": ""}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
 
 
 == using quorum rewrite corrupted mode ==
diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out
index 55f4951..8699c46 100644
--- a/tests/qemu-iotests/087.out
+++ b/tests/qemu-iotests/087.out
@@ -9,7 +9,6 @@ QMP_VERSION
 {"error": {"class": "GenericError", "desc": "'id' and/or 'node-name' need to be specified for the root node"}}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
 
 
 === Duplicate ID ===
@@ -25,7 +24,6 @@ QMP_VERSION
 {"error": {"class": "GenericError", "desc": "node-name=disk3 is conflicting with a device id"}}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
 
 
 === aio=native without O_DIRECT ===
@@ -36,7 +34,6 @@ QMP_VERSION
 {"error": {"class": "GenericError", "desc": "aio=native requires cache.direct=true"}}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
 
 
 === Encrypted image ===
@@ -48,7 +45,6 @@ QMP_VERSION
 {"error": {"class": "GenericError", "desc": "blockdev-add doesn't support encrypted devices"}}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
 
 Testing:
 QMP_VERSION
@@ -56,7 +52,6 @@ QMP_VERSION
 {"error": {"class": "GenericError", "desc": "Guest must be stopped for opening of encrypted image"}}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
 
 
 === Missing driver ===
@@ -68,6 +63,5 @@ QMP_VERSION
 {"error": {"class": "GenericError", "desc": "Invalid parameter type for 'driver', expected: string"}}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
-{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
 
 *** done
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 22/37] blockdev: Pull out blockdev option extraction
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (20 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 21/37] blockdev: Do not create BDS for empty drive Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 23/37] blockdev: Allow more options for BB-less BDS tree Max Reitz
                   ` (14 subsequent siblings)
  36 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

Extract some of the blockdev option extraction code from blockdev_init()
into its own function. This simplifies blockdev_init() and will allow
reusing the code in a different function added in a follow-up patch.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 blockdev.c | 201 +++++++++++++++++++++++++++++++++----------------------------
 1 file changed, 108 insertions(+), 93 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 5319bb0..f44e09b 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -343,24 +343,123 @@ static bool check_throttle_config(ThrottleConfig *cfg, Error **errp)
 
 typedef enum { MEDIA_DISK, MEDIA_CDROM } DriveMediaType;
 
+static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags,
+    ThrottleConfig *throttle_cfg, BlockdevDetectZeroesOptions *detect_zeroes,
+    Error **errp)
+{
+    const char *discard, *aio;
+    Error *local_error = NULL;
+
+    if (!qemu_opt_get_bool(opts, "read-only", false)) {
+        *bdrv_flags |= BDRV_O_RDWR;
+    }
+    if (qemu_opt_get_bool(opts, "copy-on-read", false)) {
+        *bdrv_flags |= BDRV_O_COPY_ON_READ;
+    }
+
+    if ((discard = qemu_opt_get(opts, "discard")) != NULL) {
+        if (bdrv_parse_discard_flags(discard, bdrv_flags) != 0) {
+            error_setg(errp, "Invalid discard option");
+            return;
+        }
+    }
+
+    if (qemu_opt_get_bool(opts, "cache.writeback", true)) {
+        *bdrv_flags |= BDRV_O_CACHE_WB;
+    }
+    if (qemu_opt_get_bool(opts, "cache.direct", false)) {
+        *bdrv_flags |= BDRV_O_NOCACHE;
+    }
+    if (qemu_opt_get_bool(opts, "cache.no-flush", false)) {
+        *bdrv_flags |= BDRV_O_NO_FLUSH;
+    }
+
+#ifdef CONFIG_LINUX_AIO
+    if ((aio = qemu_opt_get(opts, "aio")) != NULL) {
+        if (!strcmp(aio, "native")) {
+            *bdrv_flags |= BDRV_O_NATIVE_AIO;
+        } else if (!strcmp(aio, "threads")) {
+            /* this is the default */
+        } else {
+           error_setg(errp, "invalid aio option");
+           return;
+        }
+    }
+#endif
+
+    /* disk I/O throttling */
+    memset(throttle_cfg, 0, sizeof(*throttle_cfg));
+    throttle_cfg->buckets[THROTTLE_BPS_TOTAL].avg =
+        qemu_opt_get_number(opts, "throttling.bps-total", 0);
+    throttle_cfg->buckets[THROTTLE_BPS_READ].avg  =
+        qemu_opt_get_number(opts, "throttling.bps-read", 0);
+    throttle_cfg->buckets[THROTTLE_BPS_WRITE].avg =
+        qemu_opt_get_number(opts, "throttling.bps-write", 0);
+    throttle_cfg->buckets[THROTTLE_OPS_TOTAL].avg =
+        qemu_opt_get_number(opts, "throttling.iops-total", 0);
+    throttle_cfg->buckets[THROTTLE_OPS_READ].avg =
+        qemu_opt_get_number(opts, "throttling.iops-read", 0);
+    throttle_cfg->buckets[THROTTLE_OPS_WRITE].avg =
+        qemu_opt_get_number(opts, "throttling.iops-write", 0);
+
+    throttle_cfg->buckets[THROTTLE_BPS_TOTAL].max =
+        qemu_opt_get_number(opts, "throttling.bps-total-max", 0);
+    throttle_cfg->buckets[THROTTLE_BPS_READ].max  =
+        qemu_opt_get_number(opts, "throttling.bps-read-max", 0);
+    throttle_cfg->buckets[THROTTLE_BPS_WRITE].max =
+        qemu_opt_get_number(opts, "throttling.bps-write-max", 0);
+    throttle_cfg->buckets[THROTTLE_OPS_TOTAL].max =
+        qemu_opt_get_number(opts, "throttling.iops-total-max", 0);
+    throttle_cfg->buckets[THROTTLE_OPS_READ].max =
+        qemu_opt_get_number(opts, "throttling.iops-read-max", 0);
+    throttle_cfg->buckets[THROTTLE_OPS_WRITE].max =
+        qemu_opt_get_number(opts, "throttling.iops-write-max", 0);
+
+    throttle_cfg->op_size =
+        qemu_opt_get_number(opts, "throttling.iops-size", 0);
+
+    if (!check_throttle_config(throttle_cfg, errp)) {
+        return;
+    }
+
+    *detect_zeroes =
+        qapi_enum_parse(BlockdevDetectZeroesOptions_lookup,
+                        qemu_opt_get(opts, "detect-zeroes"),
+                        BLOCKDEV_DETECT_ZEROES_OPTIONS_MAX,
+                        BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
+                        &local_error);
+    if (local_error) {
+        error_propagate(errp, local_error);
+        return;
+    }
+
+    if (*detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
+        !(*bdrv_flags & BDRV_O_UNMAP))
+    {
+        error_setg(errp, "setting detect-zeroes to unmap is not allowed "
+                         "without setting discard operation to unmap");
+        return;
+    }
+
+}
+
 /* Takes the ownership of bs_opts */
 static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
                                    Error **errp)
 {
     const char *buf;
-    int ro = 0;
     int bdrv_flags = 0;
     int on_read_error, on_write_error;
     BlockBackend *blk;
     BlockDriverState *bs;
     ThrottleConfig cfg;
     int snapshot = 0;
-    bool copy_on_read;
     Error *error = NULL;
     QemuOpts *opts;
     const char *id;
     bool has_driver_specific_opts;
-    BlockdevDetectZeroesOptions detect_zeroes;
+    BlockdevDetectZeroesOptions detect_zeroes =
+        BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;
 
     /* Check common options by copying from bs_opts to opts, all other options
      * stay in bs_opts for processing by bdrv_open(). */
@@ -385,38 +484,13 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
 
     /* extract parameters */
     snapshot = qemu_opt_get_bool(opts, "snapshot", 0);
-    ro = qemu_opt_get_bool(opts, "read-only", 0);
-    copy_on_read = qemu_opt_get_bool(opts, "copy-on-read", false);
-
-    if ((buf = qemu_opt_get(opts, "discard")) != NULL) {
-        if (bdrv_parse_discard_flags(buf, &bdrv_flags) != 0) {
-            error_setg(errp, "invalid discard option");
-            goto early_err;
-        }
-    }
 
-    if (qemu_opt_get_bool(opts, "cache.writeback", true)) {
-        bdrv_flags |= BDRV_O_CACHE_WB;
-    }
-    if (qemu_opt_get_bool(opts, "cache.direct", false)) {
-        bdrv_flags |= BDRV_O_NOCACHE;
-    }
-    if (qemu_opt_get_bool(opts, "cache.no-flush", false)) {
-        bdrv_flags |= BDRV_O_NO_FLUSH;
-    }
-
-#ifdef CONFIG_LINUX_AIO
-    if ((buf = qemu_opt_get(opts, "aio")) != NULL) {
-        if (!strcmp(buf, "native")) {
-            bdrv_flags |= BDRV_O_NATIVE_AIO;
-        } else if (!strcmp(buf, "threads")) {
-            /* this is the default */
-        } else {
-           error_setg(errp, "invalid aio option");
-           goto early_err;
-        }
+    extract_common_blockdev_options(opts, &bdrv_flags, &cfg, &detect_zeroes,
+                                    &error);
+    if (error) {
+        error_propagate(errp, error);
+        goto early_err;
     }
-#endif
 
     if ((buf = qemu_opt_get(opts, "format")) != NULL) {
         if (is_help_option(buf)) {
@@ -433,41 +507,6 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
         qdict_put(bs_opts, "driver", qstring_from_str(buf));
     }
 
-    /* disk I/O throttling */
-    memset(&cfg, 0, sizeof(cfg));
-    cfg.buckets[THROTTLE_BPS_TOTAL].avg =
-        qemu_opt_get_number(opts, "throttling.bps-total", 0);
-    cfg.buckets[THROTTLE_BPS_READ].avg  =
-        qemu_opt_get_number(opts, "throttling.bps-read", 0);
-    cfg.buckets[THROTTLE_BPS_WRITE].avg =
-        qemu_opt_get_number(opts, "throttling.bps-write", 0);
-    cfg.buckets[THROTTLE_OPS_TOTAL].avg =
-        qemu_opt_get_number(opts, "throttling.iops-total", 0);
-    cfg.buckets[THROTTLE_OPS_READ].avg =
-        qemu_opt_get_number(opts, "throttling.iops-read", 0);
-    cfg.buckets[THROTTLE_OPS_WRITE].avg =
-        qemu_opt_get_number(opts, "throttling.iops-write", 0);
-
-    cfg.buckets[THROTTLE_BPS_TOTAL].max =
-        qemu_opt_get_number(opts, "throttling.bps-total-max", 0);
-    cfg.buckets[THROTTLE_BPS_READ].max  =
-        qemu_opt_get_number(opts, "throttling.bps-read-max", 0);
-    cfg.buckets[THROTTLE_BPS_WRITE].max =
-        qemu_opt_get_number(opts, "throttling.bps-write-max", 0);
-    cfg.buckets[THROTTLE_OPS_TOTAL].max =
-        qemu_opt_get_number(opts, "throttling.iops-total-max", 0);
-    cfg.buckets[THROTTLE_OPS_READ].max =
-        qemu_opt_get_number(opts, "throttling.iops-read-max", 0);
-    cfg.buckets[THROTTLE_OPS_WRITE].max =
-        qemu_opt_get_number(opts, "throttling.iops-write-max", 0);
-
-    cfg.op_size = qemu_opt_get_number(opts, "throttling.iops-size", 0);
-
-    if (!check_throttle_config(&cfg, &error)) {
-        error_propagate(errp, error);
-        goto early_err;
-    }
-
     on_write_error = BLOCKDEV_ON_ERROR_ENOSPC;
     if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
         on_write_error = parse_block_error_action(buf, 0, &error);
@@ -486,40 +525,16 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
         }
     }
 
-    detect_zeroes =
-        qapi_enum_parse(BlockdevDetectZeroesOptions_lookup,
-                        qemu_opt_get(opts, "detect-zeroes"),
-                        BLOCKDEV_DETECT_ZEROES_OPTIONS_MAX,
-                        BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
-                        &error);
-    if (error) {
-        error_propagate(errp, error);
-        goto early_err;
-    }
-
-    if (detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
-        !(bdrv_flags & BDRV_O_UNMAP)) {
-        error_setg(errp, "setting detect-zeroes to unmap is not allowed "
-                         "without setting discard operation to unmap");
-        goto early_err;
-    }
-
     if (snapshot) {
         /* always use cache=unsafe with snapshot */
         bdrv_flags &= ~BDRV_O_CACHE_MASK;
         bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB|BDRV_O_NO_FLUSH);
     }
 
-    if (copy_on_read) {
-        bdrv_flags |= BDRV_O_COPY_ON_READ;
-    }
-
     if (runstate_check(RUN_STATE_INMIGRATE)) {
         bdrv_flags |= BDRV_O_INCOMING;
     }
 
-    bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
-
     /* init */
     if ((!file || !*file) && !has_driver_specific_opts) {
         BlockBackendRootState *blk_rs;
@@ -531,7 +546,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
 
         blk_rs = blk_get_root_state(blk);
         blk_rs->open_flags    = bdrv_flags;
-        blk_rs->read_only     = ro;
+        blk_rs->read_only     = !(bdrv_flags & BDRV_O_RDWR);
         blk_rs->detect_zeroes = detect_zeroes;
 
         if (throttle_enabled(&cfg)) {
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 23/37] blockdev: Allow more options for BB-less BDS tree
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (21 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 22/37] blockdev: Pull out blockdev option extraction Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 24/37] block: Add blk_remove_bs() Max Reitz
                   ` (13 subsequent siblings)
  36 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

Most of the options which blockdev_init() parses for both the
BlockBackend and the root BDS are valid for just the root BDS as well
(e.g. read-only). This patch allows specifying these options even if not
creating a BlockBackend.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 blockdev.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 150 insertions(+), 6 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index f44e09b..d9d6150 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -593,6 +593,61 @@ err_no_opts:
     return NULL;
 }
 
+static QemuOptsList qemu_root_bds_opts;
+
+/* Takes the ownership of bs_opts */
+static BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp)
+{
+    BlockDriverState *bs;
+    QemuOpts *opts;
+    Error *local_error = NULL;
+    ThrottleConfig cfg;
+    BlockdevDetectZeroesOptions detect_zeroes;
+    int ret;
+    int bdrv_flags = 0;
+
+    opts = qemu_opts_create(&qemu_root_bds_opts, NULL, 1, errp);
+    if (!opts) {
+        goto fail;
+    }
+
+    qemu_opts_absorb_qdict(opts, bs_opts, &local_error);
+    if (local_error) {
+        error_propagate(errp, local_error);
+        goto fail;
+    }
+
+    extract_common_blockdev_options(opts, &bdrv_flags, &cfg, &detect_zeroes,
+                                    &local_error);
+    if (local_error) {
+        error_propagate(errp, local_error);
+        goto fail;
+    }
+
+    bs = NULL;
+    ret = bdrv_open(&bs, NULL, NULL, bs_opts, bdrv_flags, NULL, errp);
+    if (ret < 0) {
+        goto fail_no_bs_opts;
+    }
+
+    bs->detect_zeroes = detect_zeroes;
+
+    /* disk I/O throttling */
+    if (throttle_enabled(&cfg)) {
+        bdrv_io_limits_enable(bs);
+        bdrv_set_io_limits(bs, &cfg);
+    }
+
+fail_no_bs_opts:
+    qemu_opts_del(opts);
+    return bs;
+
+fail:
+    qemu_opts_del(opts);
+    QDECREF(bs_opts);
+    return NULL;
+}
+
 static void qemu_opt_rename(QemuOpts *opts, const char *from, const char *to,
                             Error **errp)
 {
@@ -2974,18 +3029,14 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
 
         bs = blk_bs(blk);
     } else {
-        int ret;
-
         if (!qdict_get_try_str(qdict, "node-name")) {
             error_setg(errp, "'id' and/or 'node-name' need to be specified for "
                        "the root node");
             goto fail;
         }
 
-        bs = NULL;
-        ret = bdrv_open(&bs, NULL, NULL, qdict, BDRV_O_RDWR | BDRV_O_CACHE_WB,
-                        NULL, errp);
-        if (ret < 0) {
+        bs = bds_tree_init(qdict, errp);
+        if (!bs) {
             goto fail;
         }
     }
@@ -3136,6 +3187,99 @@ QemuOptsList qemu_common_drive_opts = {
     },
 };
 
+static QemuOptsList qemu_root_bds_opts = {
+    .name = "root-bds",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head),
+    .desc = {
+        {
+            .name = "discard",
+            .type = QEMU_OPT_STRING,
+            .help = "discard operation (ignore/off, unmap/on)",
+        },{
+            .name = "cache.writeback",
+            .type = QEMU_OPT_BOOL,
+            .help = "enables writeback mode for any caches",
+        },{
+            .name = "cache.direct",
+            .type = QEMU_OPT_BOOL,
+            .help = "enables use of O_DIRECT (bypass the host page cache)",
+        },{
+            .name = "cache.no-flush",
+            .type = QEMU_OPT_BOOL,
+            .help = "ignore any flush requests for the device",
+        },{
+            .name = "aio",
+            .type = QEMU_OPT_STRING,
+            .help = "host AIO implementation (threads, native)",
+        },{
+            .name = "read-only",
+            .type = QEMU_OPT_BOOL,
+            .help = "open drive file as read-only",
+        },{
+            .name = "throttling.iops-total",
+            .type = QEMU_OPT_NUMBER,
+            .help = "limit total I/O operations per second",
+        },{
+            .name = "throttling.iops-read",
+            .type = QEMU_OPT_NUMBER,
+            .help = "limit read operations per second",
+        },{
+            .name = "throttling.iops-write",
+            .type = QEMU_OPT_NUMBER,
+            .help = "limit write operations per second",
+        },{
+            .name = "throttling.bps-total",
+            .type = QEMU_OPT_NUMBER,
+            .help = "limit total bytes per second",
+        },{
+            .name = "throttling.bps-read",
+            .type = QEMU_OPT_NUMBER,
+            .help = "limit read bytes per second",
+        },{
+            .name = "throttling.bps-write",
+            .type = QEMU_OPT_NUMBER,
+            .help = "limit write bytes per second",
+        },{
+            .name = "throttling.iops-total-max",
+            .type = QEMU_OPT_NUMBER,
+            .help = "I/O operations burst",
+        },{
+            .name = "throttling.iops-read-max",
+            .type = QEMU_OPT_NUMBER,
+            .help = "I/O operations read burst",
+        },{
+            .name = "throttling.iops-write-max",
+            .type = QEMU_OPT_NUMBER,
+            .help = "I/O operations write burst",
+        },{
+            .name = "throttling.bps-total-max",
+            .type = QEMU_OPT_NUMBER,
+            .help = "total bytes burst",
+        },{
+            .name = "throttling.bps-read-max",
+            .type = QEMU_OPT_NUMBER,
+            .help = "total bytes read burst",
+        },{
+            .name = "throttling.bps-write-max",
+            .type = QEMU_OPT_NUMBER,
+            .help = "total bytes write burst",
+        },{
+            .name = "throttling.iops-size",
+            .type = QEMU_OPT_NUMBER,
+            .help = "when limiting by iops max size of an I/O in bytes",
+        },{
+            .name = "copy-on-read",
+            .type = QEMU_OPT_BOOL,
+            .help = "copy read data from backing file into image file",
+        },{
+            .name = "detect-zeroes",
+            .type = QEMU_OPT_STRING,
+            .help = "try to optimize zero writes (off, on, unmap)",
+        },
+        { /* end of list */ }
+    },
+};
+
 QemuOptsList qemu_drive_opts = {
     .name = "drive",
     .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head),
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 24/37] block: Add blk_remove_bs()
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (22 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 23/37] blockdev: Allow more options for BB-less BDS tree Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 25/37] blockdev: Add blockdev-open-tray Max Reitz
                   ` (12 subsequent siblings)
  36 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

This function removes the BlockDriverState associated with the given
BlockBackend from that BB and sets the BDS pointer in the BB to NULL.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/block-backend.c          | 22 +++++++++++++++++++++-
 include/sysemu/block-backend.h |  1 +
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 0202923..00e96da 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -312,6 +312,22 @@ void blk_hide_on_behalf_of_do_drive_del(BlockBackend *blk)
 }
 
 /*
+ * Disassociates the currently associated BlockDriverState from @blk.
+ */
+void blk_remove_bs(BlockBackend *blk)
+{
+    if (!blk->bs) {
+        return;
+    }
+
+    blk_update_root_state(blk);
+
+    bdrv_unref(blk->bs);
+    blk->bs->blk = NULL;
+    blk->bs = NULL;
+}
+
+/*
  * Associates a new BlockDriverState with @blk.
  */
 void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs)
@@ -321,9 +337,13 @@ void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs)
     }
 
     assert(!blk->bs);
-    assert(!bs->blk);
     bdrv_ref(bs);
     blk->bs = bs;
+
+    if (bs->blk) {
+        blk_remove_bs(bs->blk);
+    }
+
     bs->blk = blk;
 }
 
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 6a4a6ba..e234aca 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -72,6 +72,7 @@ BlockBackend *blk_by_name(const char *name);
 BlockBackend *blk_next(BlockBackend *blk);
 
 BlockDriverState *blk_bs(BlockBackend *blk);
+void blk_remove_bs(BlockBackend *blk);
 void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs);
 
 void blk_hide_on_behalf_of_do_drive_del(BlockBackend *blk);
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 25/37] blockdev: Add blockdev-open-tray
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (23 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 24/37] block: Add blk_remove_bs() Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 22:01   ` Eric Blake
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 26/37] blockdev: Add blockdev-close-tray Max Reitz
                   ` (11 subsequent siblings)
  36 siblings, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 blockdev.c           | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 qapi/block-core.json | 23 +++++++++++++++++++++++
 qmp-commands.hx      | 39 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 110 insertions(+)

diff --git a/blockdev.c b/blockdev.c
index d9d6150..7d06230 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1975,6 +1975,54 @@ out:
     aio_context_release(aio_context);
 }
 
+void qmp_blockdev_open_tray(const char *device, bool has_force, bool force,
+                            Error **errp)
+{
+    BlockBackend *blk;
+    BlockDriverState *bs;
+    AioContext *aio_context = NULL;
+
+    if (!has_force) {
+        force = false;
+    }
+
+    blk = blk_by_name(device);
+    if (!blk) {
+        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+        return;
+    }
+
+    if (!blk_dev_has_removable_media(blk)) {
+        error_setg(errp, "Device '%s' is not removable", device);
+        return;
+    }
+
+    if (blk_dev_is_tray_open(blk)) {
+        return;
+    }
+
+    bs = blk_bs(blk);
+    if (bs) {
+        aio_context = bdrv_get_aio_context(bs);
+        aio_context_acquire(aio_context);
+
+        if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
+            goto out;
+        }
+    }
+
+    if (blk_dev_is_medium_locked(blk)) {
+        blk_dev_eject_request(blk, force);
+    } else {
+        blk_dev_change_media_cb(blk, false);
+    }
+
+out:
+    if (aio_context) {
+        aio_context_release(aio_context);
+    }
+}
+
 /* throttling disk I/O limits */
 void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
                                int64_t bps_wr,
diff --git a/qapi/block-core.json b/qapi/block-core.json
index e85ef40..754e671 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1730,6 +1730,29 @@
 ##
 { 'command': 'blockdev-add', 'data': { 'options': 'BlockdevOptions' } }
 
+##
+# @blockdev-open-tray:
+#
+# Opens a block device's tray. If there is a block driver state tree inserted as
+# a medium, it will become inaccessible to the guest (but it will remain
+# associated to the block device, so closing the tray will make it accessible
+# again).
+#
+# If the tray was already open before, this will be a no-op.
+#
+# @device: block device name
+#
+# @force:  #optional if false (the default), an eject request will be sent to
+#          the guest if it has locked the tray (and the tray will not be opened
+#          immediately); if true, the tray will be opened regardless of whether
+#          it is locked
+#
+# Since: 2.3
+##
+{ 'command': 'blockdev-open-tray',
+  'data': { 'device': 'str',
+            '*force': 'bool' } }
+
 
 ##
 # @BlockErrorAction
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 9001792..4fca4f6 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3655,6 +3655,45 @@ Example (2):
 EQMP
 
     {
+        .name       = "blockdev-open-tray",
+        .args_type  = "device:s,force:b?",
+        .mhandler.cmd_new = qmp_marshal_input_blockdev_open_tray,
+    },
+
+SQMP
+blockdev-open-tray
+------------------
+
+Opens a block device's tray. If there is a block driver state tree inserted as a
+medium, it will become inaccessible to the guest (but it will remain associated
+to the block device, so closing the tray will make it accessible again).
+
+If the tray was already open before, this will be a no-op.
+
+Arguments:
+
+- "device": block device name (json-string)
+- "force": if false (the default), an eject request will be sent to the guest if
+           it has locked the tray (and the tray will not be opened immediately);
+           if true, the tray will be opened regardless of whether it is locked
+           (json-bool, optional)
+
+Example:
+
+-> { "execute": "blockdev-open-tray",
+     "arguments": { "device": "ide1-cd0" } }
+
+<- { "timestamp": { "seconds": 1418751016,
+                    "microseconds": 716996 },
+     "event": "DEVICE_TRAY_MOVED",
+     "data": { "device": "ide1-cd0",
+               "tray-open": true } }
+
+<- { "return": {} }
+
+EQMP
+
+    {
         .name       = "query-named-block-nodes",
         .args_type  = "",
         .mhandler.cmd_new = qmp_marshal_input_query_named_block_nodes,
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 26/37] blockdev: Add blockdev-close-tray
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (24 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 25/37] blockdev: Add blockdev-open-tray Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 22:18   ` Eric Blake
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 27/37] blockdev: Add blockdev-remove-medium Max Reitz
                   ` (10 subsequent siblings)
  36 siblings, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 blockdev.c           | 22 ++++++++++++++++++++++
 qapi/block-core.json | 16 ++++++++++++++++
 qmp-commands.hx      | 35 +++++++++++++++++++++++++++++++++++
 3 files changed, 73 insertions(+)

diff --git a/blockdev.c b/blockdev.c
index 7d06230..eef8944 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2023,6 +2023,28 @@ out:
     }
 }
 
+void qmp_blockdev_close_tray(const char *device, Error **errp)
+{
+    BlockBackend *blk;
+
+    blk = blk_by_name(device);
+    if (!blk) {
+        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+        return;
+    }
+
+    if (!blk_dev_has_removable_media(blk)) {
+        error_setg(errp, "Device '%s' is not removable", device);
+        return;
+    }
+
+    if (!blk_dev_is_tray_open(blk)) {
+        return;
+    }
+
+    blk_dev_change_media_cb(blk, true);
+}
+
 /* throttling disk I/O limits */
 void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
                                int64_t bps_wr,
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 754e671..fc6acd7 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1753,6 +1753,22 @@
   'data': { 'device': 'str',
             '*force': 'bool' } }
 
+##
+# @blockdev-close-tray:
+#
+# Closes a block device's tray. If there is a block driver state tree associated
+# with the block device (which is currently ejected), that tree will be loaded
+# as the medium.
+#
+# If the tray was already closed before, this will be a no-op.
+#
+# @device: block device name
+#
+# Since: 2.3
+##
+{ 'command': 'blockdev-close-tray',
+  'data': { 'device': 'str' } }
+
 
 ##
 # @BlockErrorAction
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 4fca4f6..afa5cf3 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3694,6 +3694,41 @@ Example:
 EQMP
 
     {
+        .name       = "blockdev-close-tray",
+        .args_type  = "device:s",
+        .mhandler.cmd_new = qmp_marshal_input_blockdev_close_tray,
+    },
+
+SQMP
+blockdev-close-tray
+-------------------
+
+Closes a block device's tray. If there is a block driver state tree associated
+with the block device (which is currently ejected), that tree will be loaded as
+the medium.
+
+If the tray was already closed before, this will be a no-op.
+
+Arguments:
+
+- "device": block device name (json-string)
+
+Example:
+
+-> { "execute": "blockdev-close-tray",
+     "arguments": { "device": "ide1-cd0" } }
+
+<- { "timestamp": { "seconds": 1418751345,
+                    "microseconds": 272147 },
+     "event": "DEVICE_TRAY_MOVED",
+     "data": { "device": "ide1-cd0",
+               "tray-open": false } }
+
+<- { "return": {} }
+
+EQMP
+
+    {
         .name       = "query-named-block-nodes",
         .args_type  = "",
         .mhandler.cmd_new = qmp_marshal_input_query_named_block_nodes,
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 27/37] blockdev: Add blockdev-remove-medium
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (25 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 26/37] blockdev: Add blockdev-close-tray Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 22:21   ` Eric Blake
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 28/37] blockdev: Add blockdev-insert-medium Max Reitz
                   ` (9 subsequent siblings)
  36 siblings, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 blockdev.c           | 25 +++++++++++++++++++++++++
 qapi/block-core.json | 15 +++++++++++++++
 qmp-commands.hx      | 45 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 85 insertions(+)

diff --git a/blockdev.c b/blockdev.c
index eef8944..2544c6f 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2045,6 +2045,31 @@ void qmp_blockdev_close_tray(const char *device, Error **errp)
     blk_dev_change_media_cb(blk, true);
 }
 
+void qmp_blockdev_remove_medium(const char *device, Error **errp)
+{
+    BlockBackend *blk;
+
+    blk = blk_by_name(device);
+    if (!blk) {
+        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+        return;
+    }
+
+    if (!blk_dev_has_removable_media(blk)) {
+        error_setg(errp, "Device '%s' is not removable", device);
+        return;
+    }
+
+    if (!blk_dev_is_tray_open(blk)) {
+        error_setg(errp, "Tray of device '%s' is not open", device);
+        return;
+    }
+
+    if (blk_bs(blk)) {
+        blk_remove_bs(blk);
+    }
+}
+
 /* throttling disk I/O limits */
 void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
                                int64_t bps_wr,
diff --git a/qapi/block-core.json b/qapi/block-core.json
index fc6acd7..7f0f21c 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1769,6 +1769,21 @@
 { 'command': 'blockdev-close-tray',
   'data': { 'device': 'str' } }
 
+##
+# @blockdev-remove-medium:
+#
+# Removes a medium (a block driver state tree) from a block device. That block
+# device's tray must currently be open.
+#
+# If the tray is open and there is no medium inserted, this will be a no-op.
+#
+# @device: block device name
+#
+# Since: 2.3
+##
+{ 'command': 'blockdev-remove-medium',
+  'data': { 'device': 'str' } }
+
 
 ##
 # @BlockErrorAction
diff --git a/qmp-commands.hx b/qmp-commands.hx
index afa5cf3..1bd39b7 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3729,6 +3729,51 @@ Example:
 EQMP
 
     {
+        .name       = "blockdev-remove-medium",
+        .args_type  = "device:s",
+        .mhandler.cmd_new = qmp_marshal_input_blockdev_remove_medium,
+    },
+
+SQMP
+blockdev-remove-medium
+----------------------
+
+Removes a medium (a block driver state tree) from a block device. That block
+device's tray must currently be open.
+
+If the tray is open and there is no medium inserted, this will be a no-op.
+
+Arguments:
+
+- "device": block device name (json-string)
+
+Example:
+
+-> { "execute": "blockdev-remove-medium",
+     "arguments": { "device": "ide1-cd0" } }
+
+<- { "error": { "class": "GenericError",
+                "desc": "Tray of device 'ide1-cd0' is not open" } }
+
+-> { "execute": "blockdev-open-tray",
+     "arguments": { "device": "ide1-cd0" } }
+
+<- { "timestamp": { "seconds": 1418751627,
+                    "microseconds": 549958 },
+     "event": "DEVICE_TRAY_MOVED",
+     "data": { "device": "ide1-cd0",
+               "tray-open": true } }
+
+<- { "return": {} }
+
+-> { "execute": "blockdev-remove-medium",
+     "arguments": { "device": "ide1-cd0" } }
+
+<- { "return": {} }
+
+EQMP
+
+    {
         .name       = "query-named-block-nodes",
         .args_type  = "",
         .mhandler.cmd_new = qmp_marshal_input_query_named_block_nodes,
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 28/37] blockdev: Add blockdev-insert-medium
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (26 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 27/37] blockdev: Add blockdev-remove-medium Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 22:23   ` Eric Blake
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 29/37] blockdev: Implement eject with basic operations Max Reitz
                   ` (8 subsequent siblings)
  36 siblings, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

And a helper function for that which directly takes a pointer to the BDS
to be inserted instead of its node-name (which will be used for
implementing 'change' using blockdev-insert-medium).

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 blockdev.c           | 43 +++++++++++++++++++++++++++++++++++++++++++
 qapi/block-core.json | 17 +++++++++++++++++
 qmp-commands.hx      | 37 +++++++++++++++++++++++++++++++++++++
 3 files changed, 97 insertions(+)

diff --git a/blockdev.c b/blockdev.c
index 2544c6f..819a3c1 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2070,6 +2070,49 @@ void qmp_blockdev_remove_medium(const char *device, Error **errp)
     }
 }
 
+static void qmp_blockdev_insert_anon_medium(const char *device,
+                                            BlockDriverState *bs, Error **errp)
+{
+    BlockBackend *blk;
+
+    blk = blk_by_name(device);
+    if (!blk) {
+        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+        return;
+    }
+
+    if (!blk_dev_has_removable_media(blk)) {
+        error_setg(errp, "Device '%s' is not removable", device);
+        return;
+    }
+
+    if (!blk_dev_is_tray_open(blk)) {
+        error_setg(errp, "Tray of device '%s' is not open", device);
+        return;
+    }
+
+    if (blk_bs(blk)) {
+        error_setg(errp, "There already is a medium in device '%s'", device);
+        return;
+    }
+
+    blk_insert_bs(blk, bs);
+}
+
+void qmp_blockdev_insert_medium(const char *device, const char *node_name,
+                                Error **errp)
+{
+    BlockDriverState *bs;
+
+    bs = bdrv_find_node(node_name);
+    if (!bs) {
+        error_setg(errp, "Node '%s' not found", node_name);
+        return;
+    }
+
+    qmp_blockdev_insert_anon_medium(device, bs, errp);
+}
+
 /* throttling disk I/O limits */
 void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
                                int64_t bps_wr,
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 7f0f21c..d5de622 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1784,6 +1784,23 @@
 { 'command': 'blockdev-remove-medium',
   'data': { 'device': 'str' } }
 
+##
+# @blockdev-insert-medium:
+#
+# Inserts a medium (a block driver state tree) into a block device. That block
+# device's tray must currently be open and there must be no medium inserted
+# already.
+#
+# @device:    block device name
+#
+# @node-name: name of a node in the block driver state graph
+#
+# Since: 2.3
+##
+{ 'command': 'blockdev-insert-medium',
+  'data': { 'device': 'str',
+            'node-name': 'str'} }
+
 
 ##
 # @BlockErrorAction
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 1bd39b7..70b05e2 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3774,6 +3774,43 @@ Example:
 EQMP
 
     {
+        .name       = "blockdev-insert-medium",
+        .args_type  = "device:s,node-name:s",
+        .mhandler.cmd_new = qmp_marshal_input_blockdev_insert_medium,
+    },
+
+SQMP
+blockdev-insert-medium
+----------------------
+
+Inserts a medium (a block driver state tree) into a block device. That block
+device's tray must currently be open and there must be no medium inserted
+already.
+
+Arguments:
+
+- "device": block device name (json-string)
+- "node-name": root node of the BDS tree to insert into the block device
+
+Example:
+
+-> { "execute": "blockdev-add",
+     "arguments": { "options": { "node-name": "node0",
+                                 "driver": "raw",
+                                 "file": { "driver": "file",
+                                           "filename": "fedora.iso" } } } }
+
+<- { "return": {} }
+
+-> { "execute": "blockdev-insert-medium",
+     "arguments": { "device": "ide1-cd0",
+                    "node-name": "node0" } }
+
+<- { "return": {} }
+
+EQMP
+
+    {
         .name       = "query-named-block-nodes",
         .args_type  = "",
         .mhandler.cmd_new = qmp_marshal_input_query_named_block_nodes,
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 29/37] blockdev: Implement eject with basic operations
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (27 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 28/37] blockdev: Add blockdev-insert-medium Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 30/37] blockdev: Implement change " Max Reitz
                   ` (7 subsequent siblings)
  36 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

Implement 'eject' by calling blockdev-open-tray and
blockdev-remove-medium.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 blockdev.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 819a3c1..d4f7b9b 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1867,15 +1867,15 @@ out:
 
 void qmp_eject(const char *device, bool has_force, bool force, Error **errp)
 {
-    BlockBackend *blk;
+    Error *local_err = NULL;
 
-    blk = blk_by_name(device);
-    if (!blk) {
-        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+    qmp_blockdev_open_tray(device, has_force, force, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
         return;
     }
 
-    eject_device(blk, force, errp);
+    qmp_blockdev_remove_medium(device, errp);
 }
 
 void qmp_block_passwd(bool has_device, const char *device,
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 30/37] blockdev: Implement change with basic operations
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (28 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 29/37] blockdev: Implement eject with basic operations Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 22:28   ` Eric Blake
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 31/37] block: Inquire tray state before tray-moved events Max Reitz
                   ` (6 subsequent siblings)
  36 siblings, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

Implement 'change' on block devices by calling blockdev-open-tray,
blockdev-remove-medium, blockdev-insert-medium (a variation of that
which does not need a node-name) and blockdev-close-tray.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 blockdev.c | 185 +++++++++++++++++++++++++------------------------------------
 1 file changed, 77 insertions(+), 108 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index d4f7b9b..713c484 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1830,41 +1830,6 @@ exit:
     }
 }
 
-
-static void eject_device(BlockBackend *blk, int force, Error **errp)
-{
-    BlockDriverState *bs = blk_bs(blk);
-    AioContext *aio_context;
-
-    aio_context = blk_get_aio_context(blk);
-    aio_context_acquire(aio_context);
-
-    if (bs && bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
-        goto out;
-    }
-    if (!blk_dev_has_removable_media(blk)) {
-        error_setg(errp, "Device '%s' is not removable",
-                   bdrv_get_device_name(bs));
-        goto out;
-    }
-
-    if (blk_dev_is_medium_locked(blk) && !blk_dev_is_tray_open(blk)) {
-        blk_dev_eject_request(blk, force);
-        if (!force) {
-            error_setg(errp, "Device '%s' is locked",
-                       bdrv_get_device_name(bs));
-            goto out;
-        }
-    }
-
-    if (bs) {
-        bdrv_close(bs);
-    }
-
-out:
-    aio_context_release(aio_context);
-}
-
 void qmp_eject(const char *device, bool has_force, bool force, Error **errp)
 {
     Error *local_err = NULL;
@@ -1902,79 +1867,6 @@ void qmp_block_passwd(bool has_device, const char *device,
     aio_context_release(aio_context);
 }
 
-/* Assumes AioContext is held */
-static void qmp_bdrv_open_encrypted(BlockDriverState **pbs,
-                                    const char *filename,
-                                    int bdrv_flags, BlockDriver *drv,
-                                    const char *password, Error **errp)
-{
-    BlockDriverState *bs;
-    Error *local_err = NULL;
-    int ret;
-
-    ret = bdrv_open(pbs, filename, NULL, NULL, bdrv_flags, drv, &local_err);
-    if (ret < 0) {
-        error_propagate(errp, local_err);
-        return;
-    }
-    bs = *pbs;
-
-    bdrv_add_key(bs, password, errp);
-}
-
-void qmp_change_blockdev(const char *device, const char *filename,
-                         const char *format, Error **errp)
-{
-    BlockBackend *blk;
-    BlockDriverState *bs;
-    AioContext *aio_context;
-    BlockDriver *drv = NULL;
-    int bdrv_flags;
-    bool new_bs;
-    Error *err = NULL;
-
-    blk = blk_by_name(device);
-    if (!blk) {
-        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
-        return;
-    }
-    bs = blk_bs(blk);
-    new_bs = !bs;
-
-    aio_context = blk_get_aio_context(blk);
-    aio_context_acquire(aio_context);
-
-    if (format) {
-        drv = bdrv_find_whitelisted_format(format, blk_is_read_only(blk));
-        if (!drv) {
-            error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
-            goto out;
-        }
-    }
-
-    eject_device(blk, 0, &err);
-    if (err) {
-        error_propagate(errp, err);
-        goto out;
-    }
-
-    bdrv_flags = blk_is_read_only(blk) ? 0 : BDRV_O_RDWR;
-    bdrv_flags |= blk_get_root_state(blk)->open_flags & ~BDRV_O_RDWR;
-
-    qmp_bdrv_open_encrypted(&bs, filename, bdrv_flags, drv, NULL, &err);
-    if (err) {
-        error_propagate(errp, err);
-    } else if (new_bs) {
-        blk_insert_bs(blk, bs);
-        /* Has been sent automatically by bdrv_open() if blk_bs(blk) was not
-         * NULL */
-        blk_dev_change_media_cb(blk, true);
-    }
-
-out:
-    aio_context_release(aio_context);
-}
-
 void qmp_blockdev_open_tray(const char *device, bool has_force, bool force,
                             Error **errp)
 {
@@ -2113,6 +2005,83 @@ void qmp_blockdev_insert_medium(const char *device, const char *node_name,
     qmp_blockdev_insert_anon_medium(device, bs, errp);
 }
 
+void qmp_change_blockdev(const char *device, const char *filename,
+                         const char *format, Error **errp)
+{
+    BlockBackend *blk;
+    BlockBackendRootState *blk_rs;
+    BlockDriverState *medium_bs = NULL;
+    BlockDriver *drv = NULL;
+    int bdrv_flags, ret;
+    Error *err = NULL;
+
+    blk = blk_by_name(device);
+    if (!blk) {
+        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+        goto fail;
+    }
+
+    if (blk_bs(blk)) {
+        blk_update_root_state(blk);
+    }
+
+    blk_rs = blk_get_root_state(blk);
+    bdrv_flags = blk_rs->read_only ? 0 : BDRV_O_RDWR;
+    bdrv_flags |= blk_rs->open_flags & ~BDRV_O_RDWR;
+
+    if (format) {
+        drv = bdrv_find_whitelisted_format(format, bdrv_flags & BDRV_O_RDWR);
+        if (!drv) {
+            error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
+            goto fail;
+        }
+    }
+
+    assert(!medium_bs);
+    ret = bdrv_open(&medium_bs, filename, NULL, NULL, bdrv_flags, drv, errp);
+    if (ret < 0) {
+        goto fail;
+    }
+
+    medium_bs->detect_zeroes = blk_rs->detect_zeroes;
+    if (blk_rs->io_limits_enabled) {
+        bdrv_io_limits_enable(medium_bs);
+        bdrv_set_io_limits(medium_bs, &blk_rs->throttle_config);
+    }
+
+    bdrv_add_key(medium_bs, NULL, &err);
+    if (err) {
+        error_propagate(errp, err);
+        goto fail;
+    }
+
+    qmp_blockdev_open_tray(device, false, false, &err);
+    if (err) {
+        error_propagate(errp, err);
+        goto fail;
+    }
+
+    qmp_blockdev_remove_medium(device, &err);
+    if (err) {
+        error_propagate(errp, err);
+        goto fail;
+    }
+
+    qmp_blockdev_insert_anon_medium(device, medium_bs, &err);
+    if (err) {
+        error_propagate(errp, err);
+        goto fail;
+    }
+
+    qmp_blockdev_close_tray(device, errp);
+
+fail:
+    /* If the medium has been inserted, the device has its own reference, so
+     * ours must be relinquished; and if it has not been inserted successfully,
+     * the reference must be relinquished anyway */
+    bdrv_unref(medium_bs);
+}
+
 /* throttling disk I/O limits */
 void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
                                int64_t bps_wr,
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 31/37] block: Inquire tray state before tray-moved events
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (29 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 30/37] blockdev: Implement change " Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 32/37] qmp: Introduce blockdev-change-medium Max Reitz
                   ` (5 subsequent siblings)
  36 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

blk_dev_change_media_cb() is called for all potential tray movements;
however, it is possible to request closing the tray but nothing actually
happening (on a floppy disk drive without a medium).

Thus, the actual tray status should be inquired before sending a
tray-moved event (and an event should be sent whenever the status
changed).

Checking @load is now superfluous; it was necessary because it was
possible to change a medium without having explicitly opened the tray
and closed it again (or it might have been possible, at least). This is
no longer possible, though.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/block-backend.c | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 00e96da..ad0af67 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -420,18 +420,15 @@ void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops,
 void blk_dev_change_media_cb(BlockBackend *blk, bool load)
 {
     if (blk->dev_ops && blk->dev_ops->change_media_cb) {
-        bool tray_was_closed = !blk_dev_is_tray_open(blk);
+        bool tray_was_open, tray_is_open;
 
+        tray_was_open = blk_dev_is_tray_open(blk);
         blk->dev_ops->change_media_cb(blk->dev_opaque, load);
-        if (tray_was_closed) {
-            /* tray open */
-            qapi_event_send_device_tray_moved(blk_name(blk),
-                                              true, &error_abort);
-        }
-        if (load) {
-            /* tray close */
-            qapi_event_send_device_tray_moved(blk_name(blk),
-                                              false, &error_abort);
+        tray_is_open = blk_dev_is_tray_open(blk);
+
+        if (tray_was_open != tray_is_open) {
+            qapi_event_send_device_tray_moved(blk_name(blk), tray_is_open,
+                                              &error_abort);
         }
     }
 }
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 32/37] qmp: Introduce blockdev-change-medium
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (30 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 31/37] block: Inquire tray state before tray-moved events Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 23:09   ` Eric Blake
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 33/37] hmp: Use blockdev-change-medium for change command Max Reitz
                   ` (4 subsequent siblings)
  36 siblings, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

Introduce a new QMP command 'blockdev-change-medium' which is intended
to replace the 'change' command for block devices. The existing function
qmp_change_blockdev() is accordingly renamed to
qmp_blockdev_change_medium().

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 blockdev.c                |  7 ++++---
 include/sysemu/blockdev.h |  2 --
 qapi-schema.json          |  6 ++++--
 qapi/block-core.json      | 23 +++++++++++++++++++++++
 qmp-commands.hx           | 31 +++++++++++++++++++++++++++++++
 qmp.c                     |  2 +-
 6 files changed, 63 insertions(+), 8 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 713c484..7574946 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2005,8 +2005,9 @@ void qmp_blockdev_insert_medium(const char *device, const char *node_name,
     qmp_blockdev_insert_anon_medium(device, bs, errp);
 }
 
-void qmp_change_blockdev(const char *device, const char *filename,
-                         const char *format, Error **errp)
+void qmp_blockdev_change_medium(const char *device, const char *filename,
+                                bool has_format, const char *format,
+                                Error **errp)
 {
     BlockBackend *blk;
     BlockBackendRootState *blk_rs;
@@ -2029,7 +2030,7 @@ void qmp_change_blockdev(const char *device, const char *filename,
     bdrv_flags = blk_rs->read_only ? 0 : BDRV_O_RDWR;
     bdrv_flags |= blk_rs->open_flags & ~BDRV_O_RDWR;
 
-    if (format) {
+    if (has_format) {
         drv = bdrv_find_whitelisted_format(format, bdrv_flags & BDRV_O_RDWR);
         if (!drv) {
             error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
index 09d1e30..2a34332 100644
--- a/include/sysemu/blockdev.h
+++ b/include/sysemu/blockdev.h
@@ -65,8 +65,6 @@ DriveInfo *drive_new(QemuOpts *arg, BlockInterfaceType block_default_type);
 
 DriveInfo *add_init_drive(const char *opts);
 
-void qmp_change_blockdev(const char *device, const char *filename,
-                         const char *format, Error **errp);
 void do_commit(Monitor *mon, const QDict *qdict);
 int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
 #endif
diff --git a/qapi-schema.json b/qapi-schema.json
index e16f8eb..3bf3ab6 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1648,8 +1648,10 @@
 #          device's password.  The behavior of reads and writes to the block
 #          device between when these calls are executed is undefined.
 #
-# Notes:  It is strongly recommended that this interface is not used especially
-#         for changing block devices.
+# Notes:  This interface is deprecated, and it is strongly recommended that you
+#         avoid using it.  For changing block devices, use
+#         blockdev-change-medium; for changing VNC parameters, use
+#         change-vnc-password.
 #
 # Since: 0.14.0
 ##
diff --git a/qapi/block-core.json b/qapi/block-core.json
index d5de622..973f860 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1803,6 +1803,29 @@
 
 
 ##
+# @blockdev-change-medium:
+#
+# Changes the medium inserted into a block device by ejecting the current medium
+# and loading a new image file which is inserted as the new medium (this command
+# combines blockdev-open-tray, blockdev-remove-medium, blockdev-insert-medium
+# and blockdev-close-tray).
+#
+# @device:          block device name
+#
+# @filename:        filename of the new image to be loaded
+#
+# @format:          #optional, format to open the new image with (defaults to
+#                   the probed format)
+#
+# Since: 2.3
+##
+{ 'command': 'blockdev-change-medium',
+  'data': { 'device': 'str',
+            'filename': 'str',
+            '*format': 'str' } }
+
+
+##
 # @BlockErrorAction
 #
 # An enumeration of action that has been taken when a DISK I/O occurs
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 70b05e2..9b1d4eb 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3873,6 +3873,37 @@ Example:
 EQMP
 
     {
+        .name       = "blockdev-change-medium",
+        .args_type  = "device:B,filename:F,format:s?",
+        .mhandler.cmd_new = qmp_marshal_input_blockdev_change_medium,
+    },
+
+SQMP
+blockdev-change-medium
+----------------------
+
+Changes the medium inserted into a block device by ejecting the current medium
+and loading a new image file which is inserted as the new medium.
+
+Arguments:
+
+- "device": device name (json-string)
+- "filename": filename of the new image (json-string)
+- "format": format of the new image (json-string, optional)
+
+Examples:
+
+1. Change a removable medium
+
+-> { "execute": "blockdev-change-medium",
+             "arguments": { "device": "ide1-cd0",
+                            "filename": "/srv/images/Fedora-12-x86_64-DVD.iso",
+                            "format": "raw" } }
+<- { "return": {} }
+
+EQMP
+
+    {
         .name       = "query-memdev",
         .args_type  = "",
         .mhandler.cmd_new = qmp_marshal_input_query_memdev,
diff --git a/qmp.c b/qmp.c
index 6028529..ba900c3 100644
--- a/qmp.c
+++ b/qmp.c
@@ -417,7 +417,7 @@ void qmp_change(const char *device, const char *target,
     if (strcmp(device, "vnc") == 0) {
         qmp_change_vnc(target, has_arg, arg, errp);
     } else {
-        qmp_change_blockdev(device, target, arg, errp);
+        qmp_blockdev_change_medium(device, target, has_arg, arg, errp);
     }
 }
 
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 33/37] hmp: Use blockdev-change-medium for change command
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (31 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 32/37] qmp: Introduce blockdev-change-medium Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 34/37] blockdev: read-only-mode for blockdev-change-medium Max Reitz
                   ` (3 subsequent siblings)
  36 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

Use separate code paths for the two overloaded functions of the 'change'
HMP command, and invoke the 'blockdev-change-medium' QMP command if used
on a block device (by calling qmp_blockdev_change_medium()).

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 hmp.c | 27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/hmp.c b/hmp.c
index 3825b29..c874437 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1186,22 +1186,25 @@ void hmp_change(Monitor *mon, const QDict *qdict)
     const char *arg = qdict_get_try_str(qdict, "arg");
     Error *err = NULL;
 
-    if (strcmp(device, "vnc") == 0 &&
-            (strcmp(target, "passwd") == 0 ||
-             strcmp(target, "password") == 0)) {
-        if (!arg) {
-            monitor_read_password(mon, hmp_change_read_arg, NULL);
+    if (strcmp(device, "vnc") == 0) {
+        if (strcmp(target, "passwd") == 0 ||
+            strcmp(target, "password") == 0) {
+            if (!arg) {
+                monitor_read_password(mon, hmp_change_read_arg, NULL);
+                return;
+            }
+        }
+        qmp_change("vnc", target, !!arg, arg, &err);
+    } else {
+        qmp_blockdev_change_medium(device, target, !!arg, arg, &err);
+        if (err &&
+            error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
+            error_free(err);
+            monitor_read_block_device_key(mon, device, NULL, NULL);
             return;
         }
     }
 
-    qmp_change(device, target, !!arg, arg, &err);
-    if (err &&
-        error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
-        error_free(err);
-        monitor_read_block_device_key(mon, device, NULL, NULL);
-        return;
-    }
     hmp_handle_error(mon, &err);
 }
 
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 34/37] blockdev: read-only-mode for blockdev-change-medium
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (32 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 33/37] hmp: Use blockdev-change-medium for change command Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 23:15   ` Eric Blake
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 35/37] hmp: Add read-only-mode option to change command Max Reitz
                   ` (2 subsequent siblings)
  36 siblings, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

Add an option to qmp_blockdev_change_medium() which allows changing the
read-only status of the block device whose medium is changed.

Some drives do not have a inherently fixed read-only status; for
instance, floppy disks can be set read-only or writable independently of
the drive. Some users may find it useful to be able to therefore change
the read-only status of a block device when changing the medium.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 blockdev.c           | 25 ++++++++++++++++++++++++-
 hmp.c                |  2 +-
 qapi/block-core.json | 24 +++++++++++++++++++++++-
 qmp-commands.hx      | 24 +++++++++++++++++++++++-
 qmp.c                |  3 ++-
 5 files changed, 73 insertions(+), 5 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 7574946..f198be6 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2007,6 +2007,8 @@ void qmp_blockdev_insert_medium(const char *device, const char *node_name,
 
 void qmp_blockdev_change_medium(const char *device, const char *filename,
                                 bool has_format, const char *format,
+                                bool has_read_only,
+                                BlockdevChangeReadOnlyMode read_only,
                                 Error **errp)
 {
     BlockBackend *blk;
@@ -2027,7 +2029,28 @@ void qmp_blockdev_change_medium(const char *device, const char *filename,
     }
 
     blk_rs = blk_get_root_state(blk);
-    bdrv_flags = blk_rs->read_only ? 0 : BDRV_O_RDWR;
+
+    if (!has_read_only) {
+        read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
+    }
+
+    switch (read_only) {
+    case BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN:
+        bdrv_flags = blk_rs->read_only ? 0 : BDRV_O_RDWR;
+        break;
+
+    case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_ONLY:
+        bdrv_flags = 0;
+        break;
+
+    case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_WRITE:
+        bdrv_flags = BDRV_O_RDWR;
+        break;
+
+    default:
+        abort();
+    }
+
     bdrv_flags |= blk_rs->open_flags & ~BDRV_O_RDWR;
 
     if (has_format) {
diff --git a/hmp.c b/hmp.c
index c874437..5125f4f 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1196,7 +1196,7 @@ void hmp_change(Monitor *mon, const QDict *qdict)
         }
         qmp_change("vnc", target, !!arg, arg, &err);
     } else {
-        qmp_blockdev_change_medium(device, target, !!arg, arg, &err);
+        qmp_blockdev_change_medium(device, target, !!arg, arg, false, 0, &err);
         if (err &&
             error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
             error_free(err);
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 973f860..8a23446 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1803,6 +1803,24 @@
 
 
 ##
+# @BlockdevChangeReadOnlyMode:
+#
+# Specifies the new read-only mode of a block device subject to the
+# @blockdev-change-medium command.
+#
+# @retain:      Retains the current read-only mode
+#
+# @read-only:   Makes the device read-only
+#
+# @read-write:  Makes the device writable
+#
+# Since: 2.3
+##
+{ 'enum': 'BlockdevChangeReadOnlyMode',
+  'data': ['retain', 'read-only', 'read-write'] }
+
+
+##
 # @blockdev-change-medium:
 #
 # Changes the medium inserted into a block device by ejecting the current medium
@@ -1817,12 +1835,16 @@
 # @format:          #optional, format to open the new image with (defaults to
 #                   the probed format)
 #
+# @read-only-mode:  #optional, change the read-only mode of the device; defaults
+#                   to 'retain'
+#
 # Since: 2.3
 ##
 { 'command': 'blockdev-change-medium',
   'data': { 'device': 'str',
             'filename': 'str',
-            '*format': 'str' } }
+            '*format': 'str',
+            '*read-only-mode': 'BlockdevChangeReadOnlyMode' } }
 
 
 ##
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 9b1d4eb..7cc6d9a 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3874,7 +3874,7 @@ EQMP
 
     {
         .name       = "blockdev-change-medium",
-        .args_type  = "device:B,filename:F,format:s?",
+        .args_type  = "device:B,filename:F,format:s?,read-only-mode:s?",
         .mhandler.cmd_new = qmp_marshal_input_blockdev_change_medium,
     },
 
@@ -3890,6 +3890,8 @@ Arguments:
 - "device": device name (json-string)
 - "filename": filename of the new image (json-string)
 - "format": format of the new image (json-string, optional)
+- "read-only-mode": new read-only mode (json-string, optional)
+          - Possible values: "retain" (default), "read-only", "read-write"
 
 Examples:
 
@@ -3901,6 +3903,26 @@ Examples:
                             "format": "raw" } }
 <- { "return": {} }
 
+2. Load a read-only medium into a writable drive
+
+-> { "execute": "blockdev-change-medium",
+             "arguments": { "device": "isa-fd0",
+                            "filename": "/srv/images/ro.img",
+                            "format": "raw",
+                            "read-only-mode": "retain" } }
+
+<- { "error":
+     { "class": "GenericError",
+       "desc": "Could not open '/srv/images/ro.img': Permission denied" } }
+
+-> { "execute": "blockdev-change-medium",
+             "arguments": { "device": "isa-fd0",
+                            "filename": "/srv/images/ro.img",
+                            "format": "raw",
+                            "read-only-mode": "read-only" } }
+
+<- { "return": {} }
+
 EQMP
 
     {
diff --git a/qmp.c b/qmp.c
index ba900c3..2e381a1 100644
--- a/qmp.c
+++ b/qmp.c
@@ -417,7 +417,8 @@ void qmp_change(const char *device, const char *target,
     if (strcmp(device, "vnc") == 0) {
         qmp_change_vnc(target, has_arg, arg, errp);
     } else {
-        qmp_blockdev_change_medium(device, target, has_arg, arg, errp);
+        qmp_blockdev_change_medium(device, target, has_arg, arg, false, 0,
+                                   errp);
     }
 }
 
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 35/37] hmp: Add read-only-mode option to change command
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (33 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 34/37] blockdev: read-only-mode for blockdev-change-medium Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 23:17   ` Eric Blake
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 36/37] iotests: More options for VM.add_drive() Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 37/37] iotests: Add test for change-related QMP commands Max Reitz
  36 siblings, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

Expose the new read-only-mode option of 'blockdev-change-medium' for the
'change' HMP command.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 hmp-commands.hx | 20 +++++++++++++++++---
 hmp.c           | 22 +++++++++++++++++++++-
 2 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index e37bc8b..9d412ea 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -196,8 +196,8 @@ ETEXI
 
     {
         .name       = "change",
-        .args_type  = "device:B,target:F,arg:s?",
-        .params     = "device filename [format]",
+        .args_type  = "device:B,target:F,arg:s?,read-only-mode:s?",
+        .params     = "device filename [format [read-only-mode]]",
         .help       = "change a removable medium, optional format",
         .mhandler.cmd = hmp_change,
     },
@@ -209,7 +209,7 @@ STEXI
 Change the configuration of a device.
 
 @table @option
-@item change @var{diskdevice} @var{filename} [@var{format}]
+@item change @var{diskdevice} @var{filename} [@var{format} [@var{read-only-mode}]]
 Change the medium for a removable disk device to point to @var{filename}. eg
 
 @example
@@ -218,6 +218,20 @@ Change the medium for a removable disk device to point to @var{filename}. eg
 
 @var{format} is optional.
 
+@var{read-only-mode} may be used to change the read-only status of the device.
+It accepts the following values:
+
+@table @var
+@item retain
+Retains the current status; this is the default.
+
+@item read-only
+Makes the device read-only.
+
+@item read-write
+Makes the device writable.
+@end table
+
 @item change vnc @var{display},@var{options}
 Change the configuration of the VNC server. The valid syntax for @var{display}
 and @var{options} are described at @ref{sec_invocation}. eg
diff --git a/hmp.c b/hmp.c
index 5125f4f..4bab14f 100644
--- a/hmp.c
+++ b/hmp.c
@@ -24,6 +24,7 @@
 #include "monitor/monitor.h"
 #include "qapi/opts-visitor.h"
 #include "qapi/string-output-visitor.h"
+#include "qapi/util.h"
 #include "qapi-visit.h"
 #include "ui/console.h"
 #include "block/qapi.h"
@@ -1184,9 +1185,16 @@ void hmp_change(Monitor *mon, const QDict *qdict)
     const char *device = qdict_get_str(qdict, "device");
     const char *target = qdict_get_str(qdict, "target");
     const char *arg = qdict_get_try_str(qdict, "arg");
+    const char *read_only = qdict_get_try_str(qdict, "read-only-mode");
+    BlockdevChangeReadOnlyMode read_only_mode = 0;
     Error *err = NULL;
 
     if (strcmp(device, "vnc") == 0) {
+        if (read_only) {
+            monitor_printf(mon,
+                           "Parameter 'read-only-mode' is invalid for VNC");
+            return;
+        }
         if (strcmp(target, "passwd") == 0 ||
             strcmp(target, "password") == 0) {
             if (!arg) {
@@ -1196,7 +1204,19 @@ void hmp_change(Monitor *mon, const QDict *qdict)
         }
         qmp_change("vnc", target, !!arg, arg, &err);
     } else {
-        qmp_blockdev_change_medium(device, target, !!arg, arg, false, 0, &err);
+        if (read_only) {
+            read_only_mode =
+                qapi_enum_parse(BlockdevChangeReadOnlyMode_lookup,
+                                read_only, BLOCKDEV_CHANGE_READ_ONLY_MODE_MAX,
+                                BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN, &err);
+            if (err) {
+                hmp_handle_error(mon, &err);
+                return;
+            }
+        }
+
+        qmp_blockdev_change_medium(device, target, !!arg, arg,
+                                   !!read_only, read_only_mode, &err);
         if (err &&
             error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
             error_free(err);
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 36/37] iotests: More options for VM.add_drive()
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (34 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 35/37] hmp: Add read-only-mode option to change command Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 37/37] iotests: Add test for change-related QMP commands Max Reitz
  36 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

This patch allows specifying the interface to be used for the drive, and
makes specifying a path optional (if the path is None, the "file" option
will be omitted, thus creating an empty drive).

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 tests/qemu-iotests/iotests.py | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 241b5ee..5191a65 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -94,13 +94,16 @@ class VM(object):
         self._args.append('-monitor')
         self._args.append(args)
 
-    def add_drive(self, path, opts=''):
+    def add_drive(self, path, opts='', interface='virtio'):
         '''Add a virtio-blk drive to the VM'''
-        options = ['if=virtio',
+        options = ['if=%s' % interface,
                    'format=%s' % imgfmt,
                    'cache=%s' % cachemode,
-                   'file=%s' % path,
                    'id=drive%d' % self._num_drives]
+
+        if path is not None:
+            options.append('file=%s' % path)
+
         if opts:
             options.append(opts)
 
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [Qemu-devel] [PATCH v2 37/37] iotests: Add test for change-related QMP commands
  2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
                   ` (35 preceding siblings ...)
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 36/37] iotests: More options for VM.add_drive() Max Reitz
@ 2015-02-09 17:11 ` Max Reitz
  2015-02-10  0:06   ` Eric Blake
  36 siblings, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-02-09 17:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Markus Armbruster, Max Reitz, Stefan Hajnoczi, John Snow

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/118     | 653 +++++++++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/118.out |   5 +
 tests/qemu-iotests/group   |   1 +
 3 files changed, 659 insertions(+)
 create mode 100755 tests/qemu-iotests/118
 create mode 100644 tests/qemu-iotests/118.out

diff --git a/tests/qemu-iotests/118 b/tests/qemu-iotests/118
new file mode 100755
index 0000000..f5b1a4e
--- /dev/null
+++ b/tests/qemu-iotests/118
@@ -0,0 +1,653 @@
+#!/usr/bin/env python
+#
+# Test case for the QMP 'change' command and all other associated
+# commands
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+import stat
+import iotests
+from iotests import qemu_img
+
+old_img = os.path.join(iotests.test_dir, 'test0.img')
+new_img = os.path.join(iotests.test_dir, 'test1.img')
+
+class ChangeBaseClass(iotests.QMPTestCase):
+    has_opened = False
+    has_closed = False
+
+    def process_events(self):
+        for event in self.vm.get_qmp_events(wait=True):
+            if event['event'] == 'DEVICE_TRAY_MOVED' and event['data']['device'] == 'drive0':
+                if event['data']['tray-open'] == False:
+                    self.has_closed = True
+                else:
+                    self.has_opened = True
+
+class GeneralChangeTestsBaseClass(ChangeBaseClass):
+    def test_change(self):
+        result = self.vm.qmp('change', device='drive0', target=new_img,
+                                       arg=iotests.imgfmt)
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_opened:
+            self.process_events()
+        while not self.has_closed:
+            self.process_events()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+    def test_blockdev_change_medium(self):
+        result = self.vm.qmp('blockdev-change-medium', device='drive0',
+                                                       filename=new_img,
+                                                       format=iotests.imgfmt)
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_opened:
+            self.process_events()
+        while not self.has_closed:
+            self.process_events()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+    def test_eject(self):
+        result = self.vm.qmp('eject', device='drive0', force=True)
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_opened:
+            self.process_events()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', True)
+        self.assert_qmp_absent(result, 'return[0]/inserted')
+
+    def test_tray_eject_change(self):
+        result = self.vm.qmp('eject', device='drive0', force=True)
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_opened:
+            self.process_events()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', True)
+        self.assert_qmp_absent(result, 'return[0]/inserted')
+
+        result = self.vm.qmp('blockdev-change-medium', device='drive0',
+                                                       filename=new_img,
+                                                       format=iotests.imgfmt)
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_closed:
+            self.process_events()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+    def test_tray_open_close(self):
+        result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True)
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_opened:
+            self.process_events()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', True)
+        if self.was_empty == True:
+            self.assert_qmp_absent(result, 'return[0]/inserted')
+        else:
+            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+        result = self.vm.qmp('blockdev-close-tray', device='drive0')
+        self.assert_qmp(result, 'return', {})
+
+        if self.has_real_tray or not self.was_empty:
+            while not self.has_closed:
+                self.process_events()
+
+        result = self.vm.qmp('query-block')
+        if self.has_real_tray or not self.was_empty:
+            self.assert_qmp(result, 'return[0]/tray_open', False)
+        else:
+            self.assert_qmp(result, 'return[0]/tray_open', True)
+        if self.was_empty == True:
+            self.assert_qmp_absent(result, 'return[0]/inserted')
+        else:
+            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+    def test_tray_eject_close(self):
+        result = self.vm.qmp('eject', device='drive0', force=True)
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_opened:
+            self.process_events()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', True)
+        self.assert_qmp_absent(result, 'return[0]/inserted')
+
+        result = self.vm.qmp('blockdev-close-tray', device='drive0')
+        self.assert_qmp(result, 'return', {})
+
+        if self.has_real_tray:
+            while not self.has_closed:
+                self.process_events()
+
+        result = self.vm.qmp('query-block')
+        if self.has_real_tray:
+            self.assert_qmp(result, 'return[0]/tray_open', False)
+        else:
+            self.assert_qmp(result, 'return[0]/tray_open', True)
+        self.assert_qmp_absent(result, 'return[0]/inserted')
+
+    def test_tray_open_change(self):
+        result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True)
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_opened:
+            self.process_events()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', True)
+        if self.was_empty == True:
+            self.assert_qmp_absent(result, 'return[0]/inserted')
+        else:
+            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+        result = self.vm.qmp('blockdev-change-medium', device='drive0',
+                                                       filename=new_img,
+                                                       format=iotests.imgfmt)
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_closed:
+            self.process_events()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+    def test_cycle(self):
+        result = self.vm.qmp('blockdev-add',
+                             options={'node-name': 'new',
+                                      'driver': iotests.imgfmt,
+                                      'file': {'filename': new_img,
+                                               'driver': 'file'}})
+        self.assert_qmp(result, 'return', {})
+
+        result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True)
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_opened:
+            self.process_events()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', True)
+        if self.was_empty == True:
+            self.assert_qmp_absent(result, 'return[0]/inserted')
+        else:
+            self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+        result = self.vm.qmp('blockdev-remove-medium', device='drive0')
+        self.assert_qmp(result, 'return', {})
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', True)
+        self.assert_qmp_absent(result, 'return[0]/inserted')
+
+        result = self.vm.qmp('blockdev-insert-medium', device='drive0',
+                                                       node_name='new')
+        self.assert_qmp(result, 'return', {})
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', True)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+        result = self.vm.qmp('blockdev-close-tray', device='drive0')
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_closed:
+            self.process_events()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+    def test_close_on_closed(self):
+        result = self.vm.qmp('blockdev-close-tray', device='drive0')
+        # Should be a no-op
+        self.assert_qmp(result, 'return', {})
+        self.assertEquals(self.vm.get_qmp_events(wait=False), [])
+
+    def test_remove_on_closed(self):
+        if self.has_opened:
+            # Empty floppy drive
+            return
+
+        result = self.vm.qmp('blockdev-remove-medium', device='drive0')
+        self.assert_qmp(result, 'error/class', 'GenericError')
+
+    def test_insert_on_closed(self):
+        if self.has_opened:
+            # Empty floppy drive
+            return
+
+        result = self.vm.qmp('blockdev-add',
+                             options={'node-name': 'new',
+                                      'driver': iotests.imgfmt,
+                                      'file': {'filename': new_img,
+                                               'driver': 'file'}})
+        self.assert_qmp(result, 'return', {})
+
+        result = self.vm.qmp('blockdev-insert-medium', device='drive0',
+                                                       node_name='new')
+        self.assert_qmp(result, 'error/class', 'GenericError')
+
+class TestInitiallyFilled(GeneralChangeTestsBaseClass):
+    was_empty = False
+
+    def setUp(self, media, interface):
+        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
+        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
+        self.vm = iotests.VM().add_drive(old_img, 'media=%s' % media, interface)
+        self.vm.launch()
+
+    def tearDown(self):
+        self.vm.shutdown()
+        os.remove(old_img)
+        os.remove(new_img)
+
+    def test_insert_on_filled(self):
+        result = self.vm.qmp('blockdev-add',
+                             options={'node-name': 'new',
+                                      'driver': iotests.imgfmt,
+                                      'file': {'filename': new_img,
+                                               'driver': 'file'}})
+        self.assert_qmp(result, 'return', {})
+
+        result = self.vm.qmp('blockdev-open-tray', device='drive0')
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_opened:
+            self.process_events()
+
+        result = self.vm.qmp('blockdev-insert-medium', device='drive0',
+                                                       node_name='new')
+        self.assert_qmp(result, 'error/class', 'GenericError')
+
+class TestInitiallyEmpty(GeneralChangeTestsBaseClass):
+    was_empty = True
+
+    def setUp(self, media, interface):
+        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
+        self.vm = iotests.VM().add_drive(None, 'media=%s' % media, interface)
+        self.vm.launch()
+
+    def tearDown(self):
+        self.vm.shutdown()
+        os.remove(new_img)
+
+    def test_remove_on_empty(self):
+        result = self.vm.qmp('blockdev-open-tray', device='drive0')
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_opened:
+            self.process_events()
+
+        result = self.vm.qmp('blockdev-remove-medium', device='drive0')
+        # Should be a no-op
+        self.assert_qmp(result, 'return', {})
+
+class TestCDInitiallyFilled(TestInitiallyFilled):
+    TestInitiallyFilled = TestInitiallyFilled
+    has_real_tray = True
+
+    def setUp(self):
+        self.TestInitiallyFilled.setUp(self, 'cdrom', 'ide')
+
+class TestCDInitiallyEmpty(TestInitiallyEmpty):
+    TestInitiallyEmpty = TestInitiallyEmpty
+    has_real_tray = True
+
+    def setUp(self):
+        self.TestInitiallyEmpty.setUp(self, 'cdrom', 'ide')
+
+class TestFloppyInitiallyFilled(TestInitiallyFilled):
+    TestInitiallyFilled = TestInitiallyFilled
+    has_real_tray = False
+
+    def setUp(self):
+        self.TestInitiallyFilled.setUp(self, 'disk', 'floppy')
+
+class TestFloppyInitiallyEmpty(TestInitiallyEmpty):
+    TestInitiallyEmpty = TestInitiallyEmpty
+    has_real_tray = False
+
+    def setUp(self):
+        self.TestInitiallyEmpty.setUp(self, 'disk', 'floppy')
+        # FDDs not having a real tray and there not being a medium inside the
+        # tray at startup means the tray will be considered open
+        self.has_opened = True
+
+class TestChangeReadOnly(ChangeBaseClass):
+    def setUp(self):
+        qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
+        qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
+        self.vm = iotests.VM()
+
+    def tearDown(self):
+        self.vm.shutdown()
+        os.chmod(old_img, 0666)
+        os.chmod(new_img, 0666)
+        os.remove(old_img)
+        os.remove(new_img)
+
+    def test_ro_ro_retain(self):
+        os.chmod(old_img, 0444)
+        os.chmod(new_img, 0444)
+        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
+        self.vm.launch()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', True)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+        result = self.vm.qmp('blockdev-change-medium', device='drive0',
+                                                       filename=new_img,
+                                                       format=iotests.imgfmt,
+                                                       read_only_mode='retain')
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_opened:
+            self.process_events()
+        while not self.has_closed:
+            self.process_events()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', True)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+    def test_ro_rw_retain(self):
+        os.chmod(old_img, 0444)
+        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
+        self.vm.launch()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', True)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+        result = self.vm.qmp('blockdev-change-medium', device='drive0',
+                                                       filename=new_img,
+                                                       format=iotests.imgfmt,
+                                                       read_only_mode='retain')
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_opened:
+            self.process_events()
+        while not self.has_closed:
+            self.process_events()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', True)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+    def test_rw_ro_retain(self):
+        os.chmod(new_img, 0444)
+        self.vm.add_drive(old_img, 'media=disk', 'floppy')
+        self.vm.launch()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', False)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+        result = self.vm.qmp('blockdev-change-medium', device='drive0',
+                                                       filename=new_img,
+                                                       format=iotests.imgfmt,
+                                                       read_only_mode='retain')
+        self.assert_qmp(result, 'error/class', 'GenericError')
+
+        self.assertEquals(self.vm.get_qmp_events(wait=False), [])
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', False)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+    def test_ro_rw(self):
+        os.chmod(old_img, 0444)
+        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
+        self.vm.launch()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', True)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+        result = self.vm.qmp('blockdev-change-medium',
+                             device='drive0',
+                             filename=new_img,
+                             format=iotests.imgfmt,
+                             read_only_mode='read-write')
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_opened:
+            self.process_events()
+        while not self.has_closed:
+            self.process_events()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', False)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+    def test_rw_ro(self):
+        os.chmod(new_img, 0444)
+        self.vm.add_drive(old_img, 'media=disk', 'floppy')
+        self.vm.launch()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', False)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+        result = self.vm.qmp('blockdev-change-medium',
+                             device='drive0',
+                             filename=new_img,
+                             format=iotests.imgfmt,
+                             read_only_mode='read-only')
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_opened:
+            self.process_events()
+        while not self.has_closed:
+            self.process_events()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', True)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+    def test_make_rw_ro(self):
+        self.vm.add_drive(old_img, 'media=disk', 'floppy')
+        self.vm.launch()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', False)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+        result = self.vm.qmp('blockdev-change-medium',
+                             device='drive0',
+                             filename=new_img,
+                             format=iotests.imgfmt,
+                             read_only_mode='read-only')
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_opened:
+            self.process_events()
+        while not self.has_closed:
+            self.process_events()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', True)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+    def test_make_ro_rw(self):
+        os.chmod(new_img, 0444)
+        self.vm.add_drive(old_img, 'media=disk', 'floppy')
+        self.vm.launch()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', False)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+        result = self.vm.qmp('blockdev-change-medium',
+                             device='drive0',
+                             filename=new_img,
+                             format=iotests.imgfmt,
+                             read_only_mode='read-write')
+        self.assert_qmp(result, 'error/class', 'GenericError')
+
+        self.assertEquals(self.vm.get_qmp_events(wait=False), [])
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', False)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+    def test_make_rw_ro_by_retain(self):
+        os.chmod(old_img, 0444)
+        self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
+        self.vm.launch()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', True)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+        result = self.vm.qmp('blockdev-change-medium', device='drive0',
+                                                       filename=new_img,
+                                                       format=iotests.imgfmt,
+                                                       read_only_mode='retain')
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_opened:
+            self.process_events()
+        while not self.has_closed:
+            self.process_events()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', True)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+    def test_make_ro_rw_by_retain(self):
+        os.chmod(new_img, 0444)
+        self.vm.add_drive(old_img, 'media=disk', 'floppy')
+        self.vm.launch()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', False)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+        result = self.vm.qmp('blockdev-change-medium', device='drive0',
+                                                       filename=new_img,
+                                                       format=iotests.imgfmt,
+                                                       read_only_mode='retain')
+        self.assert_qmp(result, 'error/class', 'GenericError')
+
+        self.assertEquals(self.vm.get_qmp_events(wait=False), [])
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', False)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+    def test_rw_ro_cycle(self):
+        os.chmod(new_img, 0444)
+        self.vm.add_drive(old_img, 'media=disk', 'floppy')
+        self.vm.launch()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', False)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+        result = self.vm.qmp('blockdev-add',
+                             options={'node-name': 'new',
+                                      'driver': iotests.imgfmt,
+                                      'read-only': True,
+                                      'file': {'filename': new_img,
+                                               'driver': 'file'}})
+        self.assert_qmp(result, 'return', {})
+
+        result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True)
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_opened:
+            self.process_events()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', True)
+        self.assert_qmp(result, 'return[0]/inserted/ro', False)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+        result = self.vm.qmp('blockdev-remove-medium', device='drive0')
+        self.assert_qmp(result, 'return', {})
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', True)
+        self.assert_qmp_absent(result, 'return[0]/inserted')
+
+        result = self.vm.qmp('blockdev-insert-medium', device='drive0',
+                                                       node_name='new')
+        self.assert_qmp(result, 'return', {})
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', True)
+        self.assert_qmp(result, 'return[0]/inserted/ro', True)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+        result = self.vm.qmp('blockdev-close-tray', device='drive0')
+        self.assert_qmp(result, 'return', {})
+
+        while not self.has_closed:
+            self.process_events()
+
+        result = self.vm.qmp('query-block')
+        self.assert_qmp(result, 'return[0]/tray_open', False)
+        self.assert_qmp(result, 'return[0]/inserted/ro', True)
+        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+GeneralChangeTestsBaseClass = None
+TestInitiallyFilled = None
+TestInitiallyEmpty = None
+
+if __name__ == '__main__':
+    iotests.main()
diff --git a/tests/qemu-iotests/118.out b/tests/qemu-iotests/118.out
new file mode 100644
index 0000000..7d4a8ca
--- /dev/null
+++ b/tests/qemu-iotests/118.out
@@ -0,0 +1,5 @@
+..........................................................
+----------------------------------------------------------------------
+Ran 58 tests
+
+OK
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 859d0d8..9e5a6cb 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -117,3 +117,4 @@
 113 rw auto quick
 114 rw auto quick
 116 rw auto quick
+118 rw auto
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 01/37] blockdev: Allow creation of BDS trees without BB
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 01/37] blockdev: Allow creation of BDS trees without BB Max Reitz
@ 2015-02-09 18:17   ` Eric Blake
  2015-02-09 18:29     ` Max Reitz
  2015-03-04 13:39   ` Kevin Wolf
  1 sibling, 1 reply; 80+ messages in thread
From: Eric Blake @ 2015-02-09 18:17 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 2695 bytes --]

On 02/09/2015 10:11 AM, Max Reitz wrote:
> If the "id" field is missing from the options given to blockdev-add,
> just omit the BlockBackend and create the BlockDriverState tree alone.
> 
> However, if "id" is missing, "node-name" must be specified; otherwise,
> the BDS tree would no longer be accessible.
> 

Well, if we ever revived Jeff Cody's attempt at auto-assigning node
names (so that we never have an unnamed node), then this patch will have
to be partially reverted at that time (omitting id and node-name then
results in a BDS with an auto-assigned node name and no BB).  But that's
a decision for that series (if we ever revive it); for now, your policy
is just fine.

> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  blockdev.c                 | 44 +++++++++++++++++++++++++++++++-------------
>  qapi/block-core.json       | 13 +++++++++----
>  tests/qemu-iotests/087     |  2 +-
>  tests/qemu-iotests/087.out |  4 ++--
>  4 files changed, 43 insertions(+), 20 deletions(-)

Reviewed-by: Eric Blake <eblake@redhat.com>


> +++ b/qapi/block-core.json
> @@ -1260,9 +1260,12 @@
>  #
>  # @driver:        block driver name
>  # @id:            #optional id by which the new block device can be referred to.
> -#                 This is a required option on the top level of blockdev-add, and
> -#                 currently not allowed on any other level.
> -# @node-name:     #optional the name of a block driver state node (Since 2.0)
> +#                 This option is only allowed on the top level of blockdev-add.
> +#                 A BlockBackend will be created by blockdev-add if and only if
> +#                 this option is given.

I know what you mean here, but it feels a tiny bit like we are leaking
implementation details.  Would it be any better to state that: "A
guest-visible device will be created by blockdev-add if and only if this
option is given"?  That is, instead of BlockDriverState and BlockBackend
(which are internal naming conventions), should our documentation be
favoring "node within a tree of host-accessible resources that provide
the media content to a guest device" and "guest-visible device"?  But
just in typing that out, it gets tedious, and even if we do make such a
change in documentation, it would be better to do it over all existing
.json files rather than just this patch.  Furthermore, we may use
BlockBackend for things like NBD fleecing operations, which really
aren't guest-visible devices.  So my idle ramblings here don't affect my
R-b for the patch as-is.


-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 03/37] hw/block/fdc: Implement tray status
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 03/37] hw/block/fdc: Implement tray status Max Reitz
@ 2015-02-09 18:23   ` Eric Blake
  2015-03-04 14:00   ` Kevin Wolf
  1 sibling, 0 replies; 80+ messages in thread
From: Eric Blake @ 2015-02-09 18:23 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 911 bytes --]

On 02/09/2015 10:11 AM, Max Reitz wrote:
> The tray of an FDD is open iff there is no medium inserted (there are
> only two states for an FDD: "medium inserted" or "no medium inserted").
> 
> This results in the tray being reported as open if qemu has been started
> with the default floppy drive, which breaks some tests. Fix them.
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  hw/block/fdc.c             | 20 +++++++++++++---
>  tests/fdc-test.c           |  4 +---
>  tests/qemu-iotests/067.out | 60 +++++++---------------------------------------
>  tests/qemu-iotests/071.out |  2 --
>  tests/qemu-iotests/081.out |  1 -
>  tests/qemu-iotests/087.out |  6 -----
>  6 files changed, 26 insertions(+), 67 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 01/37] blockdev: Allow creation of BDS trees without BB
  2015-02-09 18:17   ` Eric Blake
@ 2015-02-09 18:29     ` Max Reitz
  0 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-09 18:29 UTC (permalink / raw)
  To: Eric Blake, qemu-devel
  Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

On 2015-02-09 at 13:17, Eric Blake wrote:
> On 02/09/2015 10:11 AM, Max Reitz wrote:
>> If the "id" field is missing from the options given to blockdev-add,
>> just omit the BlockBackend and create the BlockDriverState tree alone.
>>
>> However, if "id" is missing, "node-name" must be specified; otherwise,
>> the BDS tree would no longer be accessible.
>>
> Well, if we ever revived Jeff Cody's attempt at auto-assigning node
> names (so that we never have an unnamed node), then this patch will have
> to be partially reverted at that time (omitting id and node-name then
> results in a BDS with an auto-assigned node name and no BB).  But that's
> a decision for that series (if we ever revive it); for now, your policy
> is just fine.
>
>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>> ---
>>   blockdev.c                 | 44 +++++++++++++++++++++++++++++++-------------
>>   qapi/block-core.json       | 13 +++++++++----
>>   tests/qemu-iotests/087     |  2 +-
>>   tests/qemu-iotests/087.out |  4 ++--
>>   4 files changed, 43 insertions(+), 20 deletions(-)
> Reviewed-by: Eric Blake <eblake@redhat.com>
>
>
>> +++ b/qapi/block-core.json
>> @@ -1260,9 +1260,12 @@
>>   #
>>   # @driver:        block driver name
>>   # @id:            #optional id by which the new block device can be referred to.
>> -#                 This is a required option on the top level of blockdev-add, and
>> -#                 currently not allowed on any other level.
>> -# @node-name:     #optional the name of a block driver state node (Since 2.0)
>> +#                 This option is only allowed on the top level of blockdev-add.
>> +#                 A BlockBackend will be created by blockdev-add if and only if
>> +#                 this option is given.
> I know what you mean here, but it feels a tiny bit like we are leaking
> implementation details.  Would it be any better to state that: "A
> guest-visible device will be created by blockdev-add if and only if this
> option is given"?

Well, it's not a guest-visible device; a BlockBackend is the connector 
between a BDS tree and a guest-visible device.

However, I thought about the same thing, but there are already 
occurrences of "block driver state", so I decided to just go with it (I 
mean, we could use "block backend", but I don't know if that's really 
better).

Max

> That is, instead of BlockDriverState and BlockBackend
> (which are internal naming conventions), should our documentation be
> favoring "node within a tree of host-accessible resources that provide
> the media content to a guest device" and "guest-visible device"?  But
> just in typing that out, it gets tedious, and even if we do make such a
> change in documentation, it would be better to do it over all existing
> .json files rather than just this patch.  Furthermore, we may use
> BlockBackend for things like NBD fleecing operations, which really
> aren't guest-visible devices.  So my idle ramblings here don't affect my
> R-b for the patch as-is.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 06/37] block: Make bdrv_is_inserted() return a bool
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 06/37] block: Make bdrv_is_inserted() return a bool Max Reitz
@ 2015-02-09 18:29   ` Eric Blake
  0 siblings, 0 replies; 80+ messages in thread
From: Eric Blake @ 2015-02-09 18:29 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 798 bytes --]

On 02/09/2015 10:11 AM, Max Reitz wrote:
> Make bdrv_is_inserted(), blk_is_inserted(), and the callback
> BlockDriver.bdrv_is_inserted() return a bool.
> 
> Suggested-by: Eric Blake <eblake@redhat.com>
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  block.c                        | 12 +++++++-----
>  block/block-backend.c          |  2 +-
>  block/raw-posix.c              | 10 ++++------
>  block/raw_bsd.c                |  2 +-
>  include/block/block.h          |  2 +-
>  include/block/block_int.h      |  2 +-
>  include/sysemu/block-backend.h |  2 +-
>  7 files changed, 16 insertions(+), 16 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 08/37] block: Make bdrv_is_inserted() recursive
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 08/37] block: Make bdrv_is_inserted() recursive Max Reitz
@ 2015-02-09 19:16   ` Eric Blake
  0 siblings, 0 replies; 80+ messages in thread
From: Eric Blake @ 2015-02-09 19:16 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 1057 bytes --]

On 02/09/2015 10:11 AM, Max Reitz wrote:
> If bdrv_is_inserted() is called on the top level BDS, it should make
> sure all nodes in the BDS tree are actually inserted.
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  block.c | 7 +++----
>  1 file changed, 3 insertions(+), 4 deletions(-)

Reviewed-by: Eric Blake <eblake@redhat.com>

> 
> diff --git a/block.c b/block.c
> index ee7dfba..dafa4b7 100644
> --- a/block.c
> +++ b/block.c
> @@ -5237,10 +5237,9 @@ bool bdrv_is_inserted(BlockDriverState *bs)
>      if (!drv) {
>          return false;
>      }
> -    if (!drv->bdrv_is_inserted) {
> -        return true;
> -    }
> -    return drv->bdrv_is_inserted(bs);
> +    return (!drv->bdrv_is_inserted || drv->bdrv_is_inserted(bs)) &&
> +           (!bs->file              || bdrv_is_inserted(bs->file)) &&
> +           (!bs->backing_hd        || bdrv_is_inserted(bs->backing_hd));
>  }
>  
>  /**
> 

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 11/37] block: Remove wr_highest_sector from BlockAcctStats
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 11/37] block: Remove wr_highest_sector from BlockAcctStats Max Reitz
@ 2015-02-09 19:20   ` Eric Blake
  0 siblings, 0 replies; 80+ messages in thread
From: Eric Blake @ 2015-02-09 19:20 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 1653 bytes --]

On 02/09/2015 10:11 AM, Max Reitz wrote:
> BlockAcctStats contains statistics about the data transferred from and
> to the device; wr_highest_sector does not fit in with the rest.
> 
> Furthermore, those statistics are supposed to be specific for a certain
> device and not necessarily for a BDS (see the comment above
> bdrv_get_stats()); on the other hand, wr_highest_sector may be a rather
> important information to know for each BDS. When BlockAcctStats is
> finally removed from the BDS, we will want to keep wr_highest_sector in
> the BDS.
> 
> Finally, wr_highest_sector is renamed to wr_highest_offset and given the
> appropriate meaning. Externally, it is represented as an offset so there
> is no point in doing something different internally. Its definition is
> changed to match that in qapi/block-core.json which is "the offset after
> the greatest byte written to". Doing so should not cause any harm since
> if external programs tried to calculate the volume usage by
> (wr_highest_offset + 512) / volume_size, after this patch they will just
> assume the volume to be full slightly earlier than before.
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  block.c                    | 4 +++-
>  block/accounting.c         | 8 --------
>  block/qapi.c               | 4 ++--
>  include/block/accounting.h | 3 ---
>  include/block/block_int.h  | 3 +++
>  qmp-commands.hx            | 4 ++--
>  6 files changed, 10 insertions(+), 16 deletions(-)

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 17/37] block: Prepare remaining BB functions for NULL BDS
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 17/37] block: Prepare remaining BB functions for NULL BDS Max Reitz
@ 2015-02-09 20:47   ` Eric Blake
  0 siblings, 0 replies; 80+ messages in thread
From: Eric Blake @ 2015-02-09 20:47 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 677 bytes --]

On 02/09/2015 10:11 AM, Max Reitz wrote:
> There are several BlockBackend functions which, in theory, cannot fail.
> This patch makes them cope with the BlockDriverState pointer being NULL
> by making them fall back to some default action like ignoring the value
> in setters and returning the default in getters.
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  block/block-backend.c | 76 ++++++++++++++++++++++++++++++++++++++++-----------
>  1 file changed, 60 insertions(+), 16 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 20/37] block: Prepare for NULL BDS
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 20/37] block: Prepare for NULL BDS Max Reitz
@ 2015-02-09 21:21   ` Eric Blake
  0 siblings, 0 replies; 80+ messages in thread
From: Eric Blake @ 2015-02-09 21:21 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 741 bytes --]

On 02/09/2015 10:11 AM, Max Reitz wrote:
> blk_bs() will not necessarily return a non-NULL value any more (unless
> blk_is_available() is true or it can be assumed to otherwise, e.g.
> because it is called immediately after a successful blk_new_with_bs() or
> blk_new_open()).
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  block.c             |   5 ++
>  block/qapi.c        |   4 +-
>  blockdev.c          | 222 ++++++++++++++++++++++++++++++++++++----------------
>  hw/block/xen_disk.c |   4 +-
>  4 files changed, 163 insertions(+), 72 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 21/37] blockdev: Do not create BDS for empty drive
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 21/37] blockdev: Do not create BDS for empty drive Max Reitz
@ 2015-02-09 21:32   ` Eric Blake
  0 siblings, 0 replies; 80+ messages in thread
From: Eric Blake @ 2015-02-09 21:32 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 958 bytes --]

On 02/09/2015 10:11 AM, Max Reitz wrote:
> Do not use "rudimentary" BDSs for empty drives any longer (for
> freshly created drives).
> 
> With this change, bdrv_close_all() has no effect on empty drives (whose
> media were not changed) any longer. This breaks some test outputs, fix
> them.
> 
> After a follow-up patch, empty drives will generally use a NULL BDS, not
> only the freshly created drives.
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  blockdev.c                 | 68 ++++++++++++++++++++++++++--------------------
>  tests/qemu-iotests/067.out | 44 ------------------------------
>  tests/qemu-iotests/071.out |  2 --
>  tests/qemu-iotests/081.out |  1 -
>  tests/qemu-iotests/087.out |  6 ----
>  5 files changed, 38 insertions(+), 83 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 25/37] blockdev: Add blockdev-open-tray
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 25/37] blockdev: Add blockdev-open-tray Max Reitz
@ 2015-02-09 22:01   ` Eric Blake
  0 siblings, 0 replies; 80+ messages in thread
From: Eric Blake @ 2015-02-09 22:01 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 501 bytes --]

On 02/09/2015 10:11 AM, Max Reitz wrote:
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  blockdev.c           | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>  qapi/block-core.json | 23 +++++++++++++++++++++++
>  qmp-commands.hx      | 39 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 110 insertions(+)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 26/37] blockdev: Add blockdev-close-tray
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 26/37] blockdev: Add blockdev-close-tray Max Reitz
@ 2015-02-09 22:18   ` Eric Blake
  0 siblings, 0 replies; 80+ messages in thread
From: Eric Blake @ 2015-02-09 22:18 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 463 bytes --]

On 02/09/2015 10:11 AM, Max Reitz wrote:
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  blockdev.c           | 22 ++++++++++++++++++++++
>  qapi/block-core.json | 16 ++++++++++++++++
>  qmp-commands.hx      | 35 +++++++++++++++++++++++++++++++++++
>  3 files changed, 73 insertions(+)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 27/37] blockdev: Add blockdev-remove-medium
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 27/37] blockdev: Add blockdev-remove-medium Max Reitz
@ 2015-02-09 22:21   ` Eric Blake
  0 siblings, 0 replies; 80+ messages in thread
From: Eric Blake @ 2015-02-09 22:21 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 475 bytes --]

On 02/09/2015 10:11 AM, Max Reitz wrote:
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  blockdev.c           | 25 +++++++++++++++++++++++++
>  qapi/block-core.json | 15 +++++++++++++++
>  qmp-commands.hx      | 45 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 85 insertions(+)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 28/37] blockdev: Add blockdev-insert-medium
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 28/37] blockdev: Add blockdev-insert-medium Max Reitz
@ 2015-02-09 22:23   ` Eric Blake
  0 siblings, 0 replies; 80+ messages in thread
From: Eric Blake @ 2015-02-09 22:23 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 792 bytes --]

On 02/09/2015 10:11 AM, Max Reitz wrote:
> And a helper function for that which directly takes a pointer to the BDS

reads better with s/that/that,/

> to be inserted instead of its node-name (which will be used for
> implementing 'change' using blockdev-insert-medium).
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  blockdev.c           | 43 +++++++++++++++++++++++++++++++++++++++++++
>  qapi/block-core.json | 17 +++++++++++++++++
>  qmp-commands.hx      | 37 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 97 insertions(+)

But a grammar nit in the commit message doesn't invalidate R-b :)

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 30/37] blockdev: Implement change with basic operations
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 30/37] blockdev: Implement change " Max Reitz
@ 2015-02-09 22:28   ` Eric Blake
  0 siblings, 0 replies; 80+ messages in thread
From: Eric Blake @ 2015-02-09 22:28 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 603 bytes --]

On 02/09/2015 10:11 AM, Max Reitz wrote:
> Implement 'change' on block devices by calling blockdev-open-tray,
> blockdev-remove-medium, blockdev-insert-medium (a variation of that
> which does not need a node-name) and blockdev-close-tray.
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  blockdev.c | 185 +++++++++++++++++++++++++------------------------------------
>  1 file changed, 77 insertions(+), 108 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 32/37] qmp: Introduce blockdev-change-medium
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 32/37] qmp: Introduce blockdev-change-medium Max Reitz
@ 2015-02-09 23:09   ` Eric Blake
  0 siblings, 0 replies; 80+ messages in thread
From: Eric Blake @ 2015-02-09 23:09 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 838 bytes --]

On 02/09/2015 10:11 AM, Max Reitz wrote:
> Introduce a new QMP command 'blockdev-change-medium' which is intended
> to replace the 'change' command for block devices. The existing function
> qmp_change_blockdev() is accordingly renamed to
> qmp_blockdev_change_medium().
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  blockdev.c                |  7 ++++---
>  include/sysemu/blockdev.h |  2 --
>  qapi-schema.json          |  6 ++++--
>  qapi/block-core.json      | 23 +++++++++++++++++++++++
>  qmp-commands.hx           | 31 +++++++++++++++++++++++++++++++
>  qmp.c                     |  2 +-
>  6 files changed, 63 insertions(+), 8 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 34/37] blockdev: read-only-mode for blockdev-change-medium
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 34/37] blockdev: read-only-mode for blockdev-change-medium Max Reitz
@ 2015-02-09 23:15   ` Eric Blake
  0 siblings, 0 replies; 80+ messages in thread
From: Eric Blake @ 2015-02-09 23:15 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 981 bytes --]

On 02/09/2015 10:11 AM, Max Reitz wrote:
> Add an option to qmp_blockdev_change_medium() which allows changing the
> read-only status of the block device whose medium is changed.
> 
> Some drives do not have a inherently fixed read-only status; for
> instance, floppy disks can be set read-only or writable independently of
> the drive. Some users may find it useful to be able to therefore change
> the read-only status of a block device when changing the medium.
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  blockdev.c           | 25 ++++++++++++++++++++++++-
>  hmp.c                |  2 +-
>  qapi/block-core.json | 24 +++++++++++++++++++++++-
>  qmp-commands.hx      | 24 +++++++++++++++++++++++-
>  qmp.c                |  3 ++-
>  5 files changed, 73 insertions(+), 5 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 35/37] hmp: Add read-only-mode option to change command
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 35/37] hmp: Add read-only-mode option to change command Max Reitz
@ 2015-02-09 23:17   ` Eric Blake
  0 siblings, 0 replies; 80+ messages in thread
From: Eric Blake @ 2015-02-09 23:17 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 508 bytes --]

On 02/09/2015 10:11 AM, Max Reitz wrote:
> Expose the new read-only-mode option of 'blockdev-change-medium' for the
> 'change' HMP command.
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  hmp-commands.hx | 20 +++++++++++++++++---
>  hmp.c           | 22 +++++++++++++++++++++-
>  2 files changed, 38 insertions(+), 4 deletions(-)

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 37/37] iotests: Add test for change-related QMP commands
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 37/37] iotests: Add test for change-related QMP commands Max Reitz
@ 2015-02-10  0:06   ` Eric Blake
  2015-02-10 20:37     ` Max Reitz
  0 siblings, 1 reply; 80+ messages in thread
From: Eric Blake @ 2015-02-10  0:06 UTC (permalink / raw)
  To: Max Reitz, qemu-devel
  Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 2198 bytes --]

On 02/09/2015 10:11 AM, Max Reitz wrote:
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  tests/qemu-iotests/118     | 653 +++++++++++++++++++++++++++++++++++++++++++++
>  tests/qemu-iotests/118.out |   5 +
>  tests/qemu-iotests/group   |   1 +
>  3 files changed, 659 insertions(+)
>  create mode 100755 tests/qemu-iotests/118
>  create mode 100644 tests/qemu-iotests/118.out
> 

> +
> +    def process_events(self):
> +        for event in self.vm.get_qmp_events(wait=True):
> +            if event['event'] == 'DEVICE_TRAY_MOVED' and event['data']['device'] == 'drive0':

Long line; I think you can wrap it as:

if (event['event'] == 'DEVICE_TRAY_MOVED' and
    event['data']['device'] == 'drive0'):

> +class GeneralChangeTestsBaseClass(ChangeBaseClass):
> +    def test_change(self):
> +        result = self.vm.qmp('change', device='drive0', target=new_img,
> +                                       arg=iotests.imgfmt)

Unusual indentation. [1]

> +        self.assert_qmp(result, 'return', {})
> +
> +        while not self.has_opened:
> +            self.process_events()
> +        while not self.has_closed:
> +            self.process_events()
> +

Are we guaranteed that loops like this will gracefully timeout and fail
the test if the event doesn't happen, instead of hanging forever?  But
that's probably something affecting multiple tests, so I won't hold up
review of this one.

> +        result = self.vm.qmp('query-block')
> +        self.assert_qmp(result, 'return[0]/tray_open', False)
> +        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
> +
> +    def test_blockdev_change_medium(self):
> +        result = self.vm.qmp('blockdev-change-medium', device='drive0',
> +                                                       filename=new_img,
> +                                                       format=iotests.imgfmt)

[1] I guess your choice of not flushing arguments to the ( is intentional.

The long line thing is minor, so:
Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 37/37] iotests: Add test for change-related QMP commands
  2015-02-10  0:06   ` Eric Blake
@ 2015-02-10 20:37     ` Max Reitz
  0 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-10 20:37 UTC (permalink / raw)
  To: Eric Blake, qemu-devel
  Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

On 2015-02-09 at 19:06, Eric Blake wrote:
> On 02/09/2015 10:11 AM, Max Reitz wrote:
>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>> ---
>>   tests/qemu-iotests/118     | 653 +++++++++++++++++++++++++++++++++++++++++++++
>>   tests/qemu-iotests/118.out |   5 +
>>   tests/qemu-iotests/group   |   1 +
>>   3 files changed, 659 insertions(+)
>>   create mode 100755 tests/qemu-iotests/118
>>   create mode 100644 tests/qemu-iotests/118.out
>>
>> +
>> +    def process_events(self):
>> +        for event in self.vm.get_qmp_events(wait=True):
>> +            if event['event'] == 'DEVICE_TRAY_MOVED' and event['data']['device'] == 'drive0':
> Long line; I think you can wrap it as:
>
> if (event['event'] == 'DEVICE_TRAY_MOVED' and
>      event['data']['device'] == 'drive0'):

If that works, I'll be glad to (if I have to respin, which I don't deem 
too unlikely).

>> +class GeneralChangeTestsBaseClass(ChangeBaseClass):
>> +    def test_change(self):
>> +        result = self.vm.qmp('change', device='drive0', target=new_img,
>> +                                       arg=iotests.imgfmt)
> Unusual indentation. [1]
>
>> +        self.assert_qmp(result, 'return', {})
>> +
>> +        while not self.has_opened:
>> +            self.process_events()
>> +        while not self.has_closed:
>> +            self.process_events()
>> +
> Are we guaranteed that loops like this will gracefully timeout and fail
> the test if the event doesn't happen, instead of hanging forever?

Well, let's say it should be guaranteed, but this is a test so it may 
break. I will try adding a timeout if I respin, though.

> But
> that's probably something affecting multiple tests, so I won't hold up
> review of this one.
>
>> +        result = self.vm.qmp('query-block')
>> +        self.assert_qmp(result, 'return[0]/tray_open', False)
>> +        self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
>> +
>> +    def test_blockdev_change_medium(self):
>> +        result = self.vm.qmp('blockdev-change-medium', device='drive0',
>> +                                                       filename=new_img,
>> +                                                       format=iotests.imgfmt)
> [1] I guess your choice of not flushing arguments to the ( is intentional.
>
> The long line thing is minor, so:
> Reviewed-by: Eric Blake <eblake@redhat.com>

Once again, thank you!

Max

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 16/37] block: Fail requests to empty BlockBackend
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 16/37] block: Fail requests to empty BlockBackend Max Reitz
@ 2015-02-25 18:18   ` Max Reitz
  0 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-02-25 18:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, John Snow, Markus Armbruster, Stefan Hajnoczi

On 2015-02-09 at 12:11, Max Reitz wrote:
> If there is no BlockDriverState in a BlockBackend or if the tray of the
> guest device is open, fail all requests (where that is possible) with
> -ENOMEDIUM.
>
> The reason the status of the guest device is taken into account is
> because once the guest device's tray is opened, any request on the same
> BlockBackend as the guest uses should fail. If the BDS tree is supposed
> to be usable even after ejecting it from the guest, a different
> BlockBackend must be used.
>
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>   block/block-backend.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
>   1 file changed, 46 insertions(+), 1 deletion(-)

Note that this patch needs to be amended to accommodate for 
https://github.com/stefanha/qemu/commit/17b10170718f8b7cdaed225da4b9c473996cf250.

Max

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 01/37] blockdev: Allow creation of BDS trees without BB
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 01/37] blockdev: Allow creation of BDS trees without BB Max Reitz
  2015-02-09 18:17   ` Eric Blake
@ 2015-03-04 13:39   ` Kevin Wolf
  2015-03-04 14:04     ` Max Reitz
  2015-03-04 21:44     ` Max Reitz
  1 sibling, 2 replies; 80+ messages in thread
From: Kevin Wolf @ 2015-03-04 13:39 UTC (permalink / raw)
  To: Max Reitz; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
> If the "id" field is missing from the options given to blockdev-add,
> just omit the BlockBackend and create the BlockDriverState tree alone.
> 
> However, if "id" is missing, "node-name" must be specified; otherwise,
> the BDS tree would no longer be accessible.
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  blockdev.c                 | 44 +++++++++++++++++++++++++++++++-------------
>  qapi/block-core.json       | 13 +++++++++----
>  tests/qemu-iotests/087     |  2 +-
>  tests/qemu-iotests/087.out |  4 ++--
>  4 files changed, 43 insertions(+), 20 deletions(-)
> 
> diff --git a/blockdev.c b/blockdev.c
> index 6eedcf5..6d67c80 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -2822,17 +2822,12 @@ out:
>  void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
>  {
>      QmpOutputVisitor *ov = qmp_output_visitor_new();
> -    BlockBackend *blk;
> +    BlockDriverState *bs;
> +    BlockBackend *blk = NULL;
>      QObject *obj;
>      QDict *qdict;
>      Error *local_err = NULL;
>  
> -    /* Require an ID in the top level */
> -    if (!options->has_id) {
> -        error_setg(errp, "Block device needs an ID");
> -        goto fail;
> -    }
> -
>      /* TODO Sort it out in raw-posix and drive_new(): Reject aio=native with
>       * cache.direct=false instead of silently switching to aio=threads, except
>       * when called from drive_new().
> @@ -2860,14 +2855,37 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
>  
>      qdict_flatten(qdict);
>  
> -    blk = blockdev_init(NULL, qdict, &local_err);
> -    if (local_err) {
> -        error_propagate(errp, local_err);
> -        goto fail;
> +    if (options->has_id) {
> +        blk = blockdev_init(NULL, qdict, &local_err);
> +        if (local_err) {
> +            error_propagate(errp, local_err);
> +            goto fail;
> +        }
> +
> +        bs = blk_bs(blk);
> +    } else {
> +        int ret;
> +
> +        if (!qdict_get_try_str(qdict, "node-name")) {
> +            error_setg(errp, "'id' and/or 'node-name' need to be specified for "
> +                       "the root node");
> +            goto fail;
> +        }
> +
> +        bs = NULL;
> +        ret = bdrv_open(&bs, NULL, NULL, qdict, BDRV_O_RDWR | BDRV_O_CACHE_WB,
> +                        NULL, errp);

Now all the qdict entries that aren't parsed by bdrv_open() but
converted into flags by blockdev_init() are broken if you don't give an
id. This includes read-only, discard, the cache options - in other
words, enough to make this "support" completely useless.

I guess I need to dig out my cache mode series and get it ready to be
merged. Once this is in, the parsing of the other necessary options
should be easy to move into bdrv_open().

Unless you have a good reason why we should merge this patch in its
hardly functional state now, I would consider those conversions a
dependency of this one.

Kevin

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 03/37] hw/block/fdc: Implement tray status
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 03/37] hw/block/fdc: Implement tray status Max Reitz
  2015-02-09 18:23   ` Eric Blake
@ 2015-03-04 14:00   ` Kevin Wolf
  2015-03-04 14:07     ` Max Reitz
  2015-03-04 22:06     ` Max Reitz
  1 sibling, 2 replies; 80+ messages in thread
From: Kevin Wolf @ 2015-03-04 14:00 UTC (permalink / raw)
  To: Max Reitz; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
> The tray of an FDD is open iff there is no medium inserted (there are
> only two states for an FDD: "medium inserted" or "no medium inserted").
> 
> This results in the tray being reported as open if qemu has been started
> with the default floppy drive, which breaks some tests. Fix them.
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  hw/block/fdc.c             | 20 +++++++++++++---
>  tests/fdc-test.c           |  4 +---
>  tests/qemu-iotests/067.out | 60 +++++++---------------------------------------
>  tests/qemu-iotests/071.out |  2 --
>  tests/qemu-iotests/081.out |  1 -
>  tests/qemu-iotests/087.out |  6 -----
>  6 files changed, 26 insertions(+), 67 deletions(-)
> 
> diff --git a/hw/block/fdc.c b/hw/block/fdc.c
> index 2bf87c9..0c5a6b4 100644
> --- a/hw/block/fdc.c
> +++ b/hw/block/fdc.c
> @@ -192,6 +192,8 @@ typedef struct FDrive {
>      uint8_t ro;               /* Is read-only           */
>      uint8_t media_changed;    /* Is media changed       */
>      uint8_t media_rate;       /* Data rate of medium    */
> +
> +    bool media_inserted;      /* Is there a medium in the tray */
>  } FDrive;
>  
>  static void fd_init(FDrive *drv)
> @@ -261,7 +263,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
>  #endif
>          drv->head = head;
>          if (drv->track != track) {
> -            if (drv->blk != NULL && blk_is_inserted(drv->blk)) {
> +            if (drv->media_inserted) {

I suspect that with the removal of blk_is_inserted() in several places,
floppy passthrough (host_floppy block driver) is now even more broken
than before, potentially not noticing removal of a medium any more.

While checking this, I noticed that since commit 21fcf360,
bdrv_media_changed() is completely unused. Media change has therefore
probably been broken since at least May 2012.

Considering this, it might actually be reasonable enough to remove the
block driver. It's definitely better than having it there, but not
working any better than host_device.

Of course, alternatively you would also be welcome to fix the device
model and reintroduce bdrv_media_changed() and blk_is_inserted() calls
where necessary.

Kevin

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 04/37] hw/usb-storage: Check whether BB is inserted
  2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 04/37] hw/usb-storage: Check whether BB is inserted Max Reitz
@ 2015-03-04 14:02   ` Kevin Wolf
  2015-03-04 14:07     ` Max Reitz
  2015-03-04 22:06     ` Max Reitz
  0 siblings, 2 replies; 80+ messages in thread
From: Kevin Wolf @ 2015-03-04 14:02 UTC (permalink / raw)
  To: Max Reitz; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
> Only call bdrv_key_required() on the BlockDriverState if the
> BlockBackend has an inserted medium.
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
>  hw/usb/dev-storage.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
> index 4539733..3123baf 100644
> --- a/hw/usb/dev-storage.c
> +++ b/hw/usb/dev-storage.c
> @@ -638,7 +638,7 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
>      usb_msd_handle_reset(dev);
>      s->scsi_dev = scsi_dev;
>  
> -    if (bdrv_key_required(blk_bs(blk))) {
> +    if (blk_is_inserted(blk) && bdrv_key_required(blk_bs(blk))) {
>          if (cur_mon) {
>              monitor_read_bdrv_key_start(cur_mon, blk_bs(blk),
>                                          usb_msd_password_cb, s);

Why would bdrv_key_required() ever return true when no medium is
inserted? Sounds like a bug to me, like not resetting state correctly on
bdrv_close() of an encrypted image.

Kevin

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 01/37] blockdev: Allow creation of BDS trees without BB
  2015-03-04 13:39   ` Kevin Wolf
@ 2015-03-04 14:04     ` Max Reitz
  2015-03-04 14:15       ` Kevin Wolf
  2015-03-04 21:44     ` Max Reitz
  1 sibling, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-03-04 14:04 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

On 2015-03-04 at 08:39, Kevin Wolf wrote:
> Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
>> If the "id" field is missing from the options given to blockdev-add,
>> just omit the BlockBackend and create the BlockDriverState tree alone.
>>
>> However, if "id" is missing, "node-name" must be specified; otherwise,
>> the BDS tree would no longer be accessible.
>>
>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>> ---
>>   blockdev.c                 | 44 +++++++++++++++++++++++++++++++-------------
>>   qapi/block-core.json       | 13 +++++++++----
>>   tests/qemu-iotests/087     |  2 +-
>>   tests/qemu-iotests/087.out |  4 ++--
>>   4 files changed, 43 insertions(+), 20 deletions(-)
>>
>> diff --git a/blockdev.c b/blockdev.c
>> index 6eedcf5..6d67c80 100644
>> --- a/blockdev.c
>> +++ b/blockdev.c
>> @@ -2822,17 +2822,12 @@ out:
>>   void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
>>   {
>>       QmpOutputVisitor *ov = qmp_output_visitor_new();
>> -    BlockBackend *blk;
>> +    BlockDriverState *bs;
>> +    BlockBackend *blk = NULL;
>>       QObject *obj;
>>       QDict *qdict;
>>       Error *local_err = NULL;
>>   
>> -    /* Require an ID in the top level */
>> -    if (!options->has_id) {
>> -        error_setg(errp, "Block device needs an ID");
>> -        goto fail;
>> -    }
>> -
>>       /* TODO Sort it out in raw-posix and drive_new(): Reject aio=native with
>>        * cache.direct=false instead of silently switching to aio=threads, except
>>        * when called from drive_new().
>> @@ -2860,14 +2855,37 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
>>   
>>       qdict_flatten(qdict);
>>   
>> -    blk = blockdev_init(NULL, qdict, &local_err);
>> -    if (local_err) {
>> -        error_propagate(errp, local_err);
>> -        goto fail;
>> +    if (options->has_id) {
>> +        blk = blockdev_init(NULL, qdict, &local_err);
>> +        if (local_err) {
>> +            error_propagate(errp, local_err);
>> +            goto fail;
>> +        }
>> +
>> +        bs = blk_bs(blk);
>> +    } else {
>> +        int ret;
>> +
>> +        if (!qdict_get_try_str(qdict, "node-name")) {
>> +            error_setg(errp, "'id' and/or 'node-name' need to be specified for "
>> +                       "the root node");
>> +            goto fail;
>> +        }
>> +
>> +        bs = NULL;
>> +        ret = bdrv_open(&bs, NULL, NULL, qdict, BDRV_O_RDWR | BDRV_O_CACHE_WB,
>> +                        NULL, errp);
> Now all the qdict entries that aren't parsed by bdrv_open() but
> converted into flags by blockdev_init() are broken if you don't give an
> id. This includes read-only, discard, the cache options - in other
> words, enough to make this "support" completely useless.

See patch 23.

Max

>
> I guess I need to dig out my cache mode series and get it ready to be
> merged. Once this is in, the parsing of the other necessary options
> should be easy to move into bdrv_open().
>
> Unless you have a good reason why we should merge this patch in its
> hardly functional state now, I would consider those conversions a
> dependency of this one.
>
> Kevin

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 03/37] hw/block/fdc: Implement tray status
  2015-03-04 14:00   ` Kevin Wolf
@ 2015-03-04 14:07     ` Max Reitz
  2015-03-04 22:06     ` Max Reitz
  1 sibling, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-03-04 14:07 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

On 2015-03-04 at 09:00, Kevin Wolf wrote:
> Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
>> The tray of an FDD is open iff there is no medium inserted (there are
>> only two states for an FDD: "medium inserted" or "no medium inserted").
>>
>> This results in the tray being reported as open if qemu has been started
>> with the default floppy drive, which breaks some tests. Fix them.
>>
>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>> ---
>>   hw/block/fdc.c             | 20 +++++++++++++---
>>   tests/fdc-test.c           |  4 +---
>>   tests/qemu-iotests/067.out | 60 +++++++---------------------------------------
>>   tests/qemu-iotests/071.out |  2 --
>>   tests/qemu-iotests/081.out |  1 -
>>   tests/qemu-iotests/087.out |  6 -----
>>   6 files changed, 26 insertions(+), 67 deletions(-)
>>
>> diff --git a/hw/block/fdc.c b/hw/block/fdc.c
>> index 2bf87c9..0c5a6b4 100644
>> --- a/hw/block/fdc.c
>> +++ b/hw/block/fdc.c
>> @@ -192,6 +192,8 @@ typedef struct FDrive {
>>       uint8_t ro;               /* Is read-only           */
>>       uint8_t media_changed;    /* Is media changed       */
>>       uint8_t media_rate;       /* Data rate of medium    */
>> +
>> +    bool media_inserted;      /* Is there a medium in the tray */
>>   } FDrive;
>>   
>>   static void fd_init(FDrive *drv)
>> @@ -261,7 +263,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
>>   #endif
>>           drv->head = head;
>>           if (drv->track != track) {
>> -            if (drv->blk != NULL && blk_is_inserted(drv->blk)) {
>> +            if (drv->media_inserted) {
> I suspect that with the removal of blk_is_inserted() in several places,
> floppy passthrough (host_floppy block driver) is now even more broken
> than before, potentially not noticing removal of a medium any more.
>
> While checking this, I noticed that since commit 21fcf360,
> bdrv_media_changed() is completely unused. Media change has therefore
> probably been broken since at least May 2012.
>
> Considering this, it might actually be reasonable enough to remove the
> block driver. It's definitely better than having it there, but not
> working any better than host_device.
>
> Of course, alternatively you would also be welcome to fix the device
> model and reintroduce bdrv_media_changed() and blk_is_inserted() calls
> where necessary.

Urrggghhh... I guess it's my own fault for touching floppy code.

I guess I'll rethink this patch while keeping in mind that 
bdrv_is_inserted() (as opposed to blk_is_inserted()) actually is 
necessary here because we won't notice if the host medium has been 
exchanged otherwise.

Max

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 04/37] hw/usb-storage: Check whether BB is inserted
  2015-03-04 14:02   ` Kevin Wolf
@ 2015-03-04 14:07     ` Max Reitz
  2015-03-04 14:20       ` Kevin Wolf
  2015-03-04 22:06     ` Max Reitz
  1 sibling, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-03-04 14:07 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

On 2015-03-04 at 09:02, Kevin Wolf wrote:
> Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
>> Only call bdrv_key_required() on the BlockDriverState if the
>> BlockBackend has an inserted medium.
>>
>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>> Reviewed-by: Eric Blake <eblake@redhat.com>
>> ---
>>   hw/usb/dev-storage.c | 2 +-
>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
>> index 4539733..3123baf 100644
>> --- a/hw/usb/dev-storage.c
>> +++ b/hw/usb/dev-storage.c
>> @@ -638,7 +638,7 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
>>       usb_msd_handle_reset(dev);
>>       s->scsi_dev = scsi_dev;
>>   
>> -    if (bdrv_key_required(blk_bs(blk))) {
>> +    if (blk_is_inserted(blk) && bdrv_key_required(blk_bs(blk))) {
>>           if (cur_mon) {
>>               monitor_read_bdrv_key_start(cur_mon, blk_bs(blk),
>>                                           usb_msd_password_cb, s);
> Why would bdrv_key_required() ever return true when no medium is
> inserted? Sounds like a bug to me, like not resetting state correctly on
> bdrv_close() of an encrypted image.

The point is that blk_bs(blk) might be NULL.

Max

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 01/37] blockdev: Allow creation of BDS trees without BB
  2015-03-04 14:04     ` Max Reitz
@ 2015-03-04 14:15       ` Kevin Wolf
  2015-03-04 14:23         ` Max Reitz
  0 siblings, 1 reply; 80+ messages in thread
From: Kevin Wolf @ 2015-03-04 14:15 UTC (permalink / raw)
  To: Max Reitz; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

Am 04.03.2015 um 15:04 hat Max Reitz geschrieben:
> On 2015-03-04 at 08:39, Kevin Wolf wrote:
> >Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
> >>If the "id" field is missing from the options given to blockdev-add,
> >>just omit the BlockBackend and create the BlockDriverState tree alone.
> >>
> >>However, if "id" is missing, "node-name" must be specified; otherwise,
> >>the BDS tree would no longer be accessible.
> >>
> >>Signed-off-by: Max Reitz <mreitz@redhat.com>
> >>---
> >>  blockdev.c                 | 44 +++++++++++++++++++++++++++++++-------------
> >>  qapi/block-core.json       | 13 +++++++++----
> >>  tests/qemu-iotests/087     |  2 +-
> >>  tests/qemu-iotests/087.out |  4 ++--
> >>  4 files changed, 43 insertions(+), 20 deletions(-)
> >>
> >>diff --git a/blockdev.c b/blockdev.c
> >>index 6eedcf5..6d67c80 100644
> >>--- a/blockdev.c
> >>+++ b/blockdev.c
> >>@@ -2822,17 +2822,12 @@ out:
> >>  void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
> >>  {
> >>      QmpOutputVisitor *ov = qmp_output_visitor_new();
> >>-    BlockBackend *blk;
> >>+    BlockDriverState *bs;
> >>+    BlockBackend *blk = NULL;
> >>      QObject *obj;
> >>      QDict *qdict;
> >>      Error *local_err = NULL;
> >>-    /* Require an ID in the top level */
> >>-    if (!options->has_id) {
> >>-        error_setg(errp, "Block device needs an ID");
> >>-        goto fail;
> >>-    }
> >>-
> >>      /* TODO Sort it out in raw-posix and drive_new(): Reject aio=native with
> >>       * cache.direct=false instead of silently switching to aio=threads, except
> >>       * when called from drive_new().
> >>@@ -2860,14 +2855,37 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
> >>      qdict_flatten(qdict);
> >>-    blk = blockdev_init(NULL, qdict, &local_err);
> >>-    if (local_err) {
> >>-        error_propagate(errp, local_err);
> >>-        goto fail;
> >>+    if (options->has_id) {
> >>+        blk = blockdev_init(NULL, qdict, &local_err);
> >>+        if (local_err) {
> >>+            error_propagate(errp, local_err);
> >>+            goto fail;
> >>+        }
> >>+
> >>+        bs = blk_bs(blk);
> >>+    } else {
> >>+        int ret;
> >>+
> >>+        if (!qdict_get_try_str(qdict, "node-name")) {
> >>+            error_setg(errp, "'id' and/or 'node-name' need to be specified for "
> >>+                       "the root node");
> >>+            goto fail;
> >>+        }
> >>+
> >>+        bs = NULL;
> >>+        ret = bdrv_open(&bs, NULL, NULL, qdict, BDRV_O_RDWR | BDRV_O_CACHE_WB,
> >>+                        NULL, errp);
> >Now all the qdict entries that aren't parsed by bdrv_open() but
> >converted into flags by blockdev_init() are broken if you don't give an
> >id. This includes read-only, discard, the cache options - in other
> >words, enough to make this "support" completely useless.
> 
> See patch 23.

No matter what I'll find there (okay, I've cheated and already quickly
looked at it before writing this), this answer tells me that you're
doing things in the wrong order.

Kevin

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 04/37] hw/usb-storage: Check whether BB is inserted
  2015-03-04 14:07     ` Max Reitz
@ 2015-03-04 14:20       ` Kevin Wolf
  2015-03-04 14:24         ` Max Reitz
  0 siblings, 1 reply; 80+ messages in thread
From: Kevin Wolf @ 2015-03-04 14:20 UTC (permalink / raw)
  To: Max Reitz; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

Am 04.03.2015 um 15:07 hat Max Reitz geschrieben:
> On 2015-03-04 at 09:02, Kevin Wolf wrote:
> >Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
> >>Only call bdrv_key_required() on the BlockDriverState if the
> >>BlockBackend has an inserted medium.
> >>
> >>Signed-off-by: Max Reitz <mreitz@redhat.com>
> >>Reviewed-by: Eric Blake <eblake@redhat.com>
> >>---
> >>  hw/usb/dev-storage.c | 2 +-
> >>  1 file changed, 1 insertion(+), 1 deletion(-)
> >>
> >>diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
> >>index 4539733..3123baf 100644
> >>--- a/hw/usb/dev-storage.c
> >>+++ b/hw/usb/dev-storage.c
> >>@@ -638,7 +638,7 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
> >>      usb_msd_handle_reset(dev);
> >>      s->scsi_dev = scsi_dev;
> >>-    if (bdrv_key_required(blk_bs(blk))) {
> >>+    if (blk_is_inserted(blk) && bdrv_key_required(blk_bs(blk))) {
> >>          if (cur_mon) {
> >>              monitor_read_bdrv_key_start(cur_mon, blk_bs(blk),
> >>                                          usb_msd_password_cb, s);
> >Why would bdrv_key_required() ever return true when no medium is
> >inserted? Sounds like a bug to me, like not resetting state correctly on
> >bdrv_close() of an encrypted image.
> 
> The point is that blk_bs(blk) might be NULL.

This is not what blk_is_inserted() is checking. It happens to protect
you against segfaults because it's robust against using NULL, but with
an existing BDS, checking whether there is a medium inserted (in the
physical device for passthrough drivers) doesn't make sense.

It looks like what you want is blk_bs(blk) != NULL.

Kevin

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 01/37] blockdev: Allow creation of BDS trees without BB
  2015-03-04 14:15       ` Kevin Wolf
@ 2015-03-04 14:23         ` Max Reitz
  0 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-03-04 14:23 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

On 2015-03-04 at 09:15, Kevin Wolf wrote:
> Am 04.03.2015 um 15:04 hat Max Reitz geschrieben:
>> On 2015-03-04 at 08:39, Kevin Wolf wrote:
>>> Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
>>>> If the "id" field is missing from the options given to blockdev-add,
>>>> just omit the BlockBackend and create the BlockDriverState tree alone.
>>>>
>>>> However, if "id" is missing, "node-name" must be specified; otherwise,
>>>> the BDS tree would no longer be accessible.
>>>>
>>>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>>>> ---
>>>>   blockdev.c                 | 44 +++++++++++++++++++++++++++++++-------------
>>>>   qapi/block-core.json       | 13 +++++++++----
>>>>   tests/qemu-iotests/087     |  2 +-
>>>>   tests/qemu-iotests/087.out |  4 ++--
>>>>   4 files changed, 43 insertions(+), 20 deletions(-)
>>>>
>>>> diff --git a/blockdev.c b/blockdev.c
>>>> index 6eedcf5..6d67c80 100644
>>>> --- a/blockdev.c
>>>> +++ b/blockdev.c
>>>> @@ -2822,17 +2822,12 @@ out:
>>>>   void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
>>>>   {
>>>>       QmpOutputVisitor *ov = qmp_output_visitor_new();
>>>> -    BlockBackend *blk;
>>>> +    BlockDriverState *bs;
>>>> +    BlockBackend *blk = NULL;
>>>>       QObject *obj;
>>>>       QDict *qdict;
>>>>       Error *local_err = NULL;
>>>> -    /* Require an ID in the top level */
>>>> -    if (!options->has_id) {
>>>> -        error_setg(errp, "Block device needs an ID");
>>>> -        goto fail;
>>>> -    }
>>>> -
>>>>       /* TODO Sort it out in raw-posix and drive_new(): Reject aio=native with
>>>>        * cache.direct=false instead of silently switching to aio=threads, except
>>>>        * when called from drive_new().
>>>> @@ -2860,14 +2855,37 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
>>>>       qdict_flatten(qdict);
>>>> -    blk = blockdev_init(NULL, qdict, &local_err);
>>>> -    if (local_err) {
>>>> -        error_propagate(errp, local_err);
>>>> -        goto fail;
>>>> +    if (options->has_id) {
>>>> +        blk = blockdev_init(NULL, qdict, &local_err);
>>>> +        if (local_err) {
>>>> +            error_propagate(errp, local_err);
>>>> +            goto fail;
>>>> +        }
>>>> +
>>>> +        bs = blk_bs(blk);
>>>> +    } else {
>>>> +        int ret;
>>>> +
>>>> +        if (!qdict_get_try_str(qdict, "node-name")) {
>>>> +            error_setg(errp, "'id' and/or 'node-name' need to be specified for "
>>>> +                       "the root node");
>>>> +            goto fail;
>>>> +        }
>>>> +
>>>> +        bs = NULL;
>>>> +        ret = bdrv_open(&bs, NULL, NULL, qdict, BDRV_O_RDWR | BDRV_O_CACHE_WB,
>>>> +                        NULL, errp);
>>> Now all the qdict entries that aren't parsed by bdrv_open() but
>>> converted into flags by blockdev_init() are broken if you don't give an
>>> id. This includes read-only, discard, the cache options - in other
>>> words, enough to make this "support" completely useless.
>> See patch 23.
> No matter what I'll find there (okay, I've cheated and already quickly
> looked at it before writing this), this answer tells me that you're
> doing things in the wrong order.

To cite the cover letter of v1 regarding the patch order, here for 
patches 1 and 2:

 > Patches 35 [22] and 36 [23] are kind of a follow-up to these; but
 > patch 35 [22] depends on patch 34 [21] which is the reason why there
 > is a large gap between patch 2 and 35 [22].

I remember needing patch 2 before the rest. Maybe I don't which means I 
can move it back. I'll see.

My reasoning is the following: Yes, blockdev-add for BB-less BDS trees 
is nearly unusable after this. But it's enough for patch 2; and it does 
not break anything, because trying that simply always threw an error 
before this patch. Afterwards, only most usages will result in an error, 
but the ones introduced in patch 2 are fine. And patch 23 then "unlocks" 
all useful usages (that I can see). So nothing breaks at any point, 
we're only slowly allowing more use cases (and everything contained 
within a single series).

Max

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 04/37] hw/usb-storage: Check whether BB is inserted
  2015-03-04 14:20       ` Kevin Wolf
@ 2015-03-04 14:24         ` Max Reitz
  2015-03-04 14:39           ` Kevin Wolf
  0 siblings, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-03-04 14:24 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

On 2015-03-04 at 09:20, Kevin Wolf wrote:
> Am 04.03.2015 um 15:07 hat Max Reitz geschrieben:
>> On 2015-03-04 at 09:02, Kevin Wolf wrote:
>>> Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
>>>> Only call bdrv_key_required() on the BlockDriverState if the
>>>> BlockBackend has an inserted medium.
>>>>
>>>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>>>> Reviewed-by: Eric Blake <eblake@redhat.com>
>>>> ---
>>>>   hw/usb/dev-storage.c | 2 +-
>>>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>>>
>>>> diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
>>>> index 4539733..3123baf 100644
>>>> --- a/hw/usb/dev-storage.c
>>>> +++ b/hw/usb/dev-storage.c
>>>> @@ -638,7 +638,7 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
>>>>       usb_msd_handle_reset(dev);
>>>>       s->scsi_dev = scsi_dev;
>>>> -    if (bdrv_key_required(blk_bs(blk))) {
>>>> +    if (blk_is_inserted(blk) && bdrv_key_required(blk_bs(blk))) {
>>>>           if (cur_mon) {
>>>>               monitor_read_bdrv_key_start(cur_mon, blk_bs(blk),
>>>>                                           usb_msd_password_cb, s);
>>> Why would bdrv_key_required() ever return true when no medium is
>>> inserted? Sounds like a bug to me, like not resetting state correctly on
>>> bdrv_close() of an encrypted image.
>> The point is that blk_bs(blk) might be NULL.
> This is not what blk_is_inserted() is checking. It happens to protect
> you against segfaults because it's robust against using NULL, but with
> an existing BDS, checking whether there is a medium inserted (in the
> physical device for passthrough drivers) doesn't make sense.

Not right now it's not. See patch 6.

Yes, I will include my patch order justification chapter from v1 in the 
cover letter of v3.

Max

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 04/37] hw/usb-storage: Check whether BB is inserted
  2015-03-04 14:24         ` Max Reitz
@ 2015-03-04 14:39           ` Kevin Wolf
  2015-03-04 14:41             ` Max Reitz
  0 siblings, 1 reply; 80+ messages in thread
From: Kevin Wolf @ 2015-03-04 14:39 UTC (permalink / raw)
  To: Max Reitz; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

Am 04.03.2015 um 15:24 hat Max Reitz geschrieben:
> On 2015-03-04 at 09:20, Kevin Wolf wrote:
> >Am 04.03.2015 um 15:07 hat Max Reitz geschrieben:
> >>On 2015-03-04 at 09:02, Kevin Wolf wrote:
> >>>Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
> >>>>Only call bdrv_key_required() on the BlockDriverState if the
> >>>>BlockBackend has an inserted medium.
> >>>>
> >>>>Signed-off-by: Max Reitz <mreitz@redhat.com>
> >>>>Reviewed-by: Eric Blake <eblake@redhat.com>
> >>>>---
> >>>>  hw/usb/dev-storage.c | 2 +-
> >>>>  1 file changed, 1 insertion(+), 1 deletion(-)
> >>>>
> >>>>diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
> >>>>index 4539733..3123baf 100644
> >>>>--- a/hw/usb/dev-storage.c
> >>>>+++ b/hw/usb/dev-storage.c
> >>>>@@ -638,7 +638,7 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
> >>>>      usb_msd_handle_reset(dev);
> >>>>      s->scsi_dev = scsi_dev;
> >>>>-    if (bdrv_key_required(blk_bs(blk))) {
> >>>>+    if (blk_is_inserted(blk) && bdrv_key_required(blk_bs(blk))) {
> >>>>          if (cur_mon) {
> >>>>              monitor_read_bdrv_key_start(cur_mon, blk_bs(blk),
> >>>>                                          usb_msd_password_cb, s);
> >>>Why would bdrv_key_required() ever return true when no medium is
> >>>inserted? Sounds like a bug to me, like not resetting state correctly on
> >>>bdrv_close() of an encrypted image.
> >>The point is that blk_bs(blk) might be NULL.
> >This is not what blk_is_inserted() is checking. It happens to protect
> >you against segfaults because it's robust against using NULL, but with
> >an existing BDS, checking whether there is a medium inserted (in the
> >physical device for passthrough drivers) doesn't make sense.
> 
> Not right now it's not. See patch 6.

Patch 6 looks unrelated, at least in v2. But if you're trying to say
that I looked at the wrong version, you're right: It doesn't protect you
against segfaults at this point yet (which is okay, because blk->bs
can't be NULL yet), it only performs the misguided inserted check.

Doesn't answer my initial question or make that check any better.

Kevin

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 04/37] hw/usb-storage: Check whether BB is inserted
  2015-03-04 14:39           ` Kevin Wolf
@ 2015-03-04 14:41             ` Max Reitz
  2015-03-04 14:52               ` Max Reitz
  2015-03-04 14:53               ` Kevin Wolf
  0 siblings, 2 replies; 80+ messages in thread
From: Max Reitz @ 2015-03-04 14:41 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

On 2015-03-04 at 09:39, Kevin Wolf wrote:
> Am 04.03.2015 um 15:24 hat Max Reitz geschrieben:
>> On 2015-03-04 at 09:20, Kevin Wolf wrote:
>>> Am 04.03.2015 um 15:07 hat Max Reitz geschrieben:
>>>> On 2015-03-04 at 09:02, Kevin Wolf wrote:
>>>>> Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
>>>>>> Only call bdrv_key_required() on the BlockDriverState if the
>>>>>> BlockBackend has an inserted medium.
>>>>>>
>>>>>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>>>>>> Reviewed-by: Eric Blake <eblake@redhat.com>
>>>>>> ---
>>>>>>   hw/usb/dev-storage.c | 2 +-
>>>>>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
>>>>>> index 4539733..3123baf 100644
>>>>>> --- a/hw/usb/dev-storage.c
>>>>>> +++ b/hw/usb/dev-storage.c
>>>>>> @@ -638,7 +638,7 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
>>>>>>       usb_msd_handle_reset(dev);
>>>>>>       s->scsi_dev = scsi_dev;
>>>>>> -    if (bdrv_key_required(blk_bs(blk))) {
>>>>>> +    if (blk_is_inserted(blk) && bdrv_key_required(blk_bs(blk))) {
>>>>>>           if (cur_mon) {
>>>>>>               monitor_read_bdrv_key_start(cur_mon, blk_bs(blk),
>>>>>>                                           usb_msd_password_cb, s);
>>>>> Why would bdrv_key_required() ever return true when no medium is
>>>>> inserted? Sounds like a bug to me, like not resetting state correctly on
>>>>> bdrv_close() of an encrypted image.
>>>> The point is that blk_bs(blk) might be NULL.
>>> This is not what blk_is_inserted() is checking. It happens to protect
>>> you against segfaults because it's robust against using NULL, but with
>>> an existing BDS, checking whether there is a medium inserted (in the
>>> physical device for passthrough drivers) doesn't make sense.
>> Not right now it's not. See patch 6.
> Patch 6 looks unrelated, at least in v2. But if you're trying to say
> that I looked at the wrong version, you're right: It doesn't protect you
> against segfaults at this point yet (which is okay, because blk->bs
> can't be NULL yet), it only performs the misguided inserted check.

Oops, yes, I meant patch 7.

> Doesn't answer my initial question or make that check any better.

The answer to your initial question is: bdrv_key_required() assumes a 
non-NULL BDS pointer is passed (which is reasonable). Therefore, it 
crashes when "no medium is inserted" in the sense of !blk_bs(blk).

How it makes the check better: I'll move it after patch 7.

Max

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 04/37] hw/usb-storage: Check whether BB is inserted
  2015-03-04 14:41             ` Max Reitz
@ 2015-03-04 14:52               ` Max Reitz
  2015-03-04 14:53               ` Kevin Wolf
  1 sibling, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-03-04 14:52 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

On 2015-03-04 at 09:41, Max Reitz wrote:
> On 2015-03-04 at 09:39, Kevin Wolf wrote:
>> Am 04.03.2015 um 15:24 hat Max Reitz geschrieben:
>>> On 2015-03-04 at 09:20, Kevin Wolf wrote:
>>>> Am 04.03.2015 um 15:07 hat Max Reitz geschrieben:
>>>>> On 2015-03-04 at 09:02, Kevin Wolf wrote:
>>>>>> Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
>>>>>>> Only call bdrv_key_required() on the BlockDriverState if the
>>>>>>> BlockBackend has an inserted medium.
>>>>>>>
>>>>>>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>>>>>>> Reviewed-by: Eric Blake <eblake@redhat.com>
>>>>>>> ---
>>>>>>>   hw/usb/dev-storage.c | 2 +-
>>>>>>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>>>>>>
>>>>>>> diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
>>>>>>> index 4539733..3123baf 100644
>>>>>>> --- a/hw/usb/dev-storage.c
>>>>>>> +++ b/hw/usb/dev-storage.c
>>>>>>> @@ -638,7 +638,7 @@ static void 
>>>>>>> usb_msd_realize_storage(USBDevice *dev, Error **errp)
>>>>>>>       usb_msd_handle_reset(dev);
>>>>>>>       s->scsi_dev = scsi_dev;
>>>>>>> -    if (bdrv_key_required(blk_bs(blk))) {
>>>>>>> +    if (blk_is_inserted(blk) && bdrv_key_required(blk_bs(blk))) {
>>>>>>>           if (cur_mon) {
>>>>>>>               monitor_read_bdrv_key_start(cur_mon, blk_bs(blk),
>>>>>>> usb_msd_password_cb, s);
>>>>>> Why would bdrv_key_required() ever return true when no medium is
>>>>>> inserted? Sounds like a bug to me, like not resetting state 
>>>>>> correctly on
>>>>>> bdrv_close() of an encrypted image.
>>>>> The point is that blk_bs(blk) might be NULL.
>>>> This is not what blk_is_inserted() is checking. It happens to protect
>>>> you against segfaults because it's robust against using NULL, but with
>>>> an existing BDS, checking whether there is a medium inserted (in the
>>>> physical device for passthrough drivers) doesn't make sense.
>>> Not right now it's not. See patch 6.
>> Patch 6 looks unrelated, at least in v2. But if you're trying to say
>> that I looked at the wrong version, you're right: It doesn't protect you
>> against segfaults at this point yet (which is okay, because blk->bs
>> can't be NULL yet), it only performs the misguided inserted check.
>
> Oops, yes, I meant patch 7.
>
>> Doesn't answer my initial question or make that check any better.
>
> The answer to your initial question is: bdrv_key_required() assumes a 
> non-NULL BDS pointer is passed (which is reasonable). Therefore, it 
> crashes when "no medium is inserted" in the sense of !blk_bs(blk).
>
> How it makes the check better: I'll move it after patch 7.

And after realizing that patch 8 breaks this (because you might have a 
non-inserted host CD-ROM backing an encrypted qcow2 file), I'll use 
blk_bs(blk) instead of blk_is_inserted(blk).

Max

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 04/37] hw/usb-storage: Check whether BB is inserted
  2015-03-04 14:41             ` Max Reitz
  2015-03-04 14:52               ` Max Reitz
@ 2015-03-04 14:53               ` Kevin Wolf
  2015-03-04 14:58                 ` Max Reitz
  1 sibling, 1 reply; 80+ messages in thread
From: Kevin Wolf @ 2015-03-04 14:53 UTC (permalink / raw)
  To: Max Reitz; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

Am 04.03.2015 um 15:41 hat Max Reitz geschrieben:
> On 2015-03-04 at 09:39, Kevin Wolf wrote:
> >Am 04.03.2015 um 15:24 hat Max Reitz geschrieben:
> >>On 2015-03-04 at 09:20, Kevin Wolf wrote:
> >>>Am 04.03.2015 um 15:07 hat Max Reitz geschrieben:
> >>>>On 2015-03-04 at 09:02, Kevin Wolf wrote:
> >>>>>Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
> >>>>>>Only call bdrv_key_required() on the BlockDriverState if the
> >>>>>>BlockBackend has an inserted medium.
> >>>>>>
> >>>>>>Signed-off-by: Max Reitz <mreitz@redhat.com>
> >>>>>>Reviewed-by: Eric Blake <eblake@redhat.com>
> >>>>>>---
> >>>>>>  hw/usb/dev-storage.c | 2 +-
> >>>>>>  1 file changed, 1 insertion(+), 1 deletion(-)
> >>>>>>
> >>>>>>diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
> >>>>>>index 4539733..3123baf 100644
> >>>>>>--- a/hw/usb/dev-storage.c
> >>>>>>+++ b/hw/usb/dev-storage.c
> >>>>>>@@ -638,7 +638,7 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
> >>>>>>      usb_msd_handle_reset(dev);
> >>>>>>      s->scsi_dev = scsi_dev;
> >>>>>>-    if (bdrv_key_required(blk_bs(blk))) {
> >>>>>>+    if (blk_is_inserted(blk) && bdrv_key_required(blk_bs(blk))) {
> >>>>>>          if (cur_mon) {
> >>>>>>              monitor_read_bdrv_key_start(cur_mon, blk_bs(blk),
> >>>>>>                                          usb_msd_password_cb, s);
> >>>>>Why would bdrv_key_required() ever return true when no medium is
> >>>>>inserted? Sounds like a bug to me, like not resetting state correctly on
> >>>>>bdrv_close() of an encrypted image.
> >>>>The point is that blk_bs(blk) might be NULL.
> >>>This is not what blk_is_inserted() is checking. It happens to protect
> >>>you against segfaults because it's robust against using NULL, but with
> >>>an existing BDS, checking whether there is a medium inserted (in the
> >>>physical device for passthrough drivers) doesn't make sense.
> >>Not right now it's not. See patch 6.
> >Patch 6 looks unrelated, at least in v2. But if you're trying to say
> >that I looked at the wrong version, you're right: It doesn't protect you
> >against segfaults at this point yet (which is okay, because blk->bs
> >can't be NULL yet), it only performs the misguided inserted check.
> 
> Oops, yes, I meant patch 7.
> 
> >Doesn't answer my initial question or make that check any better.
> 
> The answer to your initial question is: bdrv_key_required() assumes
> a non-NULL BDS pointer is passed (which is reasonable). Therefore,
> it crashes when "no medium is inserted" in the sense of
> !blk_bs(blk).

That's a great argument in favour of checking blk_bs(bs), but I can't
see how it's one for the completely unrelated blk_inserted(blk).

Kevin

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 04/37] hw/usb-storage: Check whether BB is inserted
  2015-03-04 14:53               ` Kevin Wolf
@ 2015-03-04 14:58                 ` Max Reitz
  0 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-03-04 14:58 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

On 2015-03-04 at 09:53, Kevin Wolf wrote:
> Am 04.03.2015 um 15:41 hat Max Reitz geschrieben:
>> On 2015-03-04 at 09:39, Kevin Wolf wrote:
>>> Am 04.03.2015 um 15:24 hat Max Reitz geschrieben:
>>>> On 2015-03-04 at 09:20, Kevin Wolf wrote:
>>>>> Am 04.03.2015 um 15:07 hat Max Reitz geschrieben:
>>>>>> On 2015-03-04 at 09:02, Kevin Wolf wrote:
>>>>>>> Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
>>>>>>>> Only call bdrv_key_required() on the BlockDriverState if the
>>>>>>>> BlockBackend has an inserted medium.
>>>>>>>>
>>>>>>>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>>>>>>>> Reviewed-by: Eric Blake <eblake@redhat.com>
>>>>>>>> ---
>>>>>>>>   hw/usb/dev-storage.c | 2 +-
>>>>>>>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>>>>>>>
>>>>>>>> diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
>>>>>>>> index 4539733..3123baf 100644
>>>>>>>> --- a/hw/usb/dev-storage.c
>>>>>>>> +++ b/hw/usb/dev-storage.c
>>>>>>>> @@ -638,7 +638,7 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
>>>>>>>>       usb_msd_handle_reset(dev);
>>>>>>>>       s->scsi_dev = scsi_dev;
>>>>>>>> -    if (bdrv_key_required(blk_bs(blk))) {
>>>>>>>> +    if (blk_is_inserted(blk) && bdrv_key_required(blk_bs(blk))) {
>>>>>>>>           if (cur_mon) {
>>>>>>>>               monitor_read_bdrv_key_start(cur_mon, blk_bs(blk),
>>>>>>>>                                           usb_msd_password_cb, s);
>>>>>>> Why would bdrv_key_required() ever return true when no medium is
>>>>>>> inserted? Sounds like a bug to me, like not resetting state correctly on
>>>>>>> bdrv_close() of an encrypted image.
>>>>>> The point is that blk_bs(blk) might be NULL.
>>>>> This is not what blk_is_inserted() is checking. It happens to protect
>>>>> you against segfaults because it's robust against using NULL, but with
>>>>> an existing BDS, checking whether there is a medium inserted (in the
>>>>> physical device for passthrough drivers) doesn't make sense.
>>>> Not right now it's not. See patch 6.
>>> Patch 6 looks unrelated, at least in v2. But if you're trying to say
>>> that I looked at the wrong version, you're right: It doesn't protect you
>>> against segfaults at this point yet (which is okay, because blk->bs
>>> can't be NULL yet), it only performs the misguided inserted check.
>> Oops, yes, I meant patch 7.
>>
>>> Doesn't answer my initial question or make that check any better.
>> The answer to your initial question is: bdrv_key_required() assumes
>> a non-NULL BDS pointer is passed (which is reasonable). Therefore,
>> it crashes when "no medium is inserted" in the sense of
>> !blk_bs(blk).
> That's a great argument in favour of checking blk_bs(bs), but I can't
> see how it's one for the completely unrelated blk_inserted(blk).

As said in IRC, I used blk_is_inserted() because it had the side-effect 
of preventing dereferencing the NULL pointer, but I like it much more 
than calling blk_bs() for that.

Why is that? Because no code outside of the block layer should access 
the BDS directly, therefore, blk_bs() should not be called outside of 
the block layer. Why don't I add blk_key_required()? Because that 
function does not work on the BB level, but only per BDS, so I will not 
add that BB function.

So I didn't want to add more of the ugliness that makes this code here 
so ugly to it, but then again, it's the only correct way, you're right 
(except for the "remove this completely out-of-place code from here").

Max

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 01/37] blockdev: Allow creation of BDS trees without BB
  2015-03-04 13:39   ` Kevin Wolf
  2015-03-04 14:04     ` Max Reitz
@ 2015-03-04 21:44     ` Max Reitz
  1 sibling, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-03-04 21:44 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

On 2015-03-04 at 08:39, Kevin Wolf wrote:
> Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
>> If the "id" field is missing from the options given to blockdev-add,
>> just omit the BlockBackend and create the BlockDriverState tree alone.
>>
>> However, if "id" is missing, "node-name" must be specified; otherwise,
>> the BDS tree would no longer be accessible.
>>
>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>> ---
>>   blockdev.c                 | 44 +++++++++++++++++++++++++++++++-------------
>>   qapi/block-core.json       | 13 +++++++++----
>>   tests/qemu-iotests/087     |  2 +-
>>   tests/qemu-iotests/087.out |  4 ++--
>>   4 files changed, 43 insertions(+), 20 deletions(-)
>>
>> diff --git a/blockdev.c b/blockdev.c
>> index 6eedcf5..6d67c80 100644
>> --- a/blockdev.c
>> +++ b/blockdev.c
>> @@ -2822,17 +2822,12 @@ out:
>>   void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
>>   {
>>       QmpOutputVisitor *ov = qmp_output_visitor_new();
>> -    BlockBackend *blk;
>> +    BlockDriverState *bs;
>> +    BlockBackend *blk = NULL;
>>       QObject *obj;
>>       QDict *qdict;
>>       Error *local_err = NULL;
>>   
>> -    /* Require an ID in the top level */
>> -    if (!options->has_id) {
>> -        error_setg(errp, "Block device needs an ID");
>> -        goto fail;
>> -    }
>> -
>>       /* TODO Sort it out in raw-posix and drive_new(): Reject aio=native with
>>        * cache.direct=false instead of silently switching to aio=threads, except
>>        * when called from drive_new().
>> @@ -2860,14 +2855,37 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
>>   
>>       qdict_flatten(qdict);
>>   
>> -    blk = blockdev_init(NULL, qdict, &local_err);
>> -    if (local_err) {
>> -        error_propagate(errp, local_err);
>> -        goto fail;
>> +    if (options->has_id) {
>> +        blk = blockdev_init(NULL, qdict, &local_err);
>> +        if (local_err) {
>> +            error_propagate(errp, local_err);
>> +            goto fail;
>> +        }
>> +
>> +        bs = blk_bs(blk);
>> +    } else {
>> +        int ret;
>> +
>> +        if (!qdict_get_try_str(qdict, "node-name")) {
>> +            error_setg(errp, "'id' and/or 'node-name' need to be specified for "
>> +                       "the root node");
>> +            goto fail;
>> +        }
>> +
>> +        bs = NULL;
>> +        ret = bdrv_open(&bs, NULL, NULL, qdict, BDRV_O_RDWR | BDRV_O_CACHE_WB,
>> +                        NULL, errp);
> Now all the qdict entries that aren't parsed by bdrv_open() but
> converted into flags by blockdev_init() are broken if you don't give an
> id. This includes read-only, discard, the cache options - in other
> words, enough to make this "support" completely useless.
>
> I guess I need to dig out my cache mode series and get it ready to be
> merged. Once this is in, the parsing of the other necessary options
> should be easy to move into bdrv_open().
>
> Unless you have a good reason why we should merge this patch in its
> hardly functional state now, I would consider those conversions a
> dependency of this one.

Because I will not send out another version of this series for the next 
two weeks, I'll just give an overview of where I'm currently at (for 
each of the patches you replied to):

We need this patch before "block: Make bdrv_is_inserted() recursive", 
because that patch makes the problems apparent which are fixed in my 
bdrv_close_all() series (071 fails, because flushing the qcow2 metadata 
suddenly no longer results in an error; this is because 
bdrv_is_inserted() now returns false because the file BDS under qcow2 
has been closed (because it has a BB), so it's no longer inserted). 
Therefore, we need patch 2 before said patch to work around the problem 
(until it's fixed by the respective series, which depends on this one, 
however).

I could probably split up patch 22 and pull the first part up front, 
along with patch 23, but this would require work, which I don't deem 
necessary. As I said before, in my opinion this patch does not break any 
existing valid usage of blockdev-add, it's just that there are some use 
cases we want to have after this patch that do not work yet. But they 
will be added in a later patch in this series, so I don't find this an 
issue.

Therefore, for this patch, I'll add a note into the commit message 
stating that there will be a follow-up patch allowing options that are 
not parsed by bdrv_open() (like caching) to be given.

Max

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 03/37] hw/block/fdc: Implement tray status
  2015-03-04 14:00   ` Kevin Wolf
  2015-03-04 14:07     ` Max Reitz
@ 2015-03-04 22:06     ` Max Reitz
  2015-03-05 10:11       ` Kevin Wolf
  1 sibling, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-03-04 22:06 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

On 2015-03-04 at 09:00, Kevin Wolf wrote:
> Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
>> The tray of an FDD is open iff there is no medium inserted (there are
>> only two states for an FDD: "medium inserted" or "no medium inserted").
>>
>> This results in the tray being reported as open if qemu has been started
>> with the default floppy drive, which breaks some tests. Fix them.
>>
>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>> ---
>>   hw/block/fdc.c             | 20 +++++++++++++---
>>   tests/fdc-test.c           |  4 +---
>>   tests/qemu-iotests/067.out | 60 +++++++---------------------------------------
>>   tests/qemu-iotests/071.out |  2 --
>>   tests/qemu-iotests/081.out |  1 -
>>   tests/qemu-iotests/087.out |  6 -----
>>   6 files changed, 26 insertions(+), 67 deletions(-)
>>
>> diff --git a/hw/block/fdc.c b/hw/block/fdc.c
>> index 2bf87c9..0c5a6b4 100644
>> --- a/hw/block/fdc.c
>> +++ b/hw/block/fdc.c
>> @@ -192,6 +192,8 @@ typedef struct FDrive {
>>       uint8_t ro;               /* Is read-only           */
>>       uint8_t media_changed;    /* Is media changed       */
>>       uint8_t media_rate;       /* Data rate of medium    */
>> +
>> +    bool media_inserted;      /* Is there a medium in the tray */
>>   } FDrive;
>>   
>>   static void fd_init(FDrive *drv)
>> @@ -261,7 +263,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
>>   #endif
>>           drv->head = head;
>>           if (drv->track != track) {
>> -            if (drv->blk != NULL && blk_is_inserted(drv->blk)) {
>> +            if (drv->media_inserted) {
> I suspect that with the removal of blk_is_inserted() in several places,
> floppy passthrough (host_floppy block driver) is now even more broken
> than before, potentially not noticing removal of a medium any more.
>
> While checking this, I noticed that since commit 21fcf360,
> bdrv_media_changed() is completely unused. Media change has therefore
> probably been broken since at least May 2012.
>
> Considering this, it might actually be reasonable enough to remove the
> block driver. It's definitely better than having it there, but not
> working any better than host_device.
>
> Of course, alternatively you would also be welcome to fix the device
> model and reintroduce bdrv_media_changed() and blk_is_inserted() calls
> where necessary.

Status:

I thought about why I need this tray status at all. The result is: We 
need it because otherwise blockdev-close-tray doesn't do anything on 
floppy disk drives (you'd insert a medium with blockdev-insert-medium 
and the tray would immediately be reported as being closed, without any 
TRAY_MOVED event). So we do need it.

I tested floppy passthrough in a VM and it's horror, as can be expected. 
For instance, one cannot start qemu with floppy passthrough if the host 
drive is empty (which is actually helpful).

So what I'll be doing is set media_inserted to load && drv->blk in the 
media change CB and set it to true in the floppy drive initialization 
code if there is a BB and blk_is_inserted() is true. The tray will be 
considered closed if media_inserted && blk_is_inserted().

So why do I check blk_is_inserted() in the initialization code? If we 
just set media_inserted to true, that would be wrong. Imagine an empty 
drive (no BDS tree), media_inserted will be set to true, then you 
inserted a BDS tree (blockdev-insert-medium) and the tray will be 
considered closed without you having executed blockdev-close-tray 
(media_inserted is true, and now blk_is_inserted() is true as well).

So I have to check whether there's a BDS tree in the initialization 
code, if there isn't, media_inserted must be false. Why am I not using 
blk_bs() for that? I tried to explain for the USB patch: blk_bs() 
returns a BDS, and that's something for the block layer, nobody else 
should care about that.

How could blk_is_inserted() be wrong here, if blk_bs() is the thing that 
will work? Correct, if blk_bs() && !bdrv_is_inserted(blk_bs()). However, 
this will never be the case, because as said above, qemu actually cannot 
start with a host floppy drive without a medium, so 
!!blk_is_inserted(blk) == !!blk_bs(blk).

I see the question popping up "Why don't you just add a bool has_bs(BB) 
{ return blk_bs(BB); } and then not add that test to blk_is_inserted()"? 
I've asked that myself. Answer: Again, anything outside of the block 
layer should not care about things like BDS trees. But moreover, 
bdrv_is_inserted() does not only check whether all the host devices 
represented by BDSs are inserted, but also whether BDS.drv != NULL, 
which until this series was the sign for an empty drive. Therefore, 
checking blk_is_inserted() is the logical conclusion of 
bdrv_is_inserted() (bdrv_is_inserted() tests whether BDS.drv != NULL, 
blk_is_inserted() tests whether BLK.bs != NULL).

But medium management is now done on the BB level, so a separate 
function for checking whether there's a BDS tree (because that should be 
equivalent to "whether there's a medium") seems to have its merits. 
However, I don't think so. blk_is_inserted() is exactly that function: 
It's true if there is a BDS tree and, if there is host passthrough, 
whether all the media are inserted, which is correct.

In theory, guest models should not have to distinguish whether a BB does 
not have a medium because there is no BDS tree or because we're using 
passthrough and that BDS does not have a medium. So why does floppy have 
to distinguish? Because it does not have a real tray, but that's the 
model we have to be working with. Inserting a medium into a 
passed-through host drive must result in the tray being considered 
closed immediately; inserting a medium into a guest device through 
blockdev-insert-medium must not.

So our bane is that we need tray status for floppy disks but they don't 
have a tray, so inserting a medium in a host drive does something 
different than doing the same in a purely virtual drive. Dropping 
host_floppy probably solves that problem, but I'm too cautious for that.

Max

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 04/37] hw/usb-storage: Check whether BB is inserted
  2015-03-04 14:02   ` Kevin Wolf
  2015-03-04 14:07     ` Max Reitz
@ 2015-03-04 22:06     ` Max Reitz
  1 sibling, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-03-04 22:06 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

On 2015-03-04 at 09:02, Kevin Wolf wrote:
> Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
>> Only call bdrv_key_required() on the BlockDriverState if the
>> BlockBackend has an inserted medium.
>>
>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>> Reviewed-by: Eric Blake <eblake@redhat.com>
>> ---
>>   hw/usb/dev-storage.c | 2 +-
>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
>> index 4539733..3123baf 100644
>> --- a/hw/usb/dev-storage.c
>> +++ b/hw/usb/dev-storage.c
>> @@ -638,7 +638,7 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
>>       usb_msd_handle_reset(dev);
>>       s->scsi_dev = scsi_dev;
>>   
>> -    if (bdrv_key_required(blk_bs(blk))) {
>> +    if (blk_is_inserted(blk) && bdrv_key_required(blk_bs(blk))) {
>>           if (cur_mon) {
>>               monitor_read_bdrv_key_start(cur_mon, blk_bs(blk),
>>                                           usb_msd_password_cb, s);
> Why would bdrv_key_required() ever return true when no medium is
> inserted? Sounds like a bug to me, like not resetting state correctly on
> bdrv_close() of an encrypted image.

Status: s/is_inserted/bs/

Max

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 03/37] hw/block/fdc: Implement tray status
  2015-03-04 22:06     ` Max Reitz
@ 2015-03-05 10:11       ` Kevin Wolf
  2015-03-16 13:36         ` Max Reitz
  0 siblings, 1 reply; 80+ messages in thread
From: Kevin Wolf @ 2015-03-05 10:11 UTC (permalink / raw)
  To: Max Reitz; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

Am 04.03.2015 um 23:06 hat Max Reitz geschrieben:
> On 2015-03-04 at 09:00, Kevin Wolf wrote:
> >Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
> >>The tray of an FDD is open iff there is no medium inserted (there are
> >>only two states for an FDD: "medium inserted" or "no medium inserted").
> >>
> >>This results in the tray being reported as open if qemu has been started
> >>with the default floppy drive, which breaks some tests. Fix them.
> >>
> >>Signed-off-by: Max Reitz <mreitz@redhat.com>
> >>---
> >>  hw/block/fdc.c             | 20 +++++++++++++---
> >>  tests/fdc-test.c           |  4 +---
> >>  tests/qemu-iotests/067.out | 60 +++++++---------------------------------------
> >>  tests/qemu-iotests/071.out |  2 --
> >>  tests/qemu-iotests/081.out |  1 -
> >>  tests/qemu-iotests/087.out |  6 -----
> >>  6 files changed, 26 insertions(+), 67 deletions(-)
> >>
> >>diff --git a/hw/block/fdc.c b/hw/block/fdc.c
> >>index 2bf87c9..0c5a6b4 100644
> >>--- a/hw/block/fdc.c
> >>+++ b/hw/block/fdc.c
> >>@@ -192,6 +192,8 @@ typedef struct FDrive {
> >>      uint8_t ro;               /* Is read-only           */
> >>      uint8_t media_changed;    /* Is media changed       */
> >>      uint8_t media_rate;       /* Data rate of medium    */
> >>+
> >>+    bool media_inserted;      /* Is there a medium in the tray */
> >>  } FDrive;
> >>  static void fd_init(FDrive *drv)
> >>@@ -261,7 +263,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
> >>  #endif
> >>          drv->head = head;
> >>          if (drv->track != track) {
> >>-            if (drv->blk != NULL && blk_is_inserted(drv->blk)) {
> >>+            if (drv->media_inserted) {
> >I suspect that with the removal of blk_is_inserted() in several places,
> >floppy passthrough (host_floppy block driver) is now even more broken
> >than before, potentially not noticing removal of a medium any more.
> >
> >While checking this, I noticed that since commit 21fcf360,
> >bdrv_media_changed() is completely unused. Media change has therefore
> >probably been broken since at least May 2012.
> >
> >Considering this, it might actually be reasonable enough to remove the
> >block driver. It's definitely better than having it there, but not
> >working any better than host_device.
> >
> >Of course, alternatively you would also be welcome to fix the device
> >model and reintroduce bdrv_media_changed() and blk_is_inserted() calls
> >where necessary.
> 
> Status:
> 
> I thought about why I need this tray status at all. The result is:
> We need it because otherwise blockdev-close-tray doesn't do anything
> on floppy disk drives (you'd insert a medium with
> blockdev-insert-medium and the tray would immediately be reported as
> being closed, without any TRAY_MOVED event). So we do need it.
> 
> I tested floppy passthrough in a VM and it's horror, as can be
> expected. For instance, one cannot start qemu with floppy
> passthrough if the host drive is empty (which is actually helpful).
> 
> So what I'll be doing is set media_inserted to load && drv->blk in
> the media change CB and set it to true in the floppy drive
> initialization code if there is a BB and blk_is_inserted() is true.
> The tray will be considered closed if media_inserted &&
> blk_is_inserted().
> 
> So why do I check blk_is_inserted() in the initialization code? If
> we just set media_inserted to true, that would be wrong. Imagine an
> empty drive (no BDS tree), media_inserted will be set to true, then
> you inserted a BDS tree (blockdev-insert-medium) and the tray will
> be considered closed without you having executed blockdev-close-tray
> (media_inserted is true, and now blk_is_inserted() is true as well).
> 
> So I have to check whether there's a BDS tree in the initialization
> code, if there isn't, media_inserted must be false. Why am I not
> using blk_bs() for that? I tried to explain for the USB patch:
> blk_bs() returns a BDS, and that's something for the block layer,
> nobody else should care about that.

This is silly, Max.

Correctness isn't defined by what you _should_ care about, but by what
you actually _need_ to know. This is where you need to start your
considerations, not with what you think you're supposed to be asking.

If the two contradict, then there are two options: Either the assumption
that you shouldn't care is wrong, or your decision that you need the
information is. This conflict needs to be resolved rather than just
working with the answer to a different question.

In this case, I think the problem starts with "empty drive (no BDS
tree)". This is not correct, an empty drive is defined by
!blk_is_inserted(bs) and not by an empty BDS tree. The passthrough case
(with a hypothetical correct implementation) helps you distinguish the
two. So your assumption that you really need to check whether there is
no BDS tree is wrong here. You need to check whether there is a medium,
and that is blk_is_inserted(). (So yes, I agree with your conclusion,
but not with the way you got there.)

In the USB case, the problem was that a bdrv_*() function is called
(which already violates the rule that this is not for outside the block
layer) and a NULL check is needed there. In that case the assumption
that calling blk_bs() isn't allowed is wrong; it's simply necessary for
calling bdrv_*() functions.

In any case "I want to know A, but I'm not supposed to ask for A, so
I'll just check B" is not the way to go.

> How could blk_is_inserted() be wrong here, if blk_bs() is the thing
> that will work? Correct, if blk_bs() && !bdrv_is_inserted(blk_bs()).
> However, this will never be the case, because as said above, qemu
> actually cannot start with a host floppy drive without a medium, so
> !!blk_is_inserted(blk) == !!blk_bs(blk).

You called it "horror" above and now you want to rely on it?

The good thing is that I suspect that blk_bs() does _not_ work and
blk_is_inserted() is what you really needed in the first place.

> I see the question popping up "Why don't you just add a bool
> has_bs(BB) { return blk_bs(BB); } and then not add that test to
> blk_is_inserted()"? I've asked that myself. Answer: Again, anything
> outside of the block layer should not care about things like BDS
> trees. But moreover, bdrv_is_inserted() does not only check whether
> all the host devices represented by BDSs are inserted, but also
> whether BDS.drv != NULL, which until this series was the sign for an
> empty drive. Therefore, checking blk_is_inserted() is the logical
> conclusion of bdrv_is_inserted() (bdrv_is_inserted() tests whether
> BDS.drv != NULL, blk_is_inserted() tests whether BLK.bs != NULL).
> 
> But medium management is now done on the BB level, so a separate
> function for checking whether there's a BDS tree (because that
> should be equivalent to "whether there's a medium") seems to have
> its merits. However, I don't think so. blk_is_inserted() is exactly
> that function: It's true if there is a BDS tree and, if there is
> host passthrough, whether all the media are inserted, which is
> correct.

No, no, no, no, no.

Stop talking about implementation details, talk about concepts. The only
valid reason for calling blk_is_inserted() is that you want to know
whether a medium is inserted. If this is what you want to know, call it.
And if it isn't, be sure not to call it.

Whether it has a NULL check here or a BDS tree there doesn't matter at
all. You can't just call a function because it happens to have the right
side effects if it was never meant for the purpose you're using it.

For our specific case: blk->bs == NULL implies an empty drive, but
that's just an implication, not an equivalence. The other direction
isn't true. That's why it's important to distinguish the cases.

> In theory, guest models should not have to distinguish whether a BB
> does not have a medium because there is no BDS tree or because we're
> using passthrough and that BDS does not have a medium. So why does
> floppy have to distinguish? Because it does not have a real tray,
> but that's the model we have to be working with. Inserting a medium
> into a passed-through host drive must result in the tray being
> considered closed immediately; inserting a medium into a guest
> device through blockdev-insert-medium must not.

That's the job of the block layer, not of the floppy emulation.

It's actually not much different from CD-ROM passthrough, where you do
have a tray on both the guest and the host. Loading the new medium and
closing the tray will have to be a single action there, because real
CD-ROMs just don't report whether there is a medium in their open tray.

Kevin

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 03/37] hw/block/fdc: Implement tray status
  2015-03-05 10:11       ` Kevin Wolf
@ 2015-03-16 13:36         ` Max Reitz
  2015-03-16 15:47           ` Markus Armbruster
  0 siblings, 1 reply; 80+ messages in thread
From: Max Reitz @ 2015-03-16 13:36 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: John Snow, qemu-devel, Stefan Hajnoczi, Markus Armbruster

On 2015-03-05 at 05:11, Kevin Wolf wrote:
> Am 04.03.2015 um 23:06 hat Max Reitz geschrieben:
>> On 2015-03-04 at 09:00, Kevin Wolf wrote:
>>> Am 09.02.2015 um 18:11 hat Max Reitz geschrieben:
>>>> The tray of an FDD is open iff there is no medium inserted (there are
>>>> only two states for an FDD: "medium inserted" or "no medium inserted").
>>>>
>>>> This results in the tray being reported as open if qemu has been started
>>>> with the default floppy drive, which breaks some tests. Fix them.
>>>>
>>>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>>>> ---
>>>>   hw/block/fdc.c             | 20 +++++++++++++---
>>>>   tests/fdc-test.c           |  4 +---
>>>>   tests/qemu-iotests/067.out | 60 +++++++---------------------------------------
>>>>   tests/qemu-iotests/071.out |  2 --
>>>>   tests/qemu-iotests/081.out |  1 -
>>>>   tests/qemu-iotests/087.out |  6 -----
>>>>   6 files changed, 26 insertions(+), 67 deletions(-)
>>>>
>>>> diff --git a/hw/block/fdc.c b/hw/block/fdc.c
>>>> index 2bf87c9..0c5a6b4 100644
>>>> --- a/hw/block/fdc.c
>>>> +++ b/hw/block/fdc.c
>>>> @@ -192,6 +192,8 @@ typedef struct FDrive {
>>>>       uint8_t ro;               /* Is read-only           */
>>>>       uint8_t media_changed;    /* Is media changed       */
>>>>       uint8_t media_rate;       /* Data rate of medium    */
>>>> +
>>>> +    bool media_inserted;      /* Is there a medium in the tray */
>>>>   } FDrive;
>>>>   static void fd_init(FDrive *drv)
>>>> @@ -261,7 +263,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
>>>>   #endif
>>>>           drv->head = head;
>>>>           if (drv->track != track) {
>>>> -            if (drv->blk != NULL && blk_is_inserted(drv->blk)) {
>>>> +            if (drv->media_inserted) {
>>> I suspect that with the removal of blk_is_inserted() in several places,
>>> floppy passthrough (host_floppy block driver) is now even more broken
>>> than before, potentially not noticing removal of a medium any more.
>>>
>>> While checking this, I noticed that since commit 21fcf360,
>>> bdrv_media_changed() is completely unused. Media change has therefore
>>> probably been broken since at least May 2012.
>>>
>>> Considering this, it might actually be reasonable enough to remove the
>>> block driver. It's definitely better than having it there, but not
>>> working any better than host_device.
>>>
>>> Of course, alternatively you would also be welcome to fix the device
>>> model and reintroduce bdrv_media_changed() and blk_is_inserted() calls
>>> where necessary.
>> Status:
>>
>> I thought about why I need this tray status at all. The result is:
>> We need it because otherwise blockdev-close-tray doesn't do anything
>> on floppy disk drives (you'd insert a medium with
>> blockdev-insert-medium and the tray would immediately be reported as
>> being closed, without any TRAY_MOVED event). So we do need it.
>>
>> I tested floppy passthrough in a VM and it's horror, as can be
>> expected. For instance, one cannot start qemu with floppy
>> passthrough if the host drive is empty (which is actually helpful).
>>
>> So what I'll be doing is set media_inserted to load && drv->blk in
>> the media change CB and set it to true in the floppy drive
>> initialization code if there is a BB and blk_is_inserted() is true.
>> The tray will be considered closed if media_inserted &&
>> blk_is_inserted().
>>
>> So why do I check blk_is_inserted() in the initialization code? If
>> we just set media_inserted to true, that would be wrong. Imagine an
>> empty drive (no BDS tree), media_inserted will be set to true, then
>> you inserted a BDS tree (blockdev-insert-medium) and the tray will
>> be considered closed without you having executed blockdev-close-tray
>> (media_inserted is true, and now blk_is_inserted() is true as well).
>>
>> So I have to check whether there's a BDS tree in the initialization
>> code, if there isn't, media_inserted must be false. Why am I not
>> using blk_bs() for that? I tried to explain for the USB patch:
>> blk_bs() returns a BDS, and that's something for the block layer,
>> nobody else should care about that.
> This is silly, Max.
>
> Correctness isn't defined by what you _should_ care about, but by what
> you actually _need_ to know. This is where you need to start your
> considerations, not with what you think you're supposed to be asking.
>
> If the two contradict, then there are two options: Either the assumption
> that you shouldn't care is wrong, or your decision that you need the
> information is. This conflict needs to be resolved rather than just
> working with the answer to a different question.
>
> In this case, I think the problem starts with "empty drive (no BDS
> tree)".

I meant "Imagine an empty drive without a BDS tree" or "Imagine a drive 
without a BDS tree, thus empty.", so rather "an empty drive, e.g. no BDS 
tree" than "an empty drive, i.e. no BDS tree".

> This is not correct, an empty drive is defined by
> !blk_is_inserted(bs) and not by an empty BDS tree. The passthrough case
> (with a hypothetical correct implementation) helps you distinguish the
> two. So your assumption that you really need to check whether there is
> no BDS tree is wrong here. You need to check whether there is a medium,
> and that is blk_is_inserted(). (So yes, I agree with your conclusion,
> but not with the way you got there.)

So what I was justifying is that blk_bs() will work, not that 
blk_is_inserted() will not work. So why do I think that 
blk_is_inserted() is not really what we want here?

Okay, so imagine the case where !!blk_bs() != blk_is_inserted() at 
startup. That means, the host drive is empty. Now we insert a medium in 
the host drive. Floppy being floppy, qemu won't have any idea that a 
medium has been inserted. This means that media_inserted will still be 
false and any read to the BB will be stopped in the device model, so 
qemu will not have a chance of noticing there is a medium now (it only 
has if the host floppy BDS is accessed).

Thus, using blk_is_inserted() without a medium at startup will not allow 
the guest to ever read from the disk, unless you manually execute 
blockdev-close-tray over QMP (I'm not even sure whether that works, but 
I guess it might).

> In the USB case, the problem was that a bdrv_*() function is called
> (which already violates the rule that this is not for outside the block
> layer) and a NULL check is needed there. In that case the assumption
> that calling blk_bs() isn't allowed is wrong; it's simply necessary for
> calling bdrv_*() functions.
>
> In any case "I want to know A, but I'm not supposed to ask for A, so
> I'll just check B" is not the way to go.

Except for when A and B are functionally equivalent.

>> How could blk_is_inserted() be wrong here, if blk_bs() is the thing
>> that will work? Correct, if blk_bs() && !bdrv_is_inserted(blk_bs()).
>> However, this will never be the case, because as said above, qemu
>> actually cannot start with a host floppy drive without a medium, so
>> !!blk_is_inserted(blk) == !!blk_bs(blk).
> You called it "horror" above and now you want to rely on it?

I said: It's horror, but it "is actually helpful". And this is what I 
meant by it.

> The good thing is that I suspect that blk_bs() does _not_ work and
> blk_is_inserted() is what you really needed in the first place.
>
>> I see the question popping up "Why don't you just add a bool
>> has_bs(BB) { return blk_bs(BB); } and then not add that test to
>> blk_is_inserted()"? I've asked that myself. Answer: Again, anything
>> outside of the block layer should not care about things like BDS
>> trees. But moreover, bdrv_is_inserted() does not only check whether
>> all the host devices represented by BDSs are inserted, but also
>> whether BDS.drv != NULL, which until this series was the sign for an
>> empty drive. Therefore, checking blk_is_inserted() is the logical
>> conclusion of bdrv_is_inserted() (bdrv_is_inserted() tests whether
>> BDS.drv != NULL, blk_is_inserted() tests whether BLK.bs != NULL).
>>
>> But medium management is now done on the BB level, so a separate
>> function for checking whether there's a BDS tree (because that
>> should be equivalent to "whether there's a medium") seems to have
>> its merits. However, I don't think so. blk_is_inserted() is exactly
>> that function: It's true if there is a BDS tree and, if there is
>> host passthrough, whether all the media are inserted, which is
>> correct.
> No, no, no, no, no.
>
> Stop talking about implementation details, talk about concepts. The only
> valid reason for calling blk_is_inserted() is that you want to know
> whether a medium is inserted. If this is what you want to know, call it.
> And if it isn't, be sure not to call it.

Maybe. I hate host passthrough, and floppy is the worst incarnation of 
it. What does this have to do with anything? See my reasoning above why 
blk_is_inserted() is actually sometimes not what we want to use.

> Whether it has a NULL check here or a BDS tree there doesn't matter at
> all. You can't just call a function because it happens to have the right
> side effects if it was never meant for the purpose you're using it.

The problem is that blk_is_inserted() was meant for the purpose I'm 
using it for, as you yourself said, but it just breaks with floppy 
passthrough because we have to make the guest access the BDS tree even 
if there is no medium there.

> For our specific case: blk->bs == NULL implies an empty drive, but
> that's just an implication, not an equivalence. The other direction
> isn't true. That's why it's important to distinguish the cases.
>
>> In theory, guest models should not have to distinguish whether a BB
>> does not have a medium because there is no BDS tree or because we're
>> using passthrough and that BDS does not have a medium. So why does
>> floppy have to distinguish? Because it does not have a real tray,
>> but that's the model we have to be working with. Inserting a medium
>> into a passed-through host drive must result in the tray being
>> considered closed immediately; inserting a medium into a guest
>> device through blockdev-insert-medium must not.
> That's the job of the block layer, not of the floppy emulation.

So do you want to fix the floppy passthrough code? I don't even know how 
to fix it. I don't even know what's wrong with it, other than that 
something's ought to be wrong.

>
> It's actually not much different from CD-ROM passthrough, where you do
> have a tray on both the guest and the host. Loading the new medium and
> closing the tray will have to be a single action there, because real
> CD-ROMs just don't report whether there is a medium in their open tray.
>
> Kevin

So, what I'm taking from this is the following: media_inserted is a kind 
of strong attribute. If it is false, no accesses to the BB will be 
generated whatsoever, and thus the host drive status will not be 
updated. So we need to make sure it's only false if we really don't care 
about the BB or the BDS tree; and that's only if there is no BDS tree at 
all.

Because I understand your reasoning on "don't use B if A gives you what 
you really want, and B just happens to behave the same here", I will be 
using blk_bs() here, too, instead of blk_is_inserted(), unless you don't 
find my reasoning correct, and although I'm still very much against 
using blk_bs() somewhere like here. I will be able to live with it here, 
just because it's FDD emulation and adding a drive status to it is kind 
of kaput in itself.

Max

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 03/37] hw/block/fdc: Implement tray status
  2015-03-16 13:36         ` Max Reitz
@ 2015-03-16 15:47           ` Markus Armbruster
  2015-03-16 15:48             ` Max Reitz
  0 siblings, 1 reply; 80+ messages in thread
From: Markus Armbruster @ 2015-03-16 15:47 UTC (permalink / raw)
  To: Max Reitz; +Cc: Kevin Wolf, John Snow, qemu-devel, Stefan Hajnoczi

Max Reitz <mreitz@redhat.com> writes:

[...]
> So do you want to fix the floppy passthrough code? I don't even know
> how to fix it. I don't even know what's wrong with it, other than that
> something's ought to be wrong.

Having a driver to pass-through hardware next to nobody has anymore is
one thing.  But maintaining special cases in the generic block layer for
it is another thing altogether: media handling is different, and the
difference is not fully encapsulated in the driver (at least last time I
checked).

Can anybody tell me why spending developer time on floppy passthrough is
a justifiable investment?

If not, let's drop it and move on.

[...]

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [Qemu-devel] [PATCH v2 03/37] hw/block/fdc: Implement tray status
  2015-03-16 15:47           ` Markus Armbruster
@ 2015-03-16 15:48             ` Max Reitz
  0 siblings, 0 replies; 80+ messages in thread
From: Max Reitz @ 2015-03-16 15:48 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: Kevin Wolf, John Snow, qemu-devel, Stefan Hajnoczi

On 2015-03-16 at 11:47, Markus Armbruster wrote:
> Max Reitz <mreitz@redhat.com> writes:
>
> [...]
>> So do you want to fix the floppy passthrough code? I don't even know
>> how to fix it. I don't even know what's wrong with it, other than that
>> something's ought to be wrong.
> Having a driver to pass-through hardware next to nobody has anymore is
> one thing.  But maintaining special cases in the generic block layer for
> it is another thing altogether: media handling is different, and the
> difference is not fully encapsulated in the driver (at least last time I
> checked).
>
> Can anybody tell me why spending developer time on floppy passthrough is
> a justifiable investment?
>
> If not, let's drop it and move on.

Do you want to do it? I don't want to be held responsible for it. ;-)

Max

^ permalink raw reply	[flat|nested] 80+ messages in thread

end of thread, other threads:[~2015-03-16 15:48 UTC | newest]

Thread overview: 80+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-09 17:11 [Qemu-devel] [PATCH v2 00/37] blockdev: BlockBackend and media Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 01/37] blockdev: Allow creation of BDS trees without BB Max Reitz
2015-02-09 18:17   ` Eric Blake
2015-02-09 18:29     ` Max Reitz
2015-03-04 13:39   ` Kevin Wolf
2015-03-04 14:04     ` Max Reitz
2015-03-04 14:15       ` Kevin Wolf
2015-03-04 14:23         ` Max Reitz
2015-03-04 21:44     ` Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 02/37] iotests: Only create BB if necessary Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 03/37] hw/block/fdc: Implement tray status Max Reitz
2015-02-09 18:23   ` Eric Blake
2015-03-04 14:00   ` Kevin Wolf
2015-03-04 14:07     ` Max Reitz
2015-03-04 22:06     ` Max Reitz
2015-03-05 10:11       ` Kevin Wolf
2015-03-16 13:36         ` Max Reitz
2015-03-16 15:47           ` Markus Armbruster
2015-03-16 15:48             ` Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 04/37] hw/usb-storage: Check whether BB is inserted Max Reitz
2015-03-04 14:02   ` Kevin Wolf
2015-03-04 14:07     ` Max Reitz
2015-03-04 14:20       ` Kevin Wolf
2015-03-04 14:24         ` Max Reitz
2015-03-04 14:39           ` Kevin Wolf
2015-03-04 14:41             ` Max Reitz
2015-03-04 14:52               ` Max Reitz
2015-03-04 14:53               ` Kevin Wolf
2015-03-04 14:58                 ` Max Reitz
2015-03-04 22:06     ` Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 05/37] block: Fix BB AIOCB AioContext without BDS Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 06/37] block: Make bdrv_is_inserted() return a bool Max Reitz
2015-02-09 18:29   ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 07/37] block: Add blk_is_available() Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 08/37] block: Make bdrv_is_inserted() recursive Max Reitz
2015-02-09 19:16   ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 09/37] block/quorum: Implement bdrv_is_inserted() Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 10/37] block: Move guest_block_size into BlockBackend Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 11/37] block: Remove wr_highest_sector from BlockAcctStats Max Reitz
2015-02-09 19:20   ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 12/37] block: Move BlockAcctStats into BlockBackend Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 13/37] block: Move I/O status and error actions into BB Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 14/37] block: Add BlockBackendRootState Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 15/37] block: Make some BB functions fall back to BBRS Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 16/37] block: Fail requests to empty BlockBackend Max Reitz
2015-02-25 18:18   ` Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 17/37] block: Prepare remaining BB functions for NULL BDS Max Reitz
2015-02-09 20:47   ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 18/37] blockdev: Use BB for blockdev-backup transaction Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 19/37] block: Add blk_insert_bs() Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 20/37] block: Prepare for NULL BDS Max Reitz
2015-02-09 21:21   ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 21/37] blockdev: Do not create BDS for empty drive Max Reitz
2015-02-09 21:32   ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 22/37] blockdev: Pull out blockdev option extraction Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 23/37] blockdev: Allow more options for BB-less BDS tree Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 24/37] block: Add blk_remove_bs() Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 25/37] blockdev: Add blockdev-open-tray Max Reitz
2015-02-09 22:01   ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 26/37] blockdev: Add blockdev-close-tray Max Reitz
2015-02-09 22:18   ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 27/37] blockdev: Add blockdev-remove-medium Max Reitz
2015-02-09 22:21   ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 28/37] blockdev: Add blockdev-insert-medium Max Reitz
2015-02-09 22:23   ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 29/37] blockdev: Implement eject with basic operations Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 30/37] blockdev: Implement change " Max Reitz
2015-02-09 22:28   ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 31/37] block: Inquire tray state before tray-moved events Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 32/37] qmp: Introduce blockdev-change-medium Max Reitz
2015-02-09 23:09   ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 33/37] hmp: Use blockdev-change-medium for change command Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 34/37] blockdev: read-only-mode for blockdev-change-medium Max Reitz
2015-02-09 23:15   ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 35/37] hmp: Add read-only-mode option to change command Max Reitz
2015-02-09 23:17   ` Eric Blake
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 36/37] iotests: More options for VM.add_drive() Max Reitz
2015-02-09 17:11 ` [Qemu-devel] [PATCH v2 37/37] iotests: Add test for change-related QMP commands Max Reitz
2015-02-10  0:06   ` Eric Blake
2015-02-10 20:37     ` Max Reitz

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.