All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media
@ 2015-07-20 17:45 Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 01/38] block: Remove host floppy support Max Reitz
                   ` (38 more replies)
  0 siblings, 39 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

First of all: Thank you, Eric and Berto, for reviewing v3! And thank
you, Fam, for at least having a peek at it and being confident enough to
base a series of your own on it. :-)

This series reworks a lot regarding BlockBackend and media. Basically,
it 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.


Quick and early summary for the v4 changes:
- Rebase on master (most changes due to the new throttle groups)
- Addressed comments for v3
- Fixed a bug: Exchanging media should always be possible for BBs
  without an attached device model (it wasn't in v3)


Justification for each of the patches and their order:

-- Preparation before _is_inserted() patches --
 1: Patch 9 will not take care not to break host floppy support, so that
    support needs to be removed first.
 2: Needed for patch 3. Patch 24 is a follow-up after BDS-less BBs are
    allowed.
 3: bdrv_close_all() is broken ("block: Rework bdrv_close_all()"). Patch
    6 will break iotest 071 (actually, just make the problem apparent).
    So this patch is required to work around the issue.
    (with "the issue" being that bdrv_close_all() does not unref() the
    BDSs it is closing, but just force-closes everything, even if the
    BDS may still be in use somewhere)

-- _is_inserted() patches --
 4: General clean-up work, nice to have before patch 6 (and goes in tune
    with patch 5).
 5: Using the same BB as a guest device means that the data read from
    there should be exactly the same. Opening the guest tray should
    therefore result in no data being readable. This is what we then
    need this function for.
 6: General clean-up work (in the _is_inserted() area).
 7: General clean-up work (in the _is_inserted() area).
 8: General clean-up work (also regarding _is_inserted()).
 9: Required so inserting a floppy will not result in the tray being
    reported as closed (you need to "push in" the floppy first, using
    blockdev-close-tray). It's here in the "_is_inserted() patches area"
    because I feel like that's a very related topic.

-- Support for BDS-less BBs --
10: Preparation for BDS-less BBs
11: Preparation for BDS-less BBs
12: Preparation for BDS-less BBs (BB properties should be in the BB, and
    not in the root BDS)
13: Patch 14 removes BlockAcctStats from the BDS, but wr_highest_sector
    is BDS-dependent, so it needs to stay here
14: Preparation for BDS-less BBs (BB properties should be in the BB, and
    not in the root BDS)
15: Preparation for BDS-less BBs (BB properties should be in the BB, and
    not in the root BDS)
16: Preparation for BDS-less BBs (Removing a BDS tree should retain some
    properties for legacy reasons, which must therefore be stored in the
    BB(RS))
17: Preparation for BDS-less BBs
18: Preparation for BDS-less BBs
19: Preparation for BDS-less BBs
20: Ability to add BDS trees to empty BBs ("inserting a medium")
21: Preparation for BDS-less BBs (needs patch 20)
22: One goal of this series, and fixes the "opening tray" event for
    empty drives when shutting down qemu
23: Needed for patch 24
24: Completion of what patch 2 begun
25: Ability to detach BDS trees from BBs

-- "Atomic" QMP tray operations --
26: blockdev-open-tray
27: blockdev-close-tray
28: blockdev-remove-medium
29: blockdev-insert-medium

-- Reimplementation of change/eject --
30: eject
31: change
32: Clean-up patch

-- New QMP blockdev-change-medium command --
33: New QMP command
34: Use for HMP change command
35: Add flag to that command for changing the read-only access mode
    (which was my original intention for this series)
36: Same flag for HMP

-- Tests --
37: Required for patch 38
38: iotests are always nice, so here is one


v4:
- Rebased on current master:
  - Patch 1 (all in code being removed):
    - DEBUG_FLOPPY has been removed
    - floppy_probe_device() was a bit more specific
  - Patch 16 (because of throttle groups): Store the throttle group name
    in the BBRS
  - Patch 21: hmp_drive_del() no longer drains or flushes explicitly
  - Patch 22: Retain throttle group for BB-BDS trees, and save throttle
    group name in the BBRS for empty BBs
  - Patch 23:
    - Read the throttle group name in the new function
    - Use macros for "cache.*"
  - Patch 24: Set the throttle group for BB-less BDS trees
  - Patches 26, 27, 28, 29, 30, 31: Drop QERR_DEVICE_NOT_FOUND
  - Patch 31:
    - Use error_setg() for QERR_INVALID_BLOCK_FORMAT
    - Respect the throttle group name stored in the BBRS
- Patch 23: Fixed potentially unused variable [Fam], and removed the
  empty line at the function's end
- Patches 26, 27, 28, 29, 33: s/2\.3/2\.5/ [Eric]
- Patches 28, 29: Assume the tray to be open if no device model is
  attached to the BB; while blk_dev_has_removable_media() will actually
  return true in this configuration, blk_dev_is_tray_open() will return
  false. But without a device, there is noone stopping you from
  exchanging the medium, so we can just ignore that.


git-backport-diff against v3:

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/38:[0025] [FC] 'block: Remove host floppy support'
002/38:[----] [--] 'blockdev: Allow creation of BDS trees without BB'
003/38:[----] [--] 'iotests: Only create BB if necessary'
004/38:[----] [--] 'block: Make bdrv_is_inserted() return a bool'
005/38:[----] [--] 'block: Add blk_is_available()'
006/38:[----] [--] 'block: Make bdrv_is_inserted() recursive'
007/38:[----] [--] 'block/quorum: Implement bdrv_is_inserted()'
008/38:[----] [-C] 'block: Invoke change media CB before NULLing drv'
009/38:[----] [--] 'hw/block/fdc: Implement tray status'
010/38:[----] [--] 'hw/usb-storage: Check whether BB is inserted'
011/38:[----] [--] 'block: Fix BB AIOCB AioContext without BDS'
012/38:[----] [-C] 'block: Move guest_block_size into BlockBackend'
013/38:[----] [--] 'block: Remove wr_highest_sector from BlockAcctStats'
014/38:[----] [-C] 'block: Move BlockAcctStats into BlockBackend'
015/38:[----] [-C] 'block: Move I/O status and error actions into BB'
016/38:[0016] [FC] 'block: Add BlockBackendRootState'
017/38:[----] [--] 'block: Make some BB functions fall back to BBRS'
018/38:[----] [--] 'block: Fail requests to empty BlockBackend'
019/38:[----] [--] 'block: Prepare remaining BB functions for NULL BDS'
020/38:[----] [--] 'block: Add blk_insert_bs()'
021/38:[0002] [FC] 'block: Prepare for NULL BDS'
022/38:[0016] [FC] 'blockdev: Do not create BDS for empty drive'
023/38:[0028] [FC] 'blockdev: Pull out blockdev option extraction'
024/38:[0008] [FC] 'blockdev: Allow more options for BB-less BDS tree'
025/38:[----] [--] 'block: Add blk_remove_bs()'
026/38:[0005] [FC] 'blockdev: Add blockdev-open-tray'
027/38:[0005] [FC] 'blockdev: Add blockdev-close-tray'
028/38:[0013] [FC] 'blockdev: Add blockdev-remove-medium'
029/38:[0013] [FC] 'blockdev: Add blockdev-insert-medium'
030/38:[0003] [FC] 'blockdev: Implement eject with basic operations'
031/38:[0010] [FC] 'blockdev: Implement change with basic operations'
032/38:[----] [--] 'block: Inquire tray state before tray-moved events'
033/38:[0002] [FC] 'qmp: Introduce blockdev-change-medium'
034/38:[----] [--] 'hmp: Use blockdev-change-medium for change command'
035/38:[----] [-C] 'blockdev: read-only-mode for blockdev-change-medium'
036/38:[----] [-C] 'hmp: Add read-only-mode option to change command'
037/38:[----] [--] 'iotests: More options for VM.add_drive()'
038/38:[----] [-C] 'iotests: Add test for change-related QMP commands'


Max Reitz (38):
  block: Remove host floppy support
  blockdev: Allow creation of BDS trees without BB
  iotests: Only create BB if necessary
  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: Invoke change media CB before NULLing drv
  hw/block/fdc: Implement tray status
  hw/usb-storage: Check whether BB is inserted
  block: Fix BB AIOCB AioContext without BDS
  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
  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                        | 169 +-------
 block/accounting.c             |   8 -
 block/backup.c                 |  17 +-
 block/block-backend.c          | 387 +++++++++++++++--
 block/commit.c                 |   3 +-
 block/io.c                     |  10 +-
 block/mirror.c                 |  17 +-
 block/qapi.c                   |  36 +-
 block/quorum.c                 |  16 +
 block/raw-posix.c              | 225 +---------
 block/raw_bsd.c                |   2 +-
 block/stream.c                 |   3 +-
 blockdev.c                     | 920 +++++++++++++++++++++++++++++------------
 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           |  30 +-
 include/block/accounting.h     |   3 -
 include/block/block.h          |  16 +-
 include/block/block_int.h      |  25 +-
 include/qemu/typedefs.h        |   1 +
 include/sysemu/block-backend.h |  14 +-
 include/sysemu/blockdev.h      |   2 -
 migration/block.c              |   5 +
 monitor.c                      |   4 +
 qapi-schema.json               |   6 +-
 qapi/block-core.json           | 138 ++++++-
 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         | 638 ++++++++++++++++++++++++++++
 tests/qemu-iotests/118.out     |   5 +
 tests/qemu-iotests/group       |   1 +
 tests/qemu-iotests/iotests.py  |   9 +-
 43 files changed, 2317 insertions(+), 924 deletions(-)
 create mode 100755 tests/qemu-iotests/118
 create mode 100644 tests/qemu-iotests/118.out

-- 
2.4.6

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

* [Qemu-devel] [PATCH v4 01/38] block: Remove host floppy support
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-09-07 15:59   ` Kevin Wolf
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 02/38] blockdev: Allow creation of BDS trees without BB Max Reitz
                   ` (37 subsequent siblings)
  38 siblings, 1 reply; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

It has been deprecated as of 2.3, so we can now remove it.

Signed-off-by: Max Reitz <mreitz@redhat.com>
---
 block/raw-posix.c    | 217 ++-------------------------------------------------
 qapi/block-core.json |   9 +--
 2 files changed, 11 insertions(+), 215 deletions(-)

diff --git a/block/raw-posix.c b/block/raw-posix.c
index 855febe..83d7054 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -127,11 +127,6 @@ do { \
 
 #define FTYPE_FILE   0
 #define FTYPE_CD     1
-#define FTYPE_FD     2
-
-/* if the FD is not accessed during that time (in ns), we try to
-   reopen it to see if the disk has been changed */
-#define FD_OPEN_TIMEOUT (1000000000)
 
 #define MAX_BLOCKSIZE	4096
 
@@ -141,13 +136,6 @@ typedef struct BDRVRawState {
     int open_flags;
     size_t buf_align;
 
-#if defined(__linux__)
-    /* linux floppy specific */
-    int64_t fd_open_time;
-    int64_t fd_error_time;
-    int fd_got_error;
-    int fd_media_changed;
-#endif
 #ifdef CONFIG_LINUX_AIO
     int use_aio;
     void *aio_ctx;
@@ -626,7 +614,7 @@ static int raw_reopen_prepare(BDRVReopenState *state,
     }
 #endif
 
-    if (s->type == FTYPE_FD || s->type == FTYPE_CD) {
+    if (s->type == FTYPE_CD) {
         raw_s->open_flags |= O_NONBLOCK;
     }
 
@@ -2172,47 +2160,6 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
 }
 
 #if defined(__linux__)
-/* Note: we do not have a reliable method to detect if the floppy is
-   present. The current method is to try to open the floppy at every
-   I/O and to keep it opened during a few hundreds of ms. */
-static int fd_open(BlockDriverState *bs)
-{
-    BDRVRawState *s = bs->opaque;
-    int last_media_present;
-
-    if (s->type != FTYPE_FD)
-        return 0;
-    last_media_present = (s->fd >= 0);
-    if (s->fd >= 0 &&
-        (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
-        qemu_close(s->fd);
-        s->fd = -1;
-        DPRINTF("Floppy closed\n");
-    }
-    if (s->fd < 0) {
-        if (s->fd_got_error &&
-            (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - s->fd_error_time) < FD_OPEN_TIMEOUT) {
-            DPRINTF("No floppy (open delayed)\n");
-            return -EIO;
-        }
-        s->fd = qemu_open(bs->filename, s->open_flags & ~O_NONBLOCK);
-        if (s->fd < 0) {
-            s->fd_error_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
-            s->fd_got_error = 1;
-            if (last_media_present)
-                s->fd_media_changed = 1;
-            DPRINTF("No floppy\n");
-            return -EIO;
-        }
-        DPRINTF("Floppy opened\n");
-    }
-    if (!last_media_present)
-        s->fd_media_changed = 1;
-    s->fd_open_time = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
-    s->fd_got_error = 0;
-    return 0;
-}
-
 static int hdev_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
 {
     BDRVRawState *s = bs->opaque;
@@ -2241,8 +2188,9 @@ static BlockAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
     pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
     return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
 }
+#endif /* linux */
 
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 static int fd_open(BlockDriverState *bs)
 {
     BDRVRawState *s = bs->opaque;
@@ -2252,7 +2200,7 @@ static int fd_open(BlockDriverState *bs)
         return 0;
     return -EIO;
 }
-#else /* !linux && !FreeBSD */
+#else /* !FreeBSD */
 
 static int fd_open(BlockDriverState *bs)
 {
@@ -2303,14 +2251,13 @@ static int hdev_create(const char *filename, QemuOpts *opts,
     int64_t total_size = 0;
     bool has_prefix;
 
-    /* This function is used by all three protocol block drivers and therefore
-     * any of these three prefixes may be given.
+    /* This function is used by both protocol block drivers and therefore either
+     * of these prefixes may be given.
      * The return value has to be stored somewhere, otherwise this is an error
      * due to -Werror=unused-value. */
     has_prefix =
         strstart(filename, "host_device:", &filename) ||
-        strstart(filename, "host_cdrom:" , &filename) ||
-        strstart(filename, "host_floppy:", &filename);
+        strstart(filename, "host_cdrom:" , &filename);
 
     (void)has_prefix;
 
@@ -2384,155 +2331,6 @@ static BlockDriver bdrv_host_device = {
 #endif
 };
 
-#ifdef __linux__
-static void floppy_parse_filename(const char *filename, QDict *options,
-                                  Error **errp)
-{
-    /* The prefix is optional, just as for "file". */
-    strstart(filename, "host_floppy:", &filename);
-
-    qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
-}
-
-static int floppy_open(BlockDriverState *bs, QDict *options, int flags,
-                       Error **errp)
-{
-    BDRVRawState *s = bs->opaque;
-    Error *local_err = NULL;
-    int ret;
-
-    s->type = FTYPE_FD;
-
-    /* open will not fail even if no floppy is inserted, so add O_NONBLOCK */
-    ret = raw_open_common(bs, options, flags, O_NONBLOCK, &local_err);
-    if (ret) {
-        if (local_err) {
-            error_propagate(errp, local_err);
-        }
-        return ret;
-    }
-
-    /* close fd so that we can reopen it as needed */
-    qemu_close(s->fd);
-    s->fd = -1;
-    s->fd_media_changed = 1;
-
-    error_report("Host floppy pass-through is deprecated");
-    error_printf("Support for it will be removed in a future release.\n");
-    return 0;
-}
-
-static int floppy_probe_device(const char *filename)
-{
-    int fd, ret;
-    int prio = 0;
-    struct floppy_struct fdparam;
-    struct stat st;
-
-    if (strstart(filename, "/dev/fd", NULL) &&
-        !strstart(filename, "/dev/fdset/", NULL) &&
-        !strstart(filename, "/dev/fd/", NULL)) {
-        prio = 50;
-    }
-
-    fd = qemu_open(filename, O_RDONLY | O_NONBLOCK);
-    if (fd < 0) {
-        goto out;
-    }
-    ret = fstat(fd, &st);
-    if (ret == -1 || !S_ISBLK(st.st_mode)) {
-        goto outc;
-    }
-
-    /* Attempt to detect via a floppy specific ioctl */
-    ret = ioctl(fd, FDGETPRM, &fdparam);
-    if (ret >= 0)
-        prio = 100;
-
-outc:
-    qemu_close(fd);
-out:
-    return prio;
-}
-
-
-static int floppy_is_inserted(BlockDriverState *bs)
-{
-    return fd_open(bs) >= 0;
-}
-
-static int floppy_media_changed(BlockDriverState *bs)
-{
-    BDRVRawState *s = bs->opaque;
-    int ret;
-
-    /*
-     * XXX: we do not have a true media changed indication.
-     * It does not work if the floppy is changed without trying to read it.
-     */
-    fd_open(bs);
-    ret = s->fd_media_changed;
-    s->fd_media_changed = 0;
-    DPRINTF("Floppy changed=%d\n", ret);
-    return ret;
-}
-
-static void floppy_eject(BlockDriverState *bs, bool eject_flag)
-{
-    BDRVRawState *s = bs->opaque;
-    int fd;
-
-    if (s->fd >= 0) {
-        qemu_close(s->fd);
-        s->fd = -1;
-    }
-    fd = qemu_open(bs->filename, s->open_flags | O_NONBLOCK);
-    if (fd >= 0) {
-        if (ioctl(fd, FDEJECT, 0) < 0)
-            perror("FDEJECT");
-        qemu_close(fd);
-    }
-}
-
-static BlockDriver bdrv_host_floppy = {
-    .format_name        = "host_floppy",
-    .protocol_name      = "host_floppy",
-    .instance_size      = sizeof(BDRVRawState),
-    .bdrv_needs_filename = true,
-    .bdrv_probe_device	= floppy_probe_device,
-    .bdrv_parse_filename = floppy_parse_filename,
-    .bdrv_file_open     = floppy_open,
-    .bdrv_close         = raw_close,
-    .bdrv_reopen_prepare = raw_reopen_prepare,
-    .bdrv_reopen_commit  = raw_reopen_commit,
-    .bdrv_reopen_abort   = raw_reopen_abort,
-    .bdrv_create         = hdev_create,
-    .create_opts         = &raw_create_opts,
-
-    .bdrv_aio_readv     = raw_aio_readv,
-    .bdrv_aio_writev    = raw_aio_writev,
-    .bdrv_aio_flush	= raw_aio_flush,
-    .bdrv_refresh_limits = raw_refresh_limits,
-    .bdrv_io_plug = raw_aio_plug,
-    .bdrv_io_unplug = raw_aio_unplug,
-    .bdrv_flush_io_queue = raw_aio_flush_io_queue,
-
-    .bdrv_truncate      = raw_truncate,
-    .bdrv_getlength      = raw_getlength,
-    .has_variable_length = true,
-    .bdrv_get_allocated_file_size
-                        = raw_get_allocated_file_size,
-
-    .bdrv_detach_aio_context = raw_detach_aio_context,
-    .bdrv_attach_aio_context = raw_attach_aio_context,
-
-    /* removable device support */
-    .bdrv_is_inserted   = floppy_is_inserted,
-    .bdrv_media_changed = floppy_media_changed,
-    .bdrv_eject         = floppy_eject,
-};
-#endif
-
 #if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 static void cdrom_parse_filename(const char *filename, QDict *options,
                                  Error **errp)
@@ -2810,7 +2608,6 @@ static void bdrv_file_init(void)
     bdrv_register(&bdrv_file);
     bdrv_register(&bdrv_host_device);
 #ifdef __linux__
-    bdrv_register(&bdrv_host_floppy);
     bdrv_register(&bdrv_host_cdrom);
 #endif
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 7b2efb8..133fa38 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -215,10 +215,11 @@
 # @drv: the name of the block format used to open the backing device. As of
 #       0.14.0 this can be: 'blkdebug', 'bochs', 'cloop', 'cow', 'dmg',
 #       'file', 'file', 'ftp', 'ftps', 'host_cdrom', 'host_device',
-#       'host_floppy', 'http', 'https', 'nbd', 'parallels', 'qcow',
+#       'http', 'https', 'nbd', 'parallels', 'qcow',
 #       'qcow2', 'raw', 'tftp', 'vdi', 'vmdk', 'vpc', 'vvfat'
 #       2.2: 'archipelago' added, 'cow' dropped
 #       2.3: 'host_floppy' deprecated
+#       2.4: 'host_floppy' dropped
 #
 # @backing_file: #optional the name of the backing file (for copy-on-write)
 #
@@ -1373,15 +1374,14 @@
 #
 # Drivers that are supported in block device operations.
 #
-# @host_device, @host_cdrom, @host_floppy: Since 2.1
-# @host_floppy: deprecated since 2.3
+# @host_device, @host_cdrom: Since 2.1
 #
 # Since: 2.0
 ##
 { 'enum': 'BlockdevDriver',
   'data': [ 'archipelago', 'blkdebug', 'blkverify', 'bochs', 'cloop',
             'dmg', 'file', 'ftp', 'ftps', 'host_cdrom', 'host_device',
-            'host_floppy', 'http', 'https', 'null-aio', 'null-co', 'parallels',
+            'http', 'https', 'null-aio', 'null-co', 'parallels',
             'qcow', 'qcow2', 'qed', 'quorum', 'raw', 'tftp', 'vdi', 'vhdx',
             'vmdk', 'vpc', 'vvfat' ] }
 
@@ -1811,7 +1811,6 @@
 # TODO gluster: Wait for structured options
       'host_cdrom': 'BlockdevOptionsFile',
       'host_device':'BlockdevOptionsFile',
-      'host_floppy':'BlockdevOptionsFile',
       'http':       'BlockdevOptionsFile',
       'https':      'BlockdevOptionsFile',
 # TODO iscsi: Wait for structured options
-- 
2.4.6

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

* [Qemu-devel] [PATCH v4 02/38] blockdev: Allow creation of BDS trees without BB
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 01/38] block: Remove host floppy support Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-09-07 16:12   ` Kevin Wolf
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 03/38] iotests: Only create BB if necessary Max Reitz
                   ` (36 subsequent siblings)
  38 siblings, 1 reply; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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.

Many BDS options which are not parsed by bdrv_open() (like caching)
cannot be specified for these BB-less BDS trees yet. A future patch will
remove this limitation.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.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 62a4586..644a01c 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3042,17 +3042,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().
@@ -3080,14 +3075,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 133fa38..bc12934 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1393,9 +1393,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)
@@ -1854,7 +1857,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.
 #
 # This command is still a work in progress.  It doesn't support all
 # block drivers, it lacks a matching blockdev-del, and more.  Stay
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 c71bb3a..354e812 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.4.6

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

* [Qemu-devel] [PATCH v4 03/38] iotests: Only create BB if necessary
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 01/38] block: Remove host floppy support Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 02/38] blockdev: Allow creation of BDS trees without BB Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-09-07 16:20   ` Kevin Wolf
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 04/38] block: Make bdrv_is_inserted() return a bool Max Reitz
                   ` (35 subsequent siblings)
  38 siblings, 1 reply; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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>
Reviewed-by: Alberto Garcia <berto@igalia.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.4.6

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

* [Qemu-devel] [PATCH v4 04/38] block: Make bdrv_is_inserted() return a bool
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (2 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 03/38] iotests: Only create BB if necessary Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 05/38] block: Add blk_is_available() Max Reitz
                   ` (34 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
---
 block.c                        | 12 +++++++-----
 block/block-backend.c          |  2 +-
 block/raw-posix.c              |  8 +++-----
 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, 15 insertions(+), 15 deletions(-)

diff --git a/block.c b/block.c
index d088ee0..494e08e 100644
--- a/block.c
+++ b/block.c
@@ -3228,14 +3228,16 @@ void bdrv_invalidate_cache_all(Error **errp)
 /**
  * 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 aee8a12..7afd5c0 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -752,7 +752,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 83d7054..bf5d780 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -2386,15 +2386,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)
@@ -2520,7 +2518,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 e3d2d04..d718583 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 37916f7..2eee6c5 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -397,7 +397,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 14ad4c3..f3b3354 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 8fc960f..8f2bf10 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -130,7 +130,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.4.6

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

* [Qemu-devel] [PATCH v4 05/38] block: Add blk_is_available()
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (3 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 04/38] block: Make bdrv_is_inserted() return a bool Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 06/38] block: Make bdrv_is_inserted() recursive Max Reitz
                   ` (33 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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>
Reviewed-by: Alberto Garcia <berto@igalia.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 7afd5c0..c2ac2b9 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -754,7 +754,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 8f2bf10..1e19d1b 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -131,6 +131,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.4.6

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

* [Qemu-devel] [PATCH v4 06/38] block: Make bdrv_is_inserted() recursive
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (4 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 05/38] block: Add blk_is_available() Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-09-07 17:43   ` Kevin Wolf
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 07/38] block/quorum: Implement bdrv_is_inserted() Max Reitz
                   ` (32 subsequent siblings)
  38 siblings, 1 reply; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
---
 block.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/block.c b/block.c
index 494e08e..1d27b6a 100644
--- a/block.c
+++ b/block.c
@@ -3235,10 +3235,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.4.6

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

* [Qemu-devel] [PATCH v4 07/38] block/quorum: Implement bdrv_is_inserted()
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (5 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 06/38] block: Make bdrv_is_inserted() recursive Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-09-07 18:03   ` Kevin Wolf
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 08/38] block: Invoke change media CB before NULLing drv Max Reitz
                   ` (31 subsequent siblings)
  38 siblings, 1 reply; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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>
Reviewed-by: Alberto Garcia <berto@igalia.com>
---
 block/quorum.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/block/quorum.c b/block/quorum.c
index 4e66221..b7a4c09 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -1034,6 +1034,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",
@@ -1057,6 +1071,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.4.6

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

* [Qemu-devel] [PATCH v4 08/38] block: Invoke change media CB before NULLing drv
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (6 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 07/38] block/quorum: Implement bdrv_is_inserted() Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 09/38] hw/block/fdc: Implement tray status Max Reitz
                   ` (30 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

In order to handle host device passthrough, some guest device models
may call blk_is_inserted() to check whether the medium is inserted on
the host, when checking the guest tray status.

This tray status is inquired by blk_dev_change_media_cb(); because
bdrv_is_inserted() (invoked by blk_is_inserted()) always returns 0 for
BDS with drv set to NULL, blk_dev_change_media_cb() should therefore be
called before drv is set to NULL.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
---
 block.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/block.c b/block.c
index 1d27b6a..e08fe5c 100644
--- a/block.c
+++ b/block.c
@@ -1900,6 +1900,10 @@ void bdrv_close(BlockDriverState *bs)
     bdrv_drain(bs); /* in case flush left pending I/O */
     notifier_list_notify(&bs->close_notifiers, bs);
 
+    if (bs->blk) {
+        blk_dev_change_media_cb(bs->blk, false);
+    }
+
     if (bs->drv) {
         BdrvChild *child, *next;
 
@@ -1942,10 +1946,6 @@ void bdrv_close(BlockDriverState *bs)
         }
     }
 
-    if (bs->blk) {
-        blk_dev_change_media_cb(bs->blk, false);
-    }
-
     /*throttling disk I/O limits*/
     if (bs->io_limits_enabled) {
         bdrv_io_limits_disable(bs);
-- 
2.4.6

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

* [Qemu-devel] [PATCH v4 09/38] hw/block/fdc: Implement tray status
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (7 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 08/38] block: Invoke change media CB before NULLing drv Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-09-07 18:13   ` Kevin Wolf
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 10/38] hw/usb-storage: Check whether BB is inserted Max Reitz
                   ` (29 subsequent siblings)
  38 siblings, 1 reply; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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>
Reviewed-by: Eric Blake <eblake@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, 25 insertions(+), 68 deletions(-)

diff --git a/hw/block/fdc.c b/hw/block/fdc.c
index 5e1b67e..5e0f4a0 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,
@@ -692,7 +694,7 @@ static bool fdrive_media_changed_needed(void *opaque)
 {
     FDrive *drive = opaque;
 
-    return (drive->blk != NULL && drive->media_changed != 1);
+    return (drive->media_inserted && drive->media_changed != 1);
 }
 
 static const VMStateDescription vmstate_fdrive_media_changed = {
@@ -2184,12 +2186,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 */
@@ -2217,6 +2228,7 @@ 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);
+            drive->media_inserted = blk_is_inserted(drive->blk);
         }
     }
 }
diff --git a/tests/fdc-test.c b/tests/fdc-test.c
index 416394f..b5a4696 100644
--- a/tests/fdc-test.c
+++ b/tests/fdc-test.c
@@ -304,9 +304,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 6ff41bc..a692c95 100644
--- a/tests/qemu-iotests/067.out
+++ b/tests/qemu-iotests/067.out
@@ -70,7 +70,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"
         },
         {
@@ -132,7 +132,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"
         },
         {
@@ -166,17 +166,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 ===
@@ -248,7 +237,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"
         },
         {
@@ -314,7 +303,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"
         },
         {
@@ -348,17 +337,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 ===
@@ -388,7 +366,7 @@ Testing:
             "device": "floppy0",
             "locked": false,
             "removable": true,
-            "tray_open": false,
+            "tray_open": true,
             "type": "unknown"
         },
         {
@@ -499,7 +477,7 @@ Testing:
             "device": "floppy0",
             "locked": false,
             "removable": true,
-            "tray_open": false,
+            "tray_open": true,
             "type": "unknown"
         },
         {
@@ -533,17 +511,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 ===
@@ -574,7 +541,7 @@ Testing:
             "device": "floppy0",
             "locked": false,
             "removable": true,
-            "tray_open": false,
+            "tray_open": true,
             "type": "unknown"
         },
         {
@@ -685,7 +652,7 @@ Testing:
             "device": "floppy0",
             "locked": false,
             "removable": true,
-            "tray_open": false,
+            "tray_open": true,
             "type": "unknown"
         },
         {
@@ -765,16 +732,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 354e812..0089aa8 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 ===
@@ -61,7 +58,6 @@ You can use 'qemu-img convert' to convert your image to an unencrypted one.
 {"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
@@ -73,7 +69,6 @@ You can use 'qemu-img convert' to convert your image to an unencrypted one.
 {"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 ===
@@ -92,6 +87,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.4.6

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

* [Qemu-devel] [PATCH v4 10/38] hw/usb-storage: Check whether BB is inserted
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (8 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 09/38] hw/block/fdc: Implement tray status Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 11/38] block: Fix BB AIOCB AioContext without BDS Max Reitz
                   ` (28 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

Only call bdrv_add_key() on the BlockDriverState if it is not NULL.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
---
 hw/usb/dev-storage.c | 30 ++++++++++++++++--------------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index 9a4e7dc..597d8fd 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -613,20 +613,22 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
         return;
     }
 
-    bdrv_add_key(blk_bs(blk), NULL, &err);
-    if (err) {
-        if (monitor_cur_is_qmp()) {
-            error_propagate(errp, err);
-            return;
-        }
-        error_free(err);
-        err = NULL;
-        if (cur_mon) {
-            monitor_read_bdrv_key_start(cur_mon, blk_bs(blk),
-                                        usb_msd_password_cb, s);
-            s->dev.auto_attach = 0;
-        } else {
-            autostart = 0;
+    if (blk_bs(blk)) {
+        bdrv_add_key(blk_bs(blk), NULL, &err);
+        if (err) {
+            if (monitor_cur_is_qmp()) {
+                error_propagate(errp, err);
+                return;
+            }
+            error_free(err);
+            err = NULL;
+            if (cur_mon) {
+                monitor_read_bdrv_key_start(cur_mon, blk_bs(blk),
+                                            usb_msd_password_cb, s);
+                s->dev.auto_attach = 0;
+            } else {
+                autostart = 0;
+            }
         }
     }
 
-- 
2.4.6

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

* [Qemu-devel] [PATCH v4 11/38] block: Fix BB AIOCB AioContext without BDS
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (9 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 10/38] hw/usb-storage: Check whether BB is inserted Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 12/38] block: Move guest_block_size into BlockBackend Max Reitz
                   ` (27 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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>
Reviewed-by: Alberto Garcia <berto@igalia.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 c2ac2b9..b45f617 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),
 };
 
@@ -541,6 +545,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);
@@ -814,7 +819,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.4.6

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

* [Qemu-devel] [PATCH v4 12/38] block: Move guest_block_size into BlockBackend
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (10 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 11/38] block: Fix BB AIOCB AioContext without BDS Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 13/38] block: Remove wr_highest_sector from BlockAcctStats Max Reitz
                   ` (26 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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>
Reviewed-by: Alberto Garcia <berto@igalia.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 e08fe5c..41a718b 100644
--- a/block.c
+++ b/block.c
@@ -860,7 +860,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
         goto fail_opts;
     }
 
-    bs->guest_block_size = 512;
     bs->request_alignment = 512;
     bs->zero_beyond_eof = true;
     open_flags = bdrv_open_flags(bs, flags);
@@ -2005,7 +2004,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;
@@ -3288,11 +3286,6 @@ void bdrv_lock_medium(BlockDriverState *bs, bool locked)
     }
 }
 
-void bdrv_set_guest_block_size(BlockDriverState *bs, int align)
-{
-    bs->guest_block_size = align;
-}
-
 BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name)
 {
     BdrvDirtyBitmap *bm;
diff --git a/block/block-backend.c b/block/block-backend.c
index b45f617..6a270f9 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);
 }
 
@@ -789,7 +792,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 2eee6c5..9749730 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -464,7 +464,6 @@ void bdrv_img_create(const char *filename, const char *fmt,
 size_t bdrv_min_mem_align(BlockDriverState *bs);
 /* Returns optimal alignment in bytes for bounce buffer */
 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 f3b3354..b7e1e16 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -412,9 +412,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.4.6

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

* [Qemu-devel] [PATCH v4 13/38] block: Remove wr_highest_sector from BlockAcctStats
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (11 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 12/38] block: Move guest_block_size into BlockBackend Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 14/38] block: Move BlockAcctStats into BlockBackend Max Reitz
                   ` (25 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
---
 block/accounting.c         | 8 --------
 block/io.c                 | 4 +++-
 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/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/io.c b/block/io.c
index d4bc83b..21cc82a 100644
--- a/block/io.c
+++ b/block/io.c
@@ -1141,7 +1141,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/qapi.c b/block/qapi.c
index 2ce5097..d3cbc80 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -350,13 +350,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 b7e1e16..67e05ac 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -403,6 +403,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 ba630b1..df3b116 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2456,8 +2456,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.4.6

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

* [Qemu-devel] [PATCH v4 14/38] block: Move BlockAcctStats into BlockBackend
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (12 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 13/38] block: Remove wr_highest_sector from BlockAcctStats Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 15/38] block: Move I/O status and error actions into BB Max Reitz
                   ` (24 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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>
Reviewed-by: Alberto Garcia <berto@igalia.com>
---
 block.c                   | 11 -----------
 block/block-backend.c     |  5 ++++-
 block/io.c                |  6 +++++-
 block/qapi.c              | 24 ++++++++++++++----------
 include/block/block.h     |  2 --
 include/block/block_int.h |  3 ---
 6 files changed, 23 insertions(+), 28 deletions(-)

diff --git a/block.c b/block.c
index 41a718b..3db1c16 100644
--- a/block.c
+++ b/block.c
@@ -4234,14 +4234,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 6a270f9..7a7a7e3 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 {
@@ -875,7 +878,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/io.c b/block/io.c
index 21cc82a..08b50c0 100644
--- a/block/io.c
+++ b/block/io.c
@@ -23,6 +23,7 @@
  */
 
 #include "trace.h"
+#include "sysemu/block-backend.h"
 #include "block/blockjob.h"
 #include "block/block_int.h"
 #include "block/throttle-groups.h"
@@ -1895,7 +1896,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;
 }
diff --git a/block/qapi.c b/block/qapi.c
index d3cbc80..2d1ef87 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -344,16 +344,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 9749730..32a2b90 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -613,6 +613,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 67e05ac..0376508 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -400,9 +400,6 @@ struct BlockDriverState {
     unsigned       pending_reqs[2];
     QLIST_ENTRY(BlockDriverState) round_robin;
 
-    /* I/O stats (display with "info blockstats"). */
-    BlockAcctStats stats;
-
     /* Offset after the highest byte written to */
     uint64_t wr_highest_offset;
 
-- 
2.4.6

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

* [Qemu-devel] [PATCH v4 15/38] block: Move I/O status and error actions into BB
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (13 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 14/38] block: Move BlockAcctStats into BlockBackend Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 16/38] block: Add BlockBackendRootState Max Reitz
                   ` (23 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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 3db1c16..5e05c72 100644
--- a/block.c
+++ b/block.c
@@ -258,7 +258,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]);
@@ -2022,14 +2021,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
            &bs_src->throttle_timers,
            sizeof(ThrottleTimers));
 
-    /* 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;
 
@@ -2589,82 +2580,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;
@@ -3683,46 +3598,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 965654d..c61e4c3 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -21,6 +21,7 @@
 #include "block/blockjob.h"
 #include "qapi/qmp/qerror.h"
 #include "qemu/ratelimit.h"
+#include "sysemu/block-backend.h"
 
 #define BACKUP_CLUSTER_BITS 16
 #define BACKUP_CLUSTER_SIZE (1 << BACKUP_CLUSTER_BITS)
@@ -208,7 +209,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 = {
@@ -352,8 +355,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);
 
@@ -443,7 +448,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));
@@ -472,7 +479,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_setg(errp, QERR_INVALID_PARAMETER, "on-source-error");
         return;
     }
diff --git a/block/block-backend.c b/block/block-backend.c
index 7a7a7e3..0672ce7 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,
@@ -721,21 +767,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 7312a5b..5ac228b 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -17,6 +17,7 @@
 #include "block/blockjob.h"
 #include "qapi/qmp/qerror.h"
 #include "qemu/ratelimit.h"
+#include "sysemu/block-backend.h"
 
 enum {
     /*
@@ -213,7 +214,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 323f747..19f8fe3 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 "qapi/qmp/qerror.h"
 #include "qemu/ratelimit.h"
 #include "qemu/bitmap.h"
@@ -591,7 +592,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;
@@ -613,7 +616,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)
@@ -697,7 +702,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_setg(errp, QERR_INVALID_PARAMETER, "on-source-error");
         return;
     }
@@ -733,8 +738,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 2d1ef87..f295692 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -301,9 +301,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 ab0bd05..a0b090d 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -16,6 +16,7 @@
 #include "block/blockjob.h"
 #include "qapi/qmp/qerror.h"
 #include "qemu/ratelimit.h"
+#include "sysemu/block-backend.h"
 
 enum {
     /*
@@ -250,7 +251,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_setg(errp, QERR_INVALID_PARAMETER, "on-error");
         return;
     }
diff --git a/blockdev.c b/blockdev.c
index 644a01c..7da8c45 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -549,7 +549,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)) {
@@ -2177,8 +2177,8 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict)
     if (blk_get_attached_dev(blk)) {
         blk_hide_on_behalf_of_hmp_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 62bb906..ca4be94 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/qerror.h"
 #include "qapi/qmp/qjson.h"
 #include "block/coroutine.h"
@@ -353,8 +354,8 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs,
         job->user_paused = true;
         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 32a2b90..92c6ab2 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -172,11 +172,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);
@@ -387,12 +382,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 0376508..bd35570 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -415,12 +415,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 1e19d1b..eafcef0 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_hmp_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);
@@ -120,6 +125,8 @@ int blk_flush(BlockBackend *blk);
 int blk_flush_all(void);
 void blk_drain(BlockBackend *blk);
 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 403805a..f3e7ba2 100644
--- a/qmp.c
+++ b/qmp.c
@@ -24,6 +24,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/qerror.h"
 #include "qapi/qmp/qobject.h"
@@ -164,6 +165,7 @@ SpiceInfo *qmp_query_spice(Error **errp)
 void qmp_cont(Error **errp)
 {
     Error *local_err = NULL;
+    BlockBackend *blk;
     BlockDriverState *bs;
 
     if (runstate_needs_reset()) {
@@ -173,8 +175,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.4.6

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

* [Qemu-devel] [PATCH v4 16/38] block: Add BlockBackendRootState
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (14 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 15/38] block: Move I/O status and error actions into BB Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-09-11 23:20   ` Eric Blake
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 17/38] block: Make some BB functions fall back to BBRS Max Reitz
                   ` (22 subsequent siblings)
  38 siblings, 1 reply; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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>
---
 block/block-backend.c          | 37 +++++++++++++++++++++++++++++++++++++
 include/block/block_int.h      | 10 ++++++++++
 include/qemu/typedefs.h        |  1 +
 include/sysemu/block-backend.h |  2 ++
 4 files changed, 50 insertions(+)

diff --git a/block/block-backend.c b/block/block-backend.c
index 0672ce7..b4a158d 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -13,6 +13,7 @@
 #include "sysemu/block-backend.h"
 #include "block/block_int.h"
 #include "block/blockjob.h"
+#include "block/throttle-groups.h"
 #include "sysemu/blockdev.h"
 #include "sysemu/sysemu.h"
 #include "qapi-event.h"
@@ -37,6 +38,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;
 
@@ -161,6 +166,7 @@ static void blk_delete(BlockBackend *blk)
         bdrv_unref(blk->bs);
         blk->bs = NULL;
     }
+    g_free(blk->root_state.throttle_group_name);
     /* Avoid double-remove after blk_hide_on_behalf_of_hmp_drive_del() */
     if (blk->name[0]) {
         QTAILQ_REMOVE(&blk_backends, blk, link);
@@ -1050,3 +1056,34 @@ int blk_probe_geometry(BlockBackend *blk, HDGeometry *geo)
 {
     return bdrv_probe_geometry(blk->bs, geo);
 }
+
+/*
+ * 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;
+
+    g_free(blk->root_state.throttle_group_name);
+    if (blk->bs->throttle_state) {
+        throttle_get_config(blk->bs->throttle_state,
+                            &blk->root_state.throttle_config);
+        blk->root_state.throttle_group_name =
+            g_strdup(throttle_group_get_name(blk->bs));
+    } else {
+        blk->root_state.throttle_config = (ThrottleConfig){};
+        blk->root_state.throttle_group_name = NULL;
+    }
+}
+
+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 bd35570..ca1eefa 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -449,6 +449,16 @@ struct BlockDriverState {
     NotifierWithReturn write_threshold_notifier;
 };
 
+struct BlockBackendRootState {
+    int open_flags;
+    bool read_only;
+    BlockdevDetectZeroesOptions detect_zeroes;
+
+    bool io_limits_enabled;
+    ThrottleConfig throttle_config;
+    char *throttle_group_name;
+};
+
 
 /* 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 6fdcbcd..413ac6e 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 eafcef0..52e35a1 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -163,6 +163,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.4.6

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

* [Qemu-devel] [PATCH v4 17/38] block: Make some BB functions fall back to BBRS
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (15 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 16/38] block: Add BlockBackendRootState Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 18/38] block: Fail requests to empty BlockBackend Max Reitz
                   ` (21 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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 b4a158d..6afe200 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -852,7 +852,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)
@@ -897,7 +901,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.4.6

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

* [Qemu-devel] [PATCH v4 18/38] block: Fail requests to empty BlockBackend
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (16 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 17/38] block: Make some BB functions fall back to BBRS Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 19/38] block: Prepare remaining BB functions for NULL BDS Max Reitz
                   ` (20 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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 | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 54 insertions(+), 1 deletion(-)

diff --git a/block/block-backend.c b/block/block-backend.c
index 6afe200..b3ada37 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -509,7 +509,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;
     }
 
@@ -648,6 +648,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);
 }
 
@@ -658,6 +662,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);
 }
 
@@ -688,6 +696,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);
 }
 
@@ -729,12 +741,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);
 }
 
@@ -750,11 +770,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);
 }
 
@@ -876,6 +904,11 @@ void blk_set_enable_write_cache(BlockBackend *blk, bool wce)
 
 void blk_invalidate_cache(BlockBackend *blk, Error **errp)
 {
+    if (!blk->bs) {
+        error_setg(errp, "Device '%s' has no medium", blk->name);
+        return;
+    }
+
     bdrv_invalidate_cache(blk->bs, errp);
 }
 
@@ -1031,6 +1064,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);
 }
 
@@ -1047,21 +1084,37 @@ 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);
 }
 
 int blk_probe_blocksizes(BlockBackend *blk, BlockSizes *bsz)
 {
+    if (!blk_is_available(blk)) {
+        return -ENOMEDIUM;
+    }
+
     return bdrv_probe_blocksizes(blk->bs, bsz);
 }
 
 int blk_probe_geometry(BlockBackend *blk, HDGeometry *geo)
 {
+    if (!blk_is_available(blk)) {
+        return -ENOMEDIUM;
+    }
+
     return bdrv_probe_geometry(blk->bs, geo);
 }
 
-- 
2.4.6

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

* [Qemu-devel] [PATCH v4 19/38] block: Prepare remaining BB functions for NULL BDS
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (17 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 18/38] block: Fail requests to empty BlockBackend Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 20/38] block: Add blk_insert_bs() Max Reitz
                   ` (19 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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>
Reviewed-by: Eric Blake <eblake@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 b3ada37..99429df 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -657,7 +657,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)
@@ -889,17 +893,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)
@@ -924,12 +938,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)
@@ -943,7 +961,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)
@@ -958,22 +980,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)
@@ -993,15 +1025,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,
@@ -1010,23 +1046,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.4.6

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

* [Qemu-devel] [PATCH v4 20/38] block: Add blk_insert_bs()
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (18 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 19/38] block: Prepare remaining BB functions for NULL BDS Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 21/38] block: Prepare for NULL BDS Max Reitz
                   ` (18 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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>
Reviewed-by: Alberto Garcia <berto@igalia.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 99429df..723a0df 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -314,6 +314,22 @@ void blk_hide_on_behalf_of_hmp_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 52e35a1..9306a52 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_hmp_drive_del(BlockBackend *blk);
 
-- 
2.4.6

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

* [Qemu-devel] [PATCH v4 21/38] block: Prepare for NULL BDS
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (19 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 20/38] block: Add blk_insert_bs() Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 22/38] blockdev: Do not create BDS for empty drive Max Reitz
                   ` (17 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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          | 203 ++++++++++++++++++++++++++++++++++------------------
 hw/block/xen_disk.c |   4 +-
 migration/block.c   |   5 ++
 monitor.c           |   4 ++
 6 files changed, 154 insertions(+), 71 deletions(-)

diff --git a/block.c b/block.c
index 5e05c72..f51005d 100644
--- a/block.c
+++ b/block.c
@@ -2771,6 +2771,11 @@ BlockDriverState *bdrv_lookup_bs(const char *device,
         blk = blk_by_name(device);
 
         if (blk) {
+            if (!blk_bs(blk)) {
+                error_setg(errp, "Device '%s' has no medium", device);
+                return NULL;
+            }
+
             return blk_bs(blk);
         }
     }
diff --git a/block/qapi.c b/block/qapi.c
index f295692..e936ba7 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -306,12 +306,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, errp);
         if (info->inserted == NULL) {
diff --git a/blockdev.c b/blockdev.c
index 7da8c45..7bb6ad0 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -124,14 +124,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;
 }
@@ -229,8 +231,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;
         }
     }
@@ -1038,6 +1040,10 @@ void hmp_commit(Monitor *mon, const QDict *qdict)
             monitor_printf(mon, "Device '%s' not found\n", device);
             return;
         }
+        if (!blk_is_available(blk)) {
+            monitor_printf(mon, "Device '%s' has no medium\n", device);
+            return;
+        }
         ret = bdrv_commit(blk_bs(blk));
     }
     if (ret < 0) {
@@ -1117,7 +1123,9 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
                   "Device '%s' not found", device);
         return NULL;
     }
-    bs = blk_bs(blk);
+
+    aio_context = blk_get_aio_context(blk);
+    aio_context_acquire(aio_context);
 
     if (!has_id) {
         id = NULL;
@@ -1129,11 +1137,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_setg(errp, "Device '%s' 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;
@@ -1307,16 +1318,16 @@ static void internal_snapshot_prepare(BlkTransactionState *common,
                   "Device '%s' not found", device);
         return;
     }
-    bs = blk_bs(blk);
 
     /* 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_setg(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;
@@ -1574,7 +1585,6 @@ 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;
@@ -1588,12 +1598,16 @@ static void drive_backup_prepare(BlkTransactionState *common, Error **errp)
                   "Device '%s' not found", backup->device);
         return;
     }
-    bs = blk_bs(blk);
 
     /* 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_setg(errp, "Device '%s' has no medium", backup->device);
+        return;
+    }
+
     qmp_drive_backup(backup->device, backup->target,
                      backup->has_format, backup->format,
                      backup->sync,
@@ -1608,7 +1622,7 @@ static void drive_backup_prepare(BlkTransactionState *common, Error **errp)
         return;
     }
 
-    state->bs = bs;
+    state->bs = blk_bs(blk);
     state->job = state->bs->job;
 }
 
@@ -1643,8 +1657,7 @@ static void blockdev_backup_prepare(BlkTransactionState *common, Error **errp)
 {
     BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
     BlockdevBackup *backup;
-    BlockDriverState *bs, *target;
-    BlockBackend *blk;
+    BlockBackend *blk, *target;
     Error *local_err = NULL;
 
     assert(common->action->kind == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
@@ -1655,18 +1668,16 @@ static void blockdev_backup_prepare(BlkTransactionState *common, Error **errp)
         error_setg(errp, "Device '%s' not found", backup->device);
         return;
     }
-    bs = blk_bs(blk);
 
-    blk = blk_by_name(backup->target);
-    if (!blk) {
+    target = blk_by_name(backup->target);
+    if (!target) {
         error_setg(errp, "Device '%s' not found", backup->target);
         return;
     }
-    target = blk_bs(blk);
 
     /* 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;
@@ -1684,7 +1695,7 @@ static void blockdev_backup_prepare(BlkTransactionState *common, Error **errp)
         return;
     }
 
-    state->bs = bs;
+    state->bs = blk_bs(blk);
     state->job = state->bs->job;
 }
 
@@ -1822,10 +1833,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)) {
@@ -1843,7 +1854,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);
@@ -1888,18 +1901,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);
 }
@@ -1912,6 +1928,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);
@@ -1921,12 +1938,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_setg(errp, QERR_INVALID_BLOCK_FORMAT, format);
             goto out;
@@ -1939,10 +1957,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);
@@ -1982,7 +2008,15 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
                   "Device '%s' not found", device);
         return;
     }
+
+    aio_context = blk_get_aio_context(blk);
+    aio_context_acquire(aio_context);
+
     bs = blk_bs(blk);
+    if (!bs) {
+        error_setg(errp, "Device '%s' has no medium", device);
+        goto out;
+    }
 
     memset(&cfg, 0, sizeof(cfg));
     cfg.buckets[THROTTLE_BPS_TOTAL].avg = bps;
@@ -2017,12 +2051,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 (throttle_enabled(&cfg)) {
         /* Enable I/O limits if they're not enabled yet, otherwise
          * just update the throttling group. */
@@ -2038,6 +2069,7 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
         bdrv_io_limits_disable(bs);
     }
 
+out:
     aio_context_release(aio_context);
 }
 
@@ -2150,7 +2182,6 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict)
         error_report("Device '%s' not found", id);
         return;
     }
-    bs = blk_bs(blk);
 
     if (!blk_legacy_dinfo(blk)) {
         error_report("Deleting device added with blockdev-add"
@@ -2158,16 +2189,19 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict)
         return;
     }
 
-    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_err(local_err);
         aio_context_release(aio_context);
         return;
     }
 
-    bdrv_close(bs);
+    if (bs) {
+        bdrv_close(bs);
+    }
 
     /* if we have a device attached to this BlockDriverState
      * then we need to make the drive anonymous until the device
@@ -2300,11 +2334,16 @@ void qmp_block_stream(const char *device,
                   "Device '%s' not found", device);
         return;
     }
-    bs = blk_bs(blk);
 
-    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_setg(errp, "Device '%s' has no medium", device);
+        goto out;
+    }
+    bs = blk_bs(blk);
+
     if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_STREAM, errp)) {
         goto out;
     }
@@ -2375,11 +2414,16 @@ void qmp_block_commit(const char *device,
                   "Device '%s' not found", device);
         return;
     }
-    bs = blk_bs(blk);
 
-    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_setg(errp, "Device '%s' has no medium", device);
+        goto out;
+    }
+    bs = blk_bs(blk);
+
     if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_COMMIT_SOURCE, errp)) {
         goto out;
     }
@@ -2485,17 +2529,17 @@ void qmp_drive_backup(const char *device, const char *target,
                   "Device '%s' not found", device);
         return;
     }
-    bs = blk_bs(blk);
 
-    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_setg(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;
@@ -2594,7 +2638,7 @@ void qmp_blockdev_backup(const char *device, const char *target,
                          BlockdevOnError on_target_error,
                          Error **errp)
 {
-    BlockBackend *blk;
+    BlockBackend *blk, *target_blk;
     BlockDriverState *bs;
     BlockDriverState *target_bs;
     Error *local_err = NULL;
@@ -2615,17 +2659,27 @@ void qmp_blockdev_backup(const char *device, const char *target,
         error_setg(errp, "Device '%s' not found", device);
         return;
     }
-    bs = blk_bs(blk);
 
-    aio_context = bdrv_get_aio_context(bs);
+    aio_context = blk_get_aio_context(blk);
     aio_context_acquire(aio_context);
 
-    blk = blk_by_name(target);
-    if (!blk) {
+    if (!blk_is_available(blk)) {
+        error_setg(errp, "Device '%s' has no medium", device);
+        goto out;
+    }
+    bs = blk_bs(blk);
+
+    target_blk = blk_by_name(target);
+    if (!target_blk) {
         error_setg(errp, "Device '%s' not found", target);
         goto out;
     }
-    target_bs = blk_bs(blk);
+
+    if (!blk_is_available(target_blk)) {
+        error_setg(errp, "Device '%s' has no medium", target);
+        goto out;
+    }
+    target_bs = blk_bs(target_blk);
 
     bdrv_ref(target_bs);
     bdrv_set_aio_context(target_bs, aio_context);
@@ -2703,15 +2757,15 @@ void qmp_drive_mirror(const char *device, const char *target,
                   "Device '%s' not found", device);
         return;
     }
-    bs = blk_bs(blk);
 
-    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_setg(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;
@@ -2845,17 +2899,22 @@ static BlockJob *find_block_job(const char *device, AioContext **aio_context,
     BlockBackend *blk;
     BlockDriverState *bs;
 
+    *aio_context = NULL;
+
     blk = blk_by_name(device);
     if (!blk) {
         goto notfound;
     }
-    bs = blk_bs(blk);
 
-    *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;
     }
 
@@ -2864,7 +2923,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;
 }
 
@@ -2971,11 +3033,16 @@ void qmp_change_backing_file(const char *device,
                   "Device '%s' not found", device);
         return;
     }
-    bs = blk_bs(blk);
 
-    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_setg(errp, "Device '%s' 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;
     }
 
diff --git a/migration/block.c b/migration/block.c
index ed865ed..f7bb1e0 100644
--- a/migration/block.c
+++ b/migration/block.c
@@ -808,6 +808,11 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
                 return -EINVAL;
             }
             bs = blk_bs(blk);
+            if (!bs) {
+                fprintf(stderr, "Block device %s has no medium\n",
+                        device_name);
+                return -EINVAL;
+            }
 
             if (bs != bs_prev) {
                 bs_prev = bs;
diff --git a/monitor.c b/monitor.c
index aeea2b5..e18372d 100644
--- a/monitor.c
+++ b/monitor.c
@@ -5320,6 +5320,10 @@ int monitor_read_block_device_key(Monitor *mon, const char *device,
         monitor_printf(mon, "Device not found %s\n", device);
         return -1;
     }
+    if (!blk_bs(blk)) {
+        monitor_printf(mon, "Device '%s' has no medium\n", device);
+        return -1;
+    }
 
     bdrv_add_key(blk_bs(blk), NULL, &err);
     if (err) {
-- 
2.4.6

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

* [Qemu-devel] [PATCH v4 22/38] blockdev: Do not create BDS for empty drive
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (20 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 21/38] block: Prepare for NULL BDS Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 23/38] blockdev: Pull out blockdev option extraction Max Reitz
                   ` (16 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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                 | 76 +++++++++++++++++++++++++++-------------------
 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, 44 insertions(+), 85 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 7bb6ad0..4577e7e 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -508,16 +508,44 @@ 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)) {
+            if (!throttling_group) {
+                throttling_group = blk_name(blk);
+            }
+            blk_rs->io_limits_enabled = true;
+            blk_rs->throttle_config = cfg;
+            blk_rs->throttle_group_name = g_strdup(throttling_group);
+        }
 
         QDECREF(bs_opts);
     } else {
@@ -525,46 +553,30 @@ 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)) {
+            if (!throttling_group) {
+                throttling_group = blk_name(blk);
+            }
+            bdrv_io_limits_enable(bs, throttling_group);
+            bdrv_set_io_limits(bs, &cfg);
+        }
 
-    /* disk I/O throttling */
-    if (throttle_enabled(&cfg)) {
-        if (!throttling_group) {
-            throttling_group = blk_name(blk);
+        if (bdrv_key_required(bs)) {
+            autostart = 0;
         }
-        bdrv_io_limits_enable(bs, throttling_group);
-        bdrv_set_io_limits(bs, &cfg);
     }
 
-    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 a692c95..aff104a 100644
--- a/tests/qemu-iotests/067.out
+++ b/tests/qemu-iotests/067.out
@@ -155,17 +155,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 ===
@@ -326,17 +315,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 ===
@@ -500,17 +478,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 ===
@@ -721,16 +688,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 0089aa8..7d62cd5 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 ===
@@ -57,7 +54,6 @@ You can use 'qemu-img convert' to convert your image to an unencrypted one.
 {"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
@@ -68,7 +64,6 @@ You can use 'qemu-img convert' to convert your image to an unencrypted one.
 {"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 ===
@@ -86,6 +81,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.4.6

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

* [Qemu-devel] [PATCH v4 23/38] blockdev: Pull out blockdev option extraction
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (21 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 22/38] blockdev: Do not create BDS for empty drive Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 24/38] blockdev: Allow more options for BB-less BDS tree Max Reitz
                   ` (15 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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>
---
 blockdev.c | 209 +++++++++++++++++++++++++++++++++----------------------------
 1 file changed, 113 insertions(+), 96 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 4577e7e..2973985 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -344,25 +344,128 @@ 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,
+    const char **throttling_group, Error **errp)
+{
+    const char *discard;
+    Error *local_error = NULL;
+#ifdef CONFIG_LINUX_AIO
+    const char *aio;
+#endif
+
+    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, BDRV_OPT_CACHE_WB, true)) {
+        *bdrv_flags |= BDRV_O_CACHE_WB;
+    }
+    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) {
+        *bdrv_flags |= BDRV_O_NOCACHE;
+    }
+    if (qemu_opt_get_bool(opts, BDRV_OPT_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);
+
+    *throttling_group = qemu_opt_get(opts, "throttling.group");
+
+    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;
-    const char *throttling_group;
+    BlockdevDetectZeroesOptions detect_zeroes =
+        BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;
+    const char *throttling_group = NULL;
 
     /* Check common options by copying from bs_opts to opts, all other options
      * stay in bs_opts for processing by bdrv_open(). */
@@ -387,38 +490,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, BDRV_OPT_CACHE_WB, true)) {
-        bdrv_flags |= BDRV_O_CACHE_WB;
-    }
-    if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) {
-        bdrv_flags |= BDRV_O_NOCACHE;
-    }
-    if (qemu_opt_get_bool(opts, BDRV_OPT_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,
+                                    &throttling_group, &error);
+    if (error) {
+        error_propagate(errp, error);
+        goto early_err;
     }
-#endif
 
     if ((buf = qemu_opt_get(opts, "format")) != NULL) {
         if (is_help_option(buf)) {
@@ -435,43 +513,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);
-
-    throttling_group = qemu_opt_get(opts, "throttling.group");
-
-    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);
@@ -490,40 +531,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;
@@ -535,7 +552,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.4.6

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

* [Qemu-devel] [PATCH v4 24/38] blockdev: Allow more options for BB-less BDS tree
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (22 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 23/38] blockdev: Pull out blockdev option extraction Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 25/38] block: Add blk_remove_bs() Max Reitz
                   ` (14 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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>
---
 blockdev.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 154 insertions(+), 6 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 2973985..44a8c6b 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -606,6 +606,65 @@ 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;
+    const char *throttling_group = NULL;
+    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,
+                                    &throttling_group, &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)) {
+        if (!throttling_group) {
+            throttling_group = bdrv_get_node_name(bs);
+        }
+        bdrv_io_limits_enable(bs, throttling_group);
+        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)
 {
@@ -3180,18 +3239,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;
         }
     }
@@ -3346,6 +3401,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.4.6

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

* [Qemu-devel] [PATCH v4 25/38] block: Add blk_remove_bs()
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (23 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 24/38] blockdev: Allow more options for BB-less BDS tree Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 26/38] blockdev: Add blockdev-open-tray Max Reitz
                   ` (13 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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 723a0df..6353f39 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -314,6 +314,22 @@ void blk_hide_on_behalf_of_hmp_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)
@@ -323,9 +339,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 9306a52..14a6d32 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_hmp_drive_del(BlockBackend *blk);
-- 
2.4.6

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

* [Qemu-devel] [PATCH v4 26/38] blockdev: Add blockdev-open-tray
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (24 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 25/38] block: Add blk_remove_bs() Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 27/38] blockdev: Add blockdev-close-tray Max Reitz
                   ` (12 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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

diff --git a/blockdev.c b/blockdev.c
index 44a8c6b..265b7a9 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2062,6 +2062,55 @@ 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, ERROR_CLASS_DEVICE_NOT_FOUND,
+                  "Device '%s' 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 bc12934..f593245 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1871,6 +1871,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.5
+##
+{ 'command': 'blockdev-open-tray',
+  'data': { 'device': 'str',
+            '*force': 'bool' } }
+
 
 ##
 # @BlockErrorAction
diff --git a/qmp-commands.hx b/qmp-commands.hx
index df3b116..01c5d6e 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3872,6 +3872,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.4.6

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

* [Qemu-devel] [PATCH v4 27/38] blockdev: Add blockdev-close-tray
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (25 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 26/38] blockdev: Add blockdev-open-tray Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 28/38] blockdev: Add blockdev-remove-medium Max Reitz
                   ` (11 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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

diff --git a/blockdev.c b/blockdev.c
index 265b7a9..7af6a71 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2111,6 +2111,29 @@ out:
     }
 }
 
+void qmp_blockdev_close_tray(const char *device, Error **errp)
+{
+    BlockBackend *blk;
+
+    blk = blk_by_name(device);
+    if (!blk) {
+        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+                  "Device '%s' 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 f593245..ad1f018 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1894,6 +1894,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.5
+##
+{ 'command': 'blockdev-close-tray',
+  'data': { 'device': 'str' } }
+
 
 ##
 # @BlockErrorAction
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 01c5d6e..aa7ec30 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3911,6 +3911,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.4.6

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

* [Qemu-devel] [PATCH v4 28/38] blockdev: Add blockdev-remove-medium
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (26 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 27/38] blockdev: Add blockdev-close-tray Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 29/38] blockdev: Add blockdev-insert-medium Max Reitz
                   ` (10 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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

diff --git a/blockdev.c b/blockdev.c
index 7af6a71..481760a 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2134,6 +2134,36 @@ 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;
+    bool has_device;
+
+    blk = blk_by_name(device);
+    if (!blk) {
+        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+                  "Device '%s' not found", device);
+        return;
+    }
+
+    /* For BBs without a device, we can exchange the BDS tree at will */
+    has_device = blk_get_attached_dev(blk);
+
+    if (has_device && !blk_dev_has_removable_media(blk)) {
+        error_setg(errp, "Device '%s' is not removable", device);
+        return;
+    }
+
+    if (has_device && !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 ad1f018..63a83e4 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1910,6 +1910,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.5
+##
+{ 'command': 'blockdev-remove-medium',
+  'data': { 'device': 'str' } }
+
 
 ##
 # @BlockErrorAction
diff --git a/qmp-commands.hx b/qmp-commands.hx
index aa7ec30..ff6c572 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3946,6 +3946,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.4.6

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

* [Qemu-devel] [PATCH v4 29/38] blockdev: Add blockdev-insert-medium
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (27 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 28/38] blockdev: Add blockdev-remove-medium Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-09-08  5:53   ` Wen Congyang
  2015-09-08  9:13   ` Wen Congyang
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 30/38] blockdev: Implement eject with basic operations Max Reitz
                   ` (9 subsequent siblings)
  38 siblings, 2 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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>
---
 blockdev.c           | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 qapi/block-core.json | 17 +++++++++++++++++
 qmp-commands.hx      | 37 +++++++++++++++++++++++++++++++++++++
 3 files changed, 102 insertions(+)

diff --git a/blockdev.c b/blockdev.c
index 481760a..a80d0e2 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2164,6 +2164,54 @@ 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;
+    bool has_device;
+
+    blk = blk_by_name(device);
+    if (!blk) {
+        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+                  "Device '%s' not found", device);
+        return;
+    }
+
+    /* For BBs without a device, we can exchange the BDS tree at will */
+    has_device = blk_get_attached_dev(blk);
+
+    if (has_device && !blk_dev_has_removable_media(blk)) {
+        error_setg(errp, "Device '%s' is not removable", device);
+        return;
+    }
+
+    if (has_device && !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 63a83e4..84c9b23 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1925,6 +1925,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.5
+##
+{ 'command': 'blockdev-insert-medium',
+  'data': { 'device': 'str',
+            'node-name': 'str'} }
+
 
 ##
 # @BlockErrorAction
diff --git a/qmp-commands.hx b/qmp-commands.hx
index ff6c572..b4c34fe 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3991,6 +3991,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.4.6

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

* [Qemu-devel] [PATCH v4 30/38] blockdev: Implement eject with basic operations
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (28 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 29/38] blockdev: Add blockdev-insert-medium Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 31/38] blockdev: Implement change " Max Reitz
                   ` (8 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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

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

diff --git a/blockdev.c b/blockdev.c
index a80d0e2..0a4a761 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1952,16 +1952,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, ERROR_CLASS_DEVICE_NOT_FOUND,
-                  "Device '%s' 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.4.6

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

* [Qemu-devel] [PATCH v4 31/38] blockdev: Implement change with basic operations
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (29 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 30/38] blockdev: Implement eject with basic operations Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 32/38] block: Inquire tray state before tray-moved events Max Reitz
                   ` (7 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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 | 187 ++++++++++++++++++++++++++-----------------------------------
 1 file changed, 78 insertions(+), 109 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 0a4a761..3ea9d8d 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1915,41 +1915,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;
@@ -1987,80 +1952,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, ERROR_CLASS_DEVICE_NOT_FOUND,
-                  "Device '%s' 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_setg(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)
 {
@@ -2211,6 +2102,84 @@ 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, ERROR_CLASS_DEVICE_NOT_FOUND,
+                  "Device '%s' 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_setg(errp, "Invalid block format '%s'", 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, blk_rs->throttle_group_name);
+        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.4.6

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

* [Qemu-devel] [PATCH v4 32/38] block: Inquire tray state before tray-moved events
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (30 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 31/38] blockdev: Implement change " Max Reitz
@ 2015-07-20 17:45 ` Max Reitz
  2015-07-20 17:46 ` [Qemu-devel] [PATCH v4 33/38] qmp: Introduce blockdev-change-medium Max Reitz
                   ` (6 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:45 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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 6353f39..93a2e25 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -422,18 +422,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.4.6

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

* [Qemu-devel] [PATCH v4 33/38] qmp: Introduce blockdev-change-medium
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (31 preceding siblings ...)
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 32/38] block: Inquire tray state before tray-moved events Max Reitz
@ 2015-07-20 17:46 ` Max Reitz
  2015-07-20 17:46 ` [Qemu-devel] [PATCH v4 34/38] hmp: Use blockdev-change-medium for change command Max Reitz
                   ` (5 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:46 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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 3ea9d8d..0f18c92 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2102,8 +2102,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;
@@ -2127,7 +2128,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_setg(errp, "Invalid block format '%s'", format);
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
index 3104150..553b53c 100644
--- a/include/sysemu/blockdev.h
+++ b/include/sysemu/blockdev.h
@@ -63,8 +63,6 @@ DriveInfo *drive_new(QemuOpts *arg, BlockInterfaceType block_default_type);
 
 /* device-hotplug */
 
-void qmp_change_blockdev(const char *device, const char *filename,
-                         const char *format, Error **errp);
 void hmp_commit(Monitor *mon, const QDict *qdict);
 void hmp_drive_del(Monitor *mon, const QDict *qdict);
 #endif
diff --git a/qapi-schema.json b/qapi-schema.json
index a0a45f7..01bcc20 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1809,8 +1809,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 84c9b23..bc56625 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1944,6 +1944,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.5
+##
+{ '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 b4c34fe..ce8516b 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -4090,6 +4090,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 f3e7ba2..55f006c 100644
--- a/qmp.c
+++ b/qmp.c
@@ -413,7 +413,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.4.6

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

* [Qemu-devel] [PATCH v4 34/38] hmp: Use blockdev-change-medium for change command
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (32 preceding siblings ...)
  2015-07-20 17:46 ` [Qemu-devel] [PATCH v4 33/38] qmp: Introduce blockdev-change-medium Max Reitz
@ 2015-07-20 17:46 ` Max Reitz
  2015-07-20 17:46 ` [Qemu-devel] [PATCH v4 35/38] blockdev: read-only-mode for blockdev-change-medium Max Reitz
                   ` (4 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:46 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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 dcc66f1..1a201a9 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1317,22 +1317,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.4.6

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

* [Qemu-devel] [PATCH v4 35/38] blockdev: read-only-mode for blockdev-change-medium
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (33 preceding siblings ...)
  2015-07-20 17:46 ` [Qemu-devel] [PATCH v4 34/38] hmp: Use blockdev-change-medium for change command Max Reitz
@ 2015-07-20 17:46 ` Max Reitz
  2015-07-20 17:46 ` [Qemu-devel] [PATCH v4 36/38] hmp: Add read-only-mode option to change command Max Reitz
                   ` (3 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:46 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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>
Reviewed-by: Eric Blake <eblake@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 0f18c92..77e47da 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2104,6 +2104,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;
@@ -2125,7 +2127,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 1a201a9..a4f3634 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1327,7 +1327,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 bc56625..cb99cad 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1944,6 +1944,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
@@ -1958,12 +1976,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.5
 ##
 { '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 ce8516b..5936b24 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -4091,7 +4091,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,
     },
 
@@ -4107,6 +4107,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:
 
@@ -4118,6 +4120,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 55f006c..3493b3b 100644
--- a/qmp.c
+++ b/qmp.c
@@ -413,7 +413,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.4.6

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

* [Qemu-devel] [PATCH v4 36/38] hmp: Add read-only-mode option to change command
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (34 preceding siblings ...)
  2015-07-20 17:46 ` [Qemu-devel] [PATCH v4 35/38] blockdev: read-only-mode for blockdev-change-medium Max Reitz
@ 2015-07-20 17:46 ` Max Reitz
  2015-07-20 17:46 ` [Qemu-devel] [PATCH v4 37/38] iotests: More options for VM.add_drive() Max Reitz
                   ` (2 subsequent siblings)
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:46 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

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

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@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 d3b7932..b3e1632 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -194,8 +194,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,
     },
@@ -206,7 +206,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
@@ -215,6 +215,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 a4f3634..e503414 100644
--- a/hmp.c
+++ b/hmp.c
@@ -27,6 +27,7 @@
 #include "qapi/opts-visitor.h"
 #include "qapi/qmp/qerror.h"
 #include "qapi/string-output-visitor.h"
+#include "qapi/util.h"
 #include "qapi-visit.h"
 #include "ui/console.h"
 #include "block/qapi.h"
@@ -1315,9 +1316,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) {
@@ -1327,7 +1335,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.4.6

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

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

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 8615b10..09d25db 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -117,13 +117,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.4.6

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

* [Qemu-devel] [PATCH v4 38/38] iotests: Add test for change-related QMP commands
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (36 preceding siblings ...)
  2015-07-20 17:46 ` [Qemu-devel] [PATCH v4 37/38] iotests: More options for VM.add_drive() Max Reitz
@ 2015-07-20 17:46 ` Max Reitz
  2015-09-02 15:02 ` [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Eric Blake
  38 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-07-20 17:46 UTC (permalink / raw)
  To: qemu-block
  Cc: Kevin Wolf, Alberto Garcia, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi, Max Reitz

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 tests/qemu-iotests/118     | 638 +++++++++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/118.out |   5 +
 tests/qemu-iotests/group   |   1 +
 3 files changed, 644 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..915e439
--- /dev/null
+++ b/tests/qemu-iotests/118
@@ -0,0 +1,638 @@
+#!/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 time
+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=False):
+            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
+
+    def wait_for_open(self):
+        timeout = time.clock() + 3
+        while not self.has_opened and time.clock() < timeout:
+            self.process_events()
+        if not self.has_opened:
+            self.fail('Timeout while waiting for the tray to open')
+
+    def wait_for_close(self):
+        timeout = time.clock() + 3
+        while not self.has_closed and time.clock() < timeout:
+            self.process_events()
+        if not self.has_opened:
+            self.fail('Timeout while waiting for the tray to close')
+
+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', {})
+
+        self.wait_for_open()
+        self.wait_for_close()
+
+        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', {})
+
+        self.wait_for_open()
+        self.wait_for_close()
+
+        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', {})
+
+        self.wait_for_open()
+
+        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', {})
+
+        self.wait_for_open()
+
+        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', {})
+
+        self.wait_for_close()
+
+        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', {})
+
+        self.wait_for_open()
+
+        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:
+            self.wait_for_close()
+
+        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', {})
+
+        self.wait_for_open()
+
+        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:
+            self.wait_for_close()
+
+        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', {})
+
+        self.wait_for_open()
+
+        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', {})
+
+        self.wait_for_close()
+
+        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', {})
+
+        self.wait_for_open()
+
+        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', {})
+
+        self.wait_for_close()
+
+        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', {})
+
+        self.wait_for_open()
+
+        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', {})
+
+        self.wait_for_open()
+
+        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', {})
+
+        self.wait_for_open()
+        self.wait_for_close()
+
+        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', {})
+
+        self.wait_for_open()
+        self.wait_for_close()
+
+        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', {})
+
+        self.wait_for_open()
+        self.wait_for_close()
+
+        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', {})
+
+        self.wait_for_open()
+        self.wait_for_close()
+
+        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', {})
+
+        self.wait_for_open()
+        self.wait_for_close()
+
+        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', {})
+
+        self.wait_for_open()
+        self.wait_for_close()
+
+        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', {})
+
+        self.wait_for_open()
+
+        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', {})
+
+        self.wait_for_close()
+
+        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 6206765..a3c4009 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -121,6 +121,7 @@
 114 rw auto quick
 115 rw auto
 116 rw auto quick
+118 rw auto
 119 rw auto quick
 120 rw auto quick
 121 rw auto
-- 
2.4.6

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

* Re: [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media
  2015-07-20 17:45 [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Max Reitz
                   ` (37 preceding siblings ...)
  2015-07-20 17:46 ` [Qemu-devel] [PATCH v4 38/38] iotests: Add test for change-related QMP commands Max Reitz
@ 2015-09-02 15:02 ` Eric Blake
  2015-09-07  5:53   ` Wen Congyang
  38 siblings, 1 reply; 67+ messages in thread
From: Eric Blake @ 2015-09-02 15:02 UTC (permalink / raw)
  To: Max Reitz, qemu-block
  Cc: Kevin Wolf, Alberto Garcia, qemu-devel, Markus Armbruster,
	Stefan Hajnoczi, John Snow

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

On 07/20/2015 11:45 AM, Max Reitz wrote:
> First of all: Thank you, Eric and Berto, for reviewing v3! And thank
> you, Fam, for at least having a peek at it and being confident enough to
> base a series of your own on it. :-)
> 
> This series reworks a lot regarding BlockBackend and media. Basically,
> it 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.

We've obviously missed 2.4; but now that 2.5 is open, are there plans to
get this series in sooner rather than later?  Wen's work on dynamically
adding/deleting children from a quorum would benefit from the ability to
create a BDS without an associated BB, which in turn would help the COLO
work.

-- 
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] 67+ messages in thread

* Re: [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media
  2015-09-02 15:02 ` [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media Eric Blake
@ 2015-09-07  5:53   ` Wen Congyang
  2015-09-07 18:42     ` Max Reitz
  0 siblings, 1 reply; 67+ messages in thread
From: Wen Congyang @ 2015-09-07  5:53 UTC (permalink / raw)
  To: Eric Blake, Max Reitz, qemu-block
  Cc: Kevin Wolf, Alberto Garcia, qemu-devel, Markus Armbruster,
	Stefan Hajnoczi, John Snow

On 09/02/2015 11:02 PM, Eric Blake wrote:
> On 07/20/2015 11:45 AM, Max Reitz wrote:
>> First of all: Thank you, Eric and Berto, for reviewing v3! And thank
>> you, Fam, for at least having a peek at it and being confident enough to
>> base a series of your own on it. :-)
>>
>> This series reworks a lot regarding BlockBackend and media. Basically,
>> it 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.
> 
> We've obviously missed 2.4; but now that 2.5 is open, are there plans to
> get this series in sooner rather than later?  Wen's work on dynamically
> adding/deleting children from a quorum would benefit from the ability to
> create a BDS without an associated BB, which in turn would help the COLO
> work.
> 

This feature is very useful for COLO. COLO needs the following:
1. adding/deleting children from a quorum dynamically
2. allow references for backing files

The BDS without BB only can be created by the monitor command blockdev-add.
How to create it in the command line?

Thanks
Wen Congyang

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

* Re: [Qemu-devel] [PATCH v4 01/38] block: Remove host floppy support
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 01/38] block: Remove host floppy support Max Reitz
@ 2015-09-07 15:59   ` Kevin Wolf
  2015-09-07 16:26     ` Max Reitz
  0 siblings, 1 reply; 67+ messages in thread
From: Kevin Wolf @ 2015-09-07 15:59 UTC (permalink / raw)
  To: Max Reitz
  Cc: Alberto Garcia, qemu-block, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi

Am 20.07.2015 um 19:45 hat Max Reitz geschrieben:
> It has been deprecated as of 2.3, so we can now remove it.
> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>

> @@ -2241,8 +2188,9 @@ static BlockAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
>      pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
>      return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
>  }
> +#endif /* linux */
>  
> -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
> +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
>  static int fd_open(BlockDriverState *bs)
>  {
>      BDRVRawState *s = bs->opaque;
> @@ -2252,7 +2200,7 @@ static int fd_open(BlockDriverState *bs)
>          return 0;
>      return -EIO;
>  }
> -#else /* !linux && !FreeBSD */
> +#else /* !FreeBSD */
>  
>  static int fd_open(BlockDriverState *bs)
>  {

Full context:

    #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
    static int fd_open(BlockDriverState *bs)
    {
        BDRVRawState *s = bs->opaque;

        /* this is just to ensure s->fd is sane (its called by io ops) */
        if (s->fd >= 0)
            return 0;
        return -EIO;
    }
    #else /* !FreeBSD */

    static int fd_open(BlockDriverState *bs)
    {
        return 0;
    }

    #endif /* !linux && !FreeBSD */

First of all, the final comment isn't accurate any more, this branch is
now for Linux, too.

But really the whole #ifdef looks dubious now. It's not clear to me why
we're checking fd >= 0 for FreeBSD at all, using an invalid file
descriptor (most likely -1, which is set explicitly in some places)
should automatically lead to failure. And conversely, I can't see why
doing the same check for non-FreeBSD platforms should hurt.

Ideally, I'd try to get rid of all the fd_open() calls, but failing that
let's use the FreeBSD version universally and get rid of the #ifdef at
least. Or perhaps get rid of the #ifdef in this patch and add another
one that removes fd_open() completely.

> diff --git a/qapi/block-core.json b/qapi/block-core.json
> index 7b2efb8..133fa38 100644
> --- a/qapi/block-core.json
> +++ b/qapi/block-core.json
> @@ -215,10 +215,11 @@
>  # @drv: the name of the block format used to open the backing device. As of
>  #       0.14.0 this can be: 'blkdebug', 'bochs', 'cloop', 'cow', 'dmg',
>  #       'file', 'file', 'ftp', 'ftps', 'host_cdrom', 'host_device',
> -#       'host_floppy', 'http', 'https', 'nbd', 'parallels', 'qcow',
> +#       'http', 'https', 'nbd', 'parallels', 'qcow',
>  #       'qcow2', 'raw', 'tftp', 'vdi', 'vmdk', 'vpc', 'vvfat'
>  #       2.2: 'archipelago' added, 'cow' dropped
>  #       2.3: 'host_floppy' deprecated
> +#       2.4: 'host_floppy' dropped

2.5

Kevin

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

* Re: [Qemu-devel] [PATCH v4 02/38] blockdev: Allow creation of BDS trees without BB
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 02/38] blockdev: Allow creation of BDS trees without BB Max Reitz
@ 2015-09-07 16:12   ` Kevin Wolf
  2015-09-07 16:38     ` Max Reitz
  0 siblings, 1 reply; 67+ messages in thread
From: Kevin Wolf @ 2015-09-07 16:12 UTC (permalink / raw)
  To: Max Reitz
  Cc: Alberto Garcia, qemu-block, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi

Am 20.07.2015 um 19:45 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.

We can probably lift this restriction once Jeff's auto-generated ID
patches are in. However, allowing additional things is easy, so no
objection here.

> Many BDS options which are not parsed by bdrv_open() (like caching)
> cannot be specified for these BB-less BDS trees yet. A future patch will
> remove this limitation.

This makes the command mostly useless, but that's okay. We'll be working
on converting flags to QDict options one by one and then it will start
working.

There is, however, one flag that doesn't correspond to an option or
enable an additional feature that is simply missing until then. That one
worries me a bit: BDRV_O_INCOMING. We should probably include it in this
patch; or maybe better add another patch before this one which moves the
setting of BDRV_O_INCOMING from blockdev_init() to bdrv_open_common().

> Signed-off-by: Max Reitz <mreitz@redhat.com>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> Reviewed-by: Alberto Garcia <berto@igalia.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(-)

Kevin

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

* Re: [Qemu-devel] [PATCH v4 03/38] iotests: Only create BB if necessary
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 03/38] iotests: Only create BB if necessary Max Reitz
@ 2015-09-07 16:20   ` Kevin Wolf
  2015-09-07 16:54     ` Max Reitz
  0 siblings, 1 reply; 67+ messages in thread
From: Kevin Wolf @ 2015-09-07 16:20 UTC (permalink / raw)
  To: Max Reitz
  Cc: Alberto Garcia, qemu-block, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi

Am 20.07.2015 um 19:45 hat Max Reitz geschrieben:
> 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>
> Reviewed-by: Alberto Garcia <berto@igalia.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"
> +        }
> +    }
> +}

Any specific reason why format=raw is translated into driver=file here...

> +{ "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"
> +            }
> +        }
> +    }
> +}

...but into driver=raw,file.driver=file here?

> +{ "execute": "blockdev-add",
> +    "arguments": {
> +        "options": {
>              "driver": "blkverify",
>              "id": "drive0-verify",
>              "test": {

> 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"
> +            }
> +        }
> +    }
> +}

And here $IMGFMT becomes raw (which is equivalent, but...)

> +{ "execute": "blockdev-add",
> +    "arguments": {
> +        "options": {
>              "driver": "quorum",
>              "id": "drive0-quorum",
>              "vote-threshold": 2,

Kevin

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

* Re: [Qemu-devel] [PATCH v4 01/38] block: Remove host floppy support
  2015-09-07 15:59   ` Kevin Wolf
@ 2015-09-07 16:26     ` Max Reitz
  0 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-09-07 16:26 UTC (permalink / raw)
  To: Kevin Wolf
  Cc: Alberto Garcia, qemu-block, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi

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

On 07.09.2015 17:59, Kevin Wolf wrote:
> Am 20.07.2015 um 19:45 hat Max Reitz geschrieben:
>> It has been deprecated as of 2.3, so we can now remove it.
>>
>> Signed-off-by: Max Reitz <mreitz@redhat.com>
> 
>> @@ -2241,8 +2188,9 @@ static BlockAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
>>      pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
>>      return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
>>  }
>> +#endif /* linux */
>>  
>> -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
>> +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
>>  static int fd_open(BlockDriverState *bs)
>>  {
>>      BDRVRawState *s = bs->opaque;
>> @@ -2252,7 +2200,7 @@ static int fd_open(BlockDriverState *bs)
>>          return 0;
>>      return -EIO;
>>  }
>> -#else /* !linux && !FreeBSD */
>> +#else /* !FreeBSD */
>>  
>>  static int fd_open(BlockDriverState *bs)
>>  {
> 
> Full context:
> 
>     #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
>     static int fd_open(BlockDriverState *bs)
>     {
>         BDRVRawState *s = bs->opaque;
> 
>         /* this is just to ensure s->fd is sane (its called by io ops) */
>         if (s->fd >= 0)
>             return 0;
>         return -EIO;
>     }
>     #else /* !FreeBSD */
> 
>     static int fd_open(BlockDriverState *bs)
>     {
>         return 0;
>     }
> 
>     #endif /* !linux && !FreeBSD */
> 
> First of all, the final comment isn't accurate any more, this branch is
> now for Linux, too.
> 
> But really the whole #ifdef looks dubious now. It's not clear to me why
> we're checking fd >= 0 for FreeBSD at all,

Me neither, so I just decided to keep it the way it was.

> using an invalid file
> descriptor (most likely -1, which is set explicitly in some places)
> should automatically lead to failure. And conversely, I can't see why
> doing the same check for non-FreeBSD platforms should hurt.
> 
> Ideally, I'd try to get rid of all the fd_open() calls, but failing that
> let's use the FreeBSD version universally and get rid of the #ifdef at
> least. Or perhaps get rid of the #ifdef in this patch and add another
> one that removes fd_open() completely.

Seems reasonable, will do.

>> diff --git a/qapi/block-core.json b/qapi/block-core.json
>> index 7b2efb8..133fa38 100644
>> --- a/qapi/block-core.json
>> +++ b/qapi/block-core.json
>> @@ -215,10 +215,11 @@
>>  # @drv: the name of the block format used to open the backing device. As of
>>  #       0.14.0 this can be: 'blkdebug', 'bochs', 'cloop', 'cow', 'dmg',
>>  #       'file', 'file', 'ftp', 'ftps', 'host_cdrom', 'host_device',
>> -#       'host_floppy', 'http', 'https', 'nbd', 'parallels', 'qcow',
>> +#       'http', 'https', 'nbd', 'parallels', 'qcow',
>>  #       'qcow2', 'raw', 'tftp', 'vdi', 'vmdk', 'vpc', 'vvfat'
>>  #       2.2: 'archipelago' added, 'cow' dropped
>>  #       2.3: 'host_floppy' deprecated
>> +#       2.4: 'host_floppy' dropped
> 
> 2.5

I should have grep'ed through it. :-)

Thanks for reviewing!

Max


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

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

* Re: [Qemu-devel] [PATCH v4 02/38] blockdev: Allow creation of BDS trees without BB
  2015-09-07 16:12   ` Kevin Wolf
@ 2015-09-07 16:38     ` Max Reitz
  0 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-09-07 16:38 UTC (permalink / raw)
  To: Kevin Wolf
  Cc: Alberto Garcia, qemu-block, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi

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

On 07.09.2015 18:12, Kevin Wolf wrote:
> Am 20.07.2015 um 19:45 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.
> 
> We can probably lift this restriction once Jeff's auto-generated ID
> patches are in. However, allowing additional things is easy, so no
> objection here.

Maybe we can lift it, but I don't know. In order to know the node-name,
you'd have to do a query-named-block-nodes before blockdev-add and
another one afterwards, diff it, and thus obtain the ID. But maybe that
doesn't even work, since one blockdev-add operation usually adds
multiple BDSs at ones.

>> Many BDS options which are not parsed by bdrv_open() (like caching)
>> cannot be specified for these BB-less BDS trees yet. A future patch will
>> remove this limitation.
> 
> This makes the command mostly useless, but that's okay.

Well, the future patch is part of this series, so yes, it is okay.

> We'll be working
> on converting flags to QDict options one by one and then it will start
> working.
> 
> There is, however, one flag that doesn't correspond to an option or
> enable an additional feature that is simply missing until then. That one
> worries me a bit: BDRV_O_INCOMING. We should probably include it in this
> patch; or maybe better add another patch before this one which moves the
> setting of BDRV_O_INCOMING from blockdev_init() to bdrv_open_common().

Hm, probably so, yes. It's still missing at the end of this series, too.
However, as far as I can see, O_INCOMING is set only for the root BDS,
so moving it to bdrv_open_common() would probably change behavior,
though maybe that'd be a bug fix, actually.

Max

>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>> Reviewed-by: Eric Blake <eblake@redhat.com>
>> Reviewed-by: Alberto Garcia <berto@igalia.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(-)
> 
> Kevin
> 



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

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

* Re: [Qemu-devel] [PATCH v4 03/38] iotests: Only create BB if necessary
  2015-09-07 16:20   ` Kevin Wolf
@ 2015-09-07 16:54     ` Max Reitz
  0 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-09-07 16:54 UTC (permalink / raw)
  To: Kevin Wolf
  Cc: Alberto Garcia, qemu-block, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi

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

On 07.09.2015 18:20, Kevin Wolf wrote:
> Am 20.07.2015 um 19:45 hat Max Reitz geschrieben:
>> 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>
>> Reviewed-by: Alberto Garcia <berto@igalia.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"
>> +        }
>> +    }
>> +}
> 
> Any specific reason why format=raw is translated into driver=file here...

This is for the BDS used under blockdev-add, which is supposed to be a
protocol BDS. "raw" was actually wrong, but apparently I felt bad about
specifying a protocol driver on the command line.

>> +{ "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"
>> +            }
>> +        }
>> +    }
>> +}
> 
> ...but into driver=raw,file.driver=file here?

Probably because I assumed based on the test above this one that the
"raw" BDS for blkverify would be a format BDS. Apparently it's not and
both this and the test above this one should be fixed.

>> +{ "execute": "blockdev-add",
>> +    "arguments": {
>> +        "options": {
>>              "driver": "blkverify",
>>              "id": "drive0-verify",
>>              "test": {
> 
>> 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"
>> +            }
>> +        }
>> +    }
>> +}
> 
> And here $IMGFMT becomes raw (which is equivalent, but...)

The other blockdev-add in this example uses hard-coded "raw", too. And
then there's the hard-coded ".raw" extension everywhere in this test...

I'll fix it, but that means fixing the pre-existing blockdev-add, too,
and for such matters the most difficult thing always tends to be
explaining it in the commit message. :-)

Max

>> +{ "execute": "blockdev-add",
>> +    "arguments": {
>> +        "options": {
>>              "driver": "quorum",
>>              "id": "drive0-quorum",
>>              "vote-threshold": 2,
> 
> Kevin
> 



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

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

* Re: [Qemu-devel] [PATCH v4 06/38] block: Make bdrv_is_inserted() recursive
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 06/38] block: Make bdrv_is_inserted() recursive Max Reitz
@ 2015-09-07 17:43   ` Kevin Wolf
  2015-09-07 18:03     ` Max Reitz
  0 siblings, 1 reply; 67+ messages in thread
From: Kevin Wolf @ 2015-09-07 17:43 UTC (permalink / raw)
  To: Max Reitz
  Cc: Alberto Garcia, qemu-block, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi

Am 20.07.2015 um 19:45 hat Max Reitz geschrieben:
> 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>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> Reviewed-by: Alberto Garcia <berto@igalia.com>
> ---
>  block.c | 7 +++----
>  1 file changed, 3 insertions(+), 4 deletions(-)
> 
> diff --git a/block.c b/block.c
> index 494e08e..1d27b6a 100644
> --- a/block.c
> +++ b/block.c
> @@ -3235,10 +3235,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));
>  }

Hm... Recursion often makes the right semantics unclear. I think though
what you're after here is good as a default behaviour, i.e. a non-leaf
node is inserted iff all of its children are inserted. We can do things
in various ways without breaking stuff because raw-posix is the only
driver actually implementing .bdrv_is_inserted, but I think it would
make most sense like this:

* If a driver implements .bdrv_is_inserted, we use this (and only this)
  for determining whether a medium is inserted.

* The default behaviour for drivers which don't have .bdrv_is_inserted
  is checking all children (in bs->children, not restricted to file and
  backing_hd, so that quorum etc. work)

* Consequently, a driver that doesn't want all of its children
  considered (which may be a very valid desire), can implement its own
  handler and doesn't get the default handling then.

This seems to be the most consistent with other recursive operations.

Also, after this patch, raw_bsd.c should be able drop its
implementation.

Kevin

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

* Re: [Qemu-devel] [PATCH v4 06/38] block: Make bdrv_is_inserted() recursive
  2015-09-07 17:43   ` Kevin Wolf
@ 2015-09-07 18:03     ` Max Reitz
  0 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-09-07 18:03 UTC (permalink / raw)
  To: Kevin Wolf
  Cc: Alberto Garcia, qemu-block, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi

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

On 07.09.2015 19:43, Kevin Wolf wrote:
> Am 20.07.2015 um 19:45 hat Max Reitz geschrieben:
>> 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>
>> Reviewed-by: Eric Blake <eblake@redhat.com>
>> Reviewed-by: Alberto Garcia <berto@igalia.com>
>> ---
>>  block.c | 7 +++----
>>  1 file changed, 3 insertions(+), 4 deletions(-)
>>
>> diff --git a/block.c b/block.c
>> index 494e08e..1d27b6a 100644
>> --- a/block.c
>> +++ b/block.c
>> @@ -3235,10 +3235,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));
>>  }
> 
> Hm... Recursion often makes the right semantics unclear. I think though
> what you're after here is good as a default behaviour, i.e. a non-leaf
> node is inserted iff all of its children are inserted. We can do things
> in various ways without breaking stuff because raw-posix is the only
> driver actually implementing .bdrv_is_inserted, but I think it would
> make most sense like this:
> 
> * If a driver implements .bdrv_is_inserted, we use this (and only this)
>   for determining whether a medium is inserted.
> 
> * The default behaviour for drivers which don't have .bdrv_is_inserted
>   is checking all children (in bs->children, not restricted to file and
>   backing_hd, so that quorum etc. work)
> 
> * Consequently, a driver that doesn't want all of its children
>   considered (which may be a very valid desire), can implement its own
>   handler and doesn't get the default handling then.
> 
> This seems to be the most consistent with other recursive operations.

You're right, I'll change this patch accordingly.

> Also, after this patch, raw_bsd.c should be able drop its
> implementation.

Indeed.

Max


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

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

* Re: [Qemu-devel] [PATCH v4 07/38] block/quorum: Implement bdrv_is_inserted()
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 07/38] block/quorum: Implement bdrv_is_inserted() Max Reitz
@ 2015-09-07 18:03   ` Kevin Wolf
  2015-09-07 18:04     ` Max Reitz
  0 siblings, 1 reply; 67+ messages in thread
From: Kevin Wolf @ 2015-09-07 18:03 UTC (permalink / raw)
  To: Max Reitz
  Cc: Alberto Garcia, qemu-block, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi

Am 20.07.2015 um 19:45 hat Max Reitz geschrieben:
> 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>
> Reviewed-by: Alberto Garcia <berto@igalia.com>

If you implement patch 6 like I suggested, this one could be dropped.

Kevin

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

* Re: [Qemu-devel] [PATCH v4 07/38] block/quorum: Implement bdrv_is_inserted()
  2015-09-07 18:03   ` Kevin Wolf
@ 2015-09-07 18:04     ` Max Reitz
  2015-09-07 18:16       ` Kevin Wolf
  0 siblings, 1 reply; 67+ messages in thread
From: Max Reitz @ 2015-09-07 18:04 UTC (permalink / raw)
  To: Kevin Wolf
  Cc: Alberto Garcia, qemu-block, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi

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

On 07.09.2015 20:03, Kevin Wolf wrote:
> Am 20.07.2015 um 19:45 hat Max Reitz geschrieben:
>> 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>
>> Reviewed-by: Alberto Garcia <berto@igalia.com>
> 
> If you implement patch 6 like I suggested, this one could be dropped.

Now that we have this infrastructure, yes. :-)

Max


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

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

* Re: [Qemu-devel] [PATCH v4 09/38] hw/block/fdc: Implement tray status
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 09/38] hw/block/fdc: Implement tray status Max Reitz
@ 2015-09-07 18:13   ` Kevin Wolf
  0 siblings, 0 replies; 67+ messages in thread
From: Kevin Wolf @ 2015-09-07 18:13 UTC (permalink / raw)
  To: Max Reitz
  Cc: Alberto Garcia, qemu-block, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi

Am 20.07.2015 um 19:45 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>
> Reviewed-by: Eric Blake <eblake@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, 25 insertions(+), 68 deletions(-)

The test cases seem to need some rebasing.

Kevin

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

* Re: [Qemu-devel] [PATCH v4 07/38] block/quorum: Implement bdrv_is_inserted()
  2015-09-07 18:04     ` Max Reitz
@ 2015-09-07 18:16       ` Kevin Wolf
  0 siblings, 0 replies; 67+ messages in thread
From: Kevin Wolf @ 2015-09-07 18:16 UTC (permalink / raw)
  To: Max Reitz
  Cc: Alberto Garcia, qemu-block, John Snow, qemu-devel,
	Markus Armbruster, Stefan Hajnoczi

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

Am 07.09.2015 um 20:04 hat Max Reitz geschrieben:
> On 07.09.2015 20:03, Kevin Wolf wrote:
> > Am 20.07.2015 um 19:45 hat Max Reitz geschrieben:
> >> 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>
> >> Reviewed-by: Alberto Garcia <berto@igalia.com>
> > 
> > If you implement patch 6 like I suggested, this one could be dropped.
> 
> Now that we have this infrastructure, yes. :-)

It hardly ever feels like it, but sometimes we do make progress. :-)

Kevin

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [Qemu-devel] [PATCH v4 00/38] blockdev: BlockBackend and media
  2015-09-07  5:53   ` Wen Congyang
@ 2015-09-07 18:42     ` Max Reitz
  0 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-09-07 18:42 UTC (permalink / raw)
  To: Wen Congyang, Eric Blake, qemu-block
  Cc: Kevin Wolf, Alberto Garcia, qemu-devel, Markus Armbruster,
	Stefan Hajnoczi, John Snow

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

On 07.09.2015 07:53, Wen Congyang wrote:
> On 09/02/2015 11:02 PM, Eric Blake wrote:
>> On 07/20/2015 11:45 AM, Max Reitz wrote:
>>> First of all: Thank you, Eric and Berto, for reviewing v3! And thank
>>> you, Fam, for at least having a peek at it and being confident enough to
>>> base a series of your own on it. :-)
>>>
>>> This series reworks a lot regarding BlockBackend and media. Basically,
>>> it 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.
>>
>> We've obviously missed 2.4; but now that 2.5 is open, are there plans to
>> get this series in sooner rather than later?  Wen's work on dynamically
>> adding/deleting children from a quorum would benefit from the ability to
>> create a BDS without an associated BB, which in turn would help the COLO
>> work.
>>
> 
> This feature is very useful for COLO. COLO needs the following:
> 1. adding/deleting children from a quorum dynamically
> 2. allow references for backing files
> 
> The BDS without BB only can be created by the monitor command blockdev-add.
> How to create it in the command line?

Right now: Not at all. Of course it would be possible to add a new
command line parameter ("-blockdev"? "-bds"?) or option to drive
("backend=off" or whatever), but right now I didn't see a need for that.

This series uses this so you can add a new medium for e.g. a CD drive at
runtime. The backends remains attached to the drive, and you swap out
the BDS tree. Thus, there was no need to add a medium via the command line.

Furthermore, often runtime configuration is a subset of command line
configuration, i.e. you can always start the VM paused, invoke some QMP
commands, and then continue the VM. Therefore I don't know whether we
really need the ability to add BB-less BDS trees via the command line.

Max


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

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

* Re: [Qemu-devel] [PATCH v4 29/38] blockdev: Add blockdev-insert-medium
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 29/38] blockdev: Add blockdev-insert-medium Max Reitz
@ 2015-09-08  5:53   ` Wen Congyang
  2015-09-08 15:57     ` Eric Blake
  2015-09-08  9:13   ` Wen Congyang
  1 sibling, 1 reply; 67+ messages in thread
From: Wen Congyang @ 2015-09-08  5:53 UTC (permalink / raw)
  To: Max Reitz, qemu-block
  Cc: Kevin Wolf, Alberto Garcia, qemu-devel, Markus Armbruster,
	Stefan Hajnoczi, John Snow

On 07/21/2015 01:45 AM, Max Reitz wrote:
> 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).

Is it OK to insert a medium to more than one BB?

Thanks
Wen Congyang

> 
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
>  blockdev.c           | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>  qapi/block-core.json | 17 +++++++++++++++++
>  qmp-commands.hx      | 37 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 102 insertions(+)
> 
> diff --git a/blockdev.c b/blockdev.c
> index 481760a..a80d0e2 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -2164,6 +2164,54 @@ 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;
> +    bool has_device;
> +
> +    blk = blk_by_name(device);
> +    if (!blk) {
> +        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
> +                  "Device '%s' not found", device);
> +        return;
> +    }
> +
> +    /* For BBs without a device, we can exchange the BDS tree at will */
> +    has_device = blk_get_attached_dev(blk);
> +
> +    if (has_device && !blk_dev_has_removable_media(blk)) {
> +        error_setg(errp, "Device '%s' is not removable", device);
> +        return;
> +    }
> +
> +    if (has_device && !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 63a83e4..84c9b23 100644
> --- a/qapi/block-core.json
> +++ b/qapi/block-core.json
> @@ -1925,6 +1925,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.5
> +##
> +{ 'command': 'blockdev-insert-medium',
> +  'data': { 'device': 'str',
> +            'node-name': 'str'} }
> +
>  
>  ##
>  # @BlockErrorAction
> diff --git a/qmp-commands.hx b/qmp-commands.hx
> index ff6c572..b4c34fe 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -3991,6 +3991,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,
> 

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

* Re: [Qemu-devel] [PATCH v4 29/38] blockdev: Add blockdev-insert-medium
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 29/38] blockdev: Add blockdev-insert-medium Max Reitz
  2015-09-08  5:53   ` Wen Congyang
@ 2015-09-08  9:13   ` Wen Congyang
  2015-09-08 21:20     ` Max Reitz
  1 sibling, 1 reply; 67+ messages in thread
From: Wen Congyang @ 2015-09-08  9:13 UTC (permalink / raw)
  To: Max Reitz, qemu-block
  Cc: Kevin Wolf, Alberto Garcia, qemu-devel, Markus Armbruster,
	Stefan Hajnoczi, John Snow

On 07/21/2015 01:45 AM, Max Reitz wrote:
> 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>
> ---
>  blockdev.c           | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>  qapi/block-core.json | 17 +++++++++++++++++
>  qmp-commands.hx      | 37 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 102 insertions(+)
> 
> diff --git a/blockdev.c b/blockdev.c
> index 481760a..a80d0e2 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -2164,6 +2164,54 @@ 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;
> +    bool has_device;
> +
> +    blk = blk_by_name(device);
> +    if (!blk) {
> +        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
> +                  "Device '%s' not found", device);
> +        return;
> +    }
> +
> +    /* For BBs without a device, we can exchange the BDS tree at will */
> +    has_device = blk_get_attached_dev(blk);
> +
> +    if (has_device && !blk_dev_has_removable_media(blk)) {
> +        error_setg(errp, "Device '%s' is not removable", device);
> +        return;
> +    }
> +
> +    if (has_device && !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;
> +    }

Hmm, it is OK if the bs is not top BDS?

Thanks
Wen Congyang

> +
> +    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 63a83e4..84c9b23 100644
> --- a/qapi/block-core.json
> +++ b/qapi/block-core.json
> @@ -1925,6 +1925,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.5
> +##
> +{ 'command': 'blockdev-insert-medium',
> +  'data': { 'device': 'str',
> +            'node-name': 'str'} }
> +
>  
>  ##
>  # @BlockErrorAction
> diff --git a/qmp-commands.hx b/qmp-commands.hx
> index ff6c572..b4c34fe 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -3991,6 +3991,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,
> 

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

* Re: [Qemu-devel] [PATCH v4 29/38] blockdev: Add blockdev-insert-medium
  2015-09-08  5:53   ` Wen Congyang
@ 2015-09-08 15:57     ` Eric Blake
  0 siblings, 0 replies; 67+ messages in thread
From: Eric Blake @ 2015-09-08 15:57 UTC (permalink / raw)
  To: Wen Congyang, Max Reitz, qemu-block
  Cc: Kevin Wolf, Alberto Garcia, qemu-devel, Markus Armbruster,
	Stefan Hajnoczi, John Snow

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

On 09/07/2015 11:53 PM, Wen Congyang wrote:
> On 07/21/2015 01:45 AM, Max Reitz wrote:
>> 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).
> 
> Is it OK to insert a medium to more than one BB?

A read-only medium - sure :)

A read-write medium - probably a recipe for data corruption.

-- 
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] 67+ messages in thread

* Re: [Qemu-devel] [PATCH v4 29/38] blockdev: Add blockdev-insert-medium
  2015-09-08  9:13   ` Wen Congyang
@ 2015-09-08 21:20     ` Max Reitz
  2015-09-09 10:01       ` Wen Congyang
  0 siblings, 1 reply; 67+ messages in thread
From: Max Reitz @ 2015-09-08 21:20 UTC (permalink / raw)
  To: Wen Congyang, qemu-block
  Cc: Kevin Wolf, Alberto Garcia, qemu-devel, Markus Armbruster,
	Stefan Hajnoczi, John Snow

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

On 08.09.2015 11:13, Wen Congyang wrote:
> On 07/21/2015 01:45 AM, Max Reitz wrote:
>> 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>
>> ---
>>  blockdev.c           | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  qapi/block-core.json | 17 +++++++++++++++++
>>  qmp-commands.hx      | 37 +++++++++++++++++++++++++++++++++++++
>>  3 files changed, 102 insertions(+)
>>
>> diff --git a/blockdev.c b/blockdev.c
>> index 481760a..a80d0e2 100644
>> --- a/blockdev.c
>> +++ b/blockdev.c
>> @@ -2164,6 +2164,54 @@ 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;
>> +    bool has_device;
>> +
>> +    blk = blk_by_name(device);
>> +    if (!blk) {
>> +        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
>> +                  "Device '%s' not found", device);
>> +        return;
>> +    }
>> +
>> +    /* For BBs without a device, we can exchange the BDS tree at will */
>> +    has_device = blk_get_attached_dev(blk);
>> +
>> +    if (has_device && !blk_dev_has_removable_media(blk)) {
>> +        error_setg(errp, "Device '%s' is not removable", device);
>> +        return;
>> +    }
>> +
>> +    if (has_device && !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;
>> +    }
> 
> Hmm, it is OK if the bs is not top BDS?

I think so, yes. Generally, there's probably no reason to do that, but I
don't know why we should not allow that case. For instance, you might
want to make a backing file available read-only somewhere.

It should be impossible to make it available writable, and it should not
be allowed to start a block-commit operation while the backing file can
be accessed by the guest, but this should be achieved using op blockers.

What we need for this to work are fine-grained op blockers, I think. But
working around that for now by only allowing to insert top BDS won't
work, since you can still start block jobs which target top BDS, too
(e.g. blockdev-backup can write to a BDS/BB that is visible to the guest).

All in all, I think it's fine to insert non-top BDS, but we should
definitely worry about which exact BDS one can insert once we have
fine-grained op blockers.

Max

> Thanks
> Wen Congyang
> 
>> +
>> +    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 63a83e4..84c9b23 100644
>> --- a/qapi/block-core.json
>> +++ b/qapi/block-core.json
>> @@ -1925,6 +1925,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.5
>> +##
>> +{ 'command': 'blockdev-insert-medium',
>> +  'data': { 'device': 'str',
>> +            'node-name': 'str'} }
>> +
>>  
>>  ##
>>  # @BlockErrorAction
>> diff --git a/qmp-commands.hx b/qmp-commands.hx
>> index ff6c572..b4c34fe 100644
>> --- a/qmp-commands.hx
>> +++ b/qmp-commands.hx
>> @@ -3991,6 +3991,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,
>>
> 



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

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

* Re: [Qemu-devel] [PATCH v4 29/38] blockdev: Add blockdev-insert-medium
  2015-09-08 21:20     ` Max Reitz
@ 2015-09-09 10:01       ` Wen Congyang
  2015-09-09 12:59         ` Max Reitz
  0 siblings, 1 reply; 67+ messages in thread
From: Wen Congyang @ 2015-09-09 10:01 UTC (permalink / raw)
  To: Max Reitz, qemu-block
  Cc: Kevin Wolf, Alberto Garcia, qemu-devel, Markus Armbruster,
	Stefan Hajnoczi, John Snow

On 09/09/2015 05:20 AM, Max Reitz wrote:
> On 08.09.2015 11:13, Wen Congyang wrote:
>> On 07/21/2015 01:45 AM, Max Reitz wrote:
>>> 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>
>>> ---
>>>  blockdev.c           | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>  qapi/block-core.json | 17 +++++++++++++++++
>>>  qmp-commands.hx      | 37 +++++++++++++++++++++++++++++++++++++
>>>  3 files changed, 102 insertions(+)
>>>
>>> diff --git a/blockdev.c b/blockdev.c
>>> index 481760a..a80d0e2 100644
>>> --- a/blockdev.c
>>> +++ b/blockdev.c
>>> @@ -2164,6 +2164,54 @@ 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;
>>> +    bool has_device;
>>> +
>>> +    blk = blk_by_name(device);
>>> +    if (!blk) {
>>> +        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
>>> +                  "Device '%s' not found", device);
>>> +        return;
>>> +    }
>>> +
>>> +    /* For BBs without a device, we can exchange the BDS tree at will */
>>> +    has_device = blk_get_attached_dev(blk);
>>> +
>>> +    if (has_device && !blk_dev_has_removable_media(blk)) {
>>> +        error_setg(errp, "Device '%s' is not removable", device);
>>> +        return;
>>> +    }
>>> +
>>> +    if (has_device && !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;
>>> +    }
>>
>> Hmm, it is OK if the bs is not top BDS?
> 
> I think so, yes. Generally, there's probably no reason to do that, but I
> don't know why we should not allow that case. For instance, you might
> want to make a backing file available read-only somewhere.
> 
> It should be impossible to make it available writable, and it should not
> be allowed to start a block-commit operation while the backing file can
> be accessed by the guest, but this should be achieved using op blockers.
> 
> What we need for this to work are fine-grained op blockers, I think. But
> working around that for now by only allowing to insert top BDS won't
> work, since you can still start block jobs which target top BDS, too
> (e.g. blockdev-backup can write to a BDS/BB that is visible to the guest).
> 
> All in all, I think it's fine to insert non-top BDS, but we should
> definitely worry about which exact BDS one can insert once we have
> fine-grained op blockers.

A BDS can be written by its parent, its block backend, a block job..
So I think we should have some way to avoid more than two sources writing
to it, otherwise the data may be corrupted.

Thanks
Wen Congyang

> 
> Max
> 
>> Thanks
>> Wen Congyang
>>
>>> +
>>> +    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 63a83e4..84c9b23 100644
>>> --- a/qapi/block-core.json
>>> +++ b/qapi/block-core.json
>>> @@ -1925,6 +1925,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.5
>>> +##
>>> +{ 'command': 'blockdev-insert-medium',
>>> +  'data': { 'device': 'str',
>>> +            'node-name': 'str'} }
>>> +
>>>  
>>>  ##
>>>  # @BlockErrorAction
>>> diff --git a/qmp-commands.hx b/qmp-commands.hx
>>> index ff6c572..b4c34fe 100644
>>> --- a/qmp-commands.hx
>>> +++ b/qmp-commands.hx
>>> @@ -3991,6 +3991,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,
>>>
>>
> 
> 

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

* Re: [Qemu-devel] [PATCH v4 29/38] blockdev: Add blockdev-insert-medium
  2015-09-09 10:01       ` Wen Congyang
@ 2015-09-09 12:59         ` Max Reitz
  2015-09-10  1:12           ` Wen Congyang
  2015-09-10  3:22           ` Wen Congyang
  0 siblings, 2 replies; 67+ messages in thread
From: Max Reitz @ 2015-09-09 12:59 UTC (permalink / raw)
  To: Wen Congyang, qemu-block
  Cc: Kevin Wolf, Alberto Garcia, qemu-devel, Markus Armbruster,
	Stefan Hajnoczi, John Snow

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

On 09.09.2015 12:01, Wen Congyang wrote:
> On 09/09/2015 05:20 AM, Max Reitz wrote:
>> On 08.09.2015 11:13, Wen Congyang wrote:
>>> On 07/21/2015 01:45 AM, Max Reitz wrote:
>>>> 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>
>>>> ---
>>>>  blockdev.c           | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>  qapi/block-core.json | 17 +++++++++++++++++
>>>>  qmp-commands.hx      | 37 +++++++++++++++++++++++++++++++++++++
>>>>  3 files changed, 102 insertions(+)
>>>>
>>>> diff --git a/blockdev.c b/blockdev.c
>>>> index 481760a..a80d0e2 100644
>>>> --- a/blockdev.c
>>>> +++ b/blockdev.c
>>>> @@ -2164,6 +2164,54 @@ 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;
>>>> +    bool has_device;
>>>> +
>>>> +    blk = blk_by_name(device);
>>>> +    if (!blk) {
>>>> +        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
>>>> +                  "Device '%s' not found", device);
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    /* For BBs without a device, we can exchange the BDS tree at will */
>>>> +    has_device = blk_get_attached_dev(blk);
>>>> +
>>>> +    if (has_device && !blk_dev_has_removable_media(blk)) {
>>>> +        error_setg(errp, "Device '%s' is not removable", device);
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    if (has_device && !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;
>>>> +    }
>>>
>>> Hmm, it is OK if the bs is not top BDS?
>>
>> I think so, yes. Generally, there's probably no reason to do that, but I
>> don't know why we should not allow that case. For instance, you might
>> want to make a backing file available read-only somewhere.
>>
>> It should be impossible to make it available writable, and it should not
>> be allowed to start a block-commit operation while the backing file can
>> be accessed by the guest, but this should be achieved using op blockers.
>>
>> What we need for this to work are fine-grained op blockers, I think. But
>> working around that for now by only allowing to insert top BDS won't
>> work, since you can still start block jobs which target top BDS, too
>> (e.g. blockdev-backup can write to a BDS/BB that is visible to the guest).
>>
>> All in all, I think it's fine to insert non-top BDS, but we should
>> definitely worry about which exact BDS one can insert once we have
>> fine-grained op blockers.
> 
> A BDS can be written by its parent, its block backend, a block job..
> So I think we should have some way to avoid more than two sources writing
> to it, otherwise the data may be corrupted.

Yes, and that would be op blockers.

As I said, using blockdev-backup you can write to a BB that can be
written to by the guest as well. I think this is a bug, but it is a bug
that needs to be fixed by having better op blockers in place, which Jeff
Cody is working on.

Regarding this series, I don't consider this to be too big of an issue.
Yes, if you are working with floppy disks, you can have the case of a
block job and the guest writing to the BDS at the same time. But I can't
really imagine who would use floppy disks and block jobs at the same
time (people who still use floppy disks for their VMs don't strike me as
the kind of people who use the management features of qemu, especially
not for those floppy disks).

Other than that, this function (blockdev-insert-medium) can only be used
for optical ROM devices (I don't think we have CD/DVD-RW support, do
we?), so it's much less of an issue there.

So all in all I don't consider this too big of an issue here. If others
think different, then I would delay this part of the series (which
overhauls the "change" command) until we have fine-grained op blockers.

Max


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

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

* Re: [Qemu-devel] [PATCH v4 29/38] blockdev: Add blockdev-insert-medium
  2015-09-09 12:59         ` Max Reitz
@ 2015-09-10  1:12           ` Wen Congyang
  2015-09-10 19:09             ` Max Reitz
  2015-09-10  3:22           ` Wen Congyang
  1 sibling, 1 reply; 67+ messages in thread
From: Wen Congyang @ 2015-09-10  1:12 UTC (permalink / raw)
  To: Max Reitz, qemu-block
  Cc: Kevin Wolf, Alberto Garcia, qemu-devel, Markus Armbruster,
	Stefan Hajnoczi, John Snow

On 09/09/2015 08:59 PM, Max Reitz wrote:
> On 09.09.2015 12:01, Wen Congyang wrote:
>> On 09/09/2015 05:20 AM, Max Reitz wrote:
>>> On 08.09.2015 11:13, Wen Congyang wrote:
>>>> On 07/21/2015 01:45 AM, Max Reitz wrote:
>>>>> 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>
>>>>> ---
>>>>>  blockdev.c           | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>  qapi/block-core.json | 17 +++++++++++++++++
>>>>>  qmp-commands.hx      | 37 +++++++++++++++++++++++++++++++++++++
>>>>>  3 files changed, 102 insertions(+)
>>>>>
>>>>> diff --git a/blockdev.c b/blockdev.c
>>>>> index 481760a..a80d0e2 100644
>>>>> --- a/blockdev.c
>>>>> +++ b/blockdev.c
>>>>> @@ -2164,6 +2164,54 @@ 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;
>>>>> +    bool has_device;
>>>>> +
>>>>> +    blk = blk_by_name(device);
>>>>> +    if (!blk) {
>>>>> +        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
>>>>> +                  "Device '%s' not found", device);
>>>>> +        return;
>>>>> +    }
>>>>> +
>>>>> +    /* For BBs without a device, we can exchange the BDS tree at will */
>>>>> +    has_device = blk_get_attached_dev(blk);
>>>>> +
>>>>> +    if (has_device && !blk_dev_has_removable_media(blk)) {
>>>>> +        error_setg(errp, "Device '%s' is not removable", device);
>>>>> +        return;
>>>>> +    }
>>>>> +
>>>>> +    if (has_device && !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;
>>>>> +    }
>>>>
>>>> Hmm, it is OK if the bs is not top BDS?
>>>
>>> I think so, yes. Generally, there's probably no reason to do that, but I
>>> don't know why we should not allow that case. For instance, you might
>>> want to make a backing file available read-only somewhere.
>>>
>>> It should be impossible to make it available writable, and it should not
>>> be allowed to start a block-commit operation while the backing file can
>>> be accessed by the guest, but this should be achieved using op blockers.
>>>
>>> What we need for this to work are fine-grained op blockers, I think. But
>>> working around that for now by only allowing to insert top BDS won't
>>> work, since you can still start block jobs which target top BDS, too
>>> (e.g. blockdev-backup can write to a BDS/BB that is visible to the guest).
>>>
>>> All in all, I think it's fine to insert non-top BDS, but we should
>>> definitely worry about which exact BDS one can insert once we have
>>> fine-grained op blockers.
>>
>> A BDS can be written by its parent, its block backend, a block job..
>> So I think we should have some way to avoid more than two sources writing
>> to it, otherwise the data may be corrupted.
> 
> Yes, and that would be op blockers.
> 
> As I said, using blockdev-backup you can write to a BB that can be
> written to by the guest as well. I think this is a bug, but it is a bug
> that needs to be fixed by having better op blockers in place, which Jeff
> Cody is working on.
> 
> Regarding this series, I don't consider this to be too big of an issue.
> Yes, if you are working with floppy disks, you can have the case of a
> block job and the guest writing to the BDS at the same time. But I can't
> really imagine who would use floppy disks and block jobs at the same
> time (people who still use floppy disks for their VMs don't strike me as
> the kind of people who use the management features of qemu, especially
> not for those floppy disks).
> 
> Other than that, this function (blockdev-insert-medium) can only be used
> for optical ROM devices (I don't think we have CD/DVD-RW support, do
> we?), so it's much less of an issue there.
> 
> So all in all I don't consider this too big of an issue here. If others
> think different, then I would delay this part of the series (which
> overhauls the "change" command) until we have fine-grained op blockers.

In most cases, the user uses this command to change CD/DVD media, so it is OK.
But IIRC scsi disk can also be changed. So we can mark this command as experimental
(the command name can be x-blockdev-insert-medium).

Thanks
Wen Congyang

> 
> Max
> 

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

* Re: [Qemu-devel] [PATCH v4 29/38] blockdev: Add blockdev-insert-medium
  2015-09-09 12:59         ` Max Reitz
  2015-09-10  1:12           ` Wen Congyang
@ 2015-09-10  3:22           ` Wen Congyang
  2015-09-10 19:10             ` Max Reitz
  1 sibling, 1 reply; 67+ messages in thread
From: Wen Congyang @ 2015-09-10  3:22 UTC (permalink / raw)
  To: Max Reitz, qemu-block
  Cc: Kevin Wolf, Alberto Garcia, qemu-devel, Markus Armbruster,
	Stefan Hajnoczi, John Snow

On 09/09/2015 08:59 PM, Max Reitz wrote:
> On 09.09.2015 12:01, Wen Congyang wrote:
>> On 09/09/2015 05:20 AM, Max Reitz wrote:
>>> On 08.09.2015 11:13, Wen Congyang wrote:
>>>> On 07/21/2015 01:45 AM, Max Reitz wrote:
>>>>> 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>
>>>>> ---
>>>>>  blockdev.c           | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>  qapi/block-core.json | 17 +++++++++++++++++
>>>>>  qmp-commands.hx      | 37 +++++++++++++++++++++++++++++++++++++
>>>>>  3 files changed, 102 insertions(+)
>>>>>
>>>>> diff --git a/blockdev.c b/blockdev.c
>>>>> index 481760a..a80d0e2 100644
>>>>> --- a/blockdev.c
>>>>> +++ b/blockdev.c
>>>>> @@ -2164,6 +2164,54 @@ 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;
>>>>> +    bool has_device;
>>>>> +
>>>>> +    blk = blk_by_name(device);
>>>>> +    if (!blk) {
>>>>> +        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
>>>>> +                  "Device '%s' not found", device);
>>>>> +        return;
>>>>> +    }
>>>>> +
>>>>> +    /* For BBs without a device, we can exchange the BDS tree at will */
>>>>> +    has_device = blk_get_attached_dev(blk);
>>>>> +
>>>>> +    if (has_device && !blk_dev_has_removable_media(blk)) {
>>>>> +        error_setg(errp, "Device '%s' is not removable", device);
>>>>> +        return;
>>>>> +    }
>>>>> +
>>>>> +    if (has_device && !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;
>>>>> +    }
>>>>
>>>> Hmm, it is OK if the bs is not top BDS?
>>>
>>> I think so, yes. Generally, there's probably no reason to do that, but I
>>> don't know why we should not allow that case. For instance, you might
>>> want to make a backing file available read-only somewhere.
>>>
>>> It should be impossible to make it available writable, and it should not
>>> be allowed to start a block-commit operation while the backing file can
>>> be accessed by the guest, but this should be achieved using op blockers.
>>>
>>> What we need for this to work are fine-grained op blockers, I think. But
>>> working around that for now by only allowing to insert top BDS won't
>>> work, since you can still start block jobs which target top BDS, too
>>> (e.g. blockdev-backup can write to a BDS/BB that is visible to the guest).
>>>
>>> All in all, I think it's fine to insert non-top BDS, but we should
>>> definitely worry about which exact BDS one can insert once we have
>>> fine-grained op blockers.
>>
>> A BDS can be written by its parent, its block backend, a block job..
>> So I think we should have some way to avoid more than two sources writing
>> to it, otherwise the data may be corrupted.
> 
> Yes, and that would be op blockers.
> 
> As I said, using blockdev-backup you can write to a BB that can be
> written to by the guest as well. I think this is a bug, but it is a bug
> that needs to be fixed by having better op blockers in place, which Jeff
> Cody is working on.

I don't find such patches in the maillist.

Thanks
Wen Congyang

> 
> Regarding this series, I don't consider this to be too big of an issue.
> Yes, if you are working with floppy disks, you can have the case of a
> block job and the guest writing to the BDS at the same time. But I can't
> really imagine who would use floppy disks and block jobs at the same
> time (people who still use floppy disks for their VMs don't strike me as
> the kind of people who use the management features of qemu, especially
> not for those floppy disks).
> 
> Other than that, this function (blockdev-insert-medium) can only be used
> for optical ROM devices (I don't think we have CD/DVD-RW support, do
> we?), so it's much less of an issue there.
> 
> So all in all I don't consider this too big of an issue here. If others
> think different, then I would delay this part of the series (which
> overhauls the "change" command) until we have fine-grained op blockers.
> 
> Max
> 

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

* Re: [Qemu-devel] [PATCH v4 29/38] blockdev: Add blockdev-insert-medium
  2015-09-10  1:12           ` Wen Congyang
@ 2015-09-10 19:09             ` Max Reitz
  2015-09-11  7:30               ` Wen Congyang
  0 siblings, 1 reply; 67+ messages in thread
From: Max Reitz @ 2015-09-10 19:09 UTC (permalink / raw)
  To: Wen Congyang, qemu-block
  Cc: Kevin Wolf, Alberto Garcia, qemu-devel, Markus Armbruster,
	Stefan Hajnoczi, John Snow

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

On 10.09.2015 03:12, Wen Congyang wrote:
> On 09/09/2015 08:59 PM, Max Reitz wrote:
>> On 09.09.2015 12:01, Wen Congyang wrote:
>>> On 09/09/2015 05:20 AM, Max Reitz wrote:
>>>> On 08.09.2015 11:13, Wen Congyang wrote:
>>>>> On 07/21/2015 01:45 AM, Max Reitz wrote:
>>>>>> 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>
>>>>>> ---
>>>>>>  blockdev.c           | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>  qapi/block-core.json | 17 +++++++++++++++++
>>>>>>  qmp-commands.hx      | 37 +++++++++++++++++++++++++++++++++++++
>>>>>>  3 files changed, 102 insertions(+)
>>>>>>
>>>>>> diff --git a/blockdev.c b/blockdev.c
>>>>>> index 481760a..a80d0e2 100644
>>>>>> --- a/blockdev.c
>>>>>> +++ b/blockdev.c
>>>>>> @@ -2164,6 +2164,54 @@ 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;
>>>>>> +    bool has_device;
>>>>>> +
>>>>>> +    blk = blk_by_name(device);
>>>>>> +    if (!blk) {
>>>>>> +        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
>>>>>> +                  "Device '%s' not found", device);
>>>>>> +        return;
>>>>>> +    }
>>>>>> +
>>>>>> +    /* For BBs without a device, we can exchange the BDS tree at will */
>>>>>> +    has_device = blk_get_attached_dev(blk);
>>>>>> +
>>>>>> +    if (has_device && !blk_dev_has_removable_media(blk)) {
>>>>>> +        error_setg(errp, "Device '%s' is not removable", device);
>>>>>> +        return;
>>>>>> +    }
>>>>>> +
>>>>>> +    if (has_device && !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;
>>>>>> +    }
>>>>>
>>>>> Hmm, it is OK if the bs is not top BDS?
>>>>
>>>> I think so, yes. Generally, there's probably no reason to do that, but I
>>>> don't know why we should not allow that case. For instance, you might
>>>> want to make a backing file available read-only somewhere.
>>>>
>>>> It should be impossible to make it available writable, and it should not
>>>> be allowed to start a block-commit operation while the backing file can
>>>> be accessed by the guest, but this should be achieved using op blockers.
>>>>
>>>> What we need for this to work are fine-grained op blockers, I think. But
>>>> working around that for now by only allowing to insert top BDS won't
>>>> work, since you can still start block jobs which target top BDS, too
>>>> (e.g. blockdev-backup can write to a BDS/BB that is visible to the guest).
>>>>
>>>> All in all, I think it's fine to insert non-top BDS, but we should
>>>> definitely worry about which exact BDS one can insert once we have
>>>> fine-grained op blockers.
>>>
>>> A BDS can be written by its parent, its block backend, a block job..
>>> So I think we should have some way to avoid more than two sources writing
>>> to it, otherwise the data may be corrupted.
>>
>> Yes, and that would be op blockers.
>>
>> As I said, using blockdev-backup you can write to a BB that can be
>> written to by the guest as well. I think this is a bug, but it is a bug
>> that needs to be fixed by having better op blockers in place, which Jeff
>> Cody is working on.
>>
>> Regarding this series, I don't consider this to be too big of an issue.
>> Yes, if you are working with floppy disks, you can have the case of a
>> block job and the guest writing to the BDS at the same time. But I can't
>> really imagine who would use floppy disks and block jobs at the same
>> time (people who still use floppy disks for their VMs don't strike me as
>> the kind of people who use the management features of qemu, especially
>> not for those floppy disks).
>>
>> Other than that, this function (blockdev-insert-medium) can only be used
>> for optical ROM devices (I don't think we have CD/DVD-RW support, do
>> we?), so it's much less of an issue there.
>>
>> So all in all I don't consider this too big of an issue here. If others
>> think different, then I would delay this part of the series (which
>> overhauls the "change" command) until we have fine-grained op blockers.
> 
> In most cases, the user uses this command to change CD/DVD media, so it is OK.
> But IIRC scsi disk can also be changed. So we can mark this command as experimental
> (the command name can be x-blockdev-insert-medium).

I'd rather delay this part than mark it experimental. But then again,
seeing that we have cases like this already (i.e. blockdev-backup) and
nobody seems to be complaining, I still think it should be fine.

Max


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

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

* Re: [Qemu-devel] [PATCH v4 29/38] blockdev: Add blockdev-insert-medium
  2015-09-10  3:22           ` Wen Congyang
@ 2015-09-10 19:10             ` Max Reitz
  0 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-09-10 19:10 UTC (permalink / raw)
  To: Wen Congyang, qemu-block
  Cc: Kevin Wolf, Alberto Garcia, qemu-devel, Markus Armbruster,
	Stefan Hajnoczi, John Snow

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

On 10.09.2015 05:22, Wen Congyang wrote:
> On 09/09/2015 08:59 PM, Max Reitz wrote:
>> On 09.09.2015 12:01, Wen Congyang wrote:
>>> On 09/09/2015 05:20 AM, Max Reitz wrote:
>>>> On 08.09.2015 11:13, Wen Congyang wrote:
>>>>> On 07/21/2015 01:45 AM, Max Reitz wrote:
>>>>>> 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>
>>>>>> ---
>>>>>>  blockdev.c           | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>  qapi/block-core.json | 17 +++++++++++++++++
>>>>>>  qmp-commands.hx      | 37 +++++++++++++++++++++++++++++++++++++
>>>>>>  3 files changed, 102 insertions(+)
>>>>>>
>>>>>> diff --git a/blockdev.c b/blockdev.c
>>>>>> index 481760a..a80d0e2 100644
>>>>>> --- a/blockdev.c
>>>>>> +++ b/blockdev.c
>>>>>> @@ -2164,6 +2164,54 @@ 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;
>>>>>> +    bool has_device;
>>>>>> +
>>>>>> +    blk = blk_by_name(device);
>>>>>> +    if (!blk) {
>>>>>> +        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
>>>>>> +                  "Device '%s' not found", device);
>>>>>> +        return;
>>>>>> +    }
>>>>>> +
>>>>>> +    /* For BBs without a device, we can exchange the BDS tree at will */
>>>>>> +    has_device = blk_get_attached_dev(blk);
>>>>>> +
>>>>>> +    if (has_device && !blk_dev_has_removable_media(blk)) {
>>>>>> +        error_setg(errp, "Device '%s' is not removable", device);
>>>>>> +        return;
>>>>>> +    }
>>>>>> +
>>>>>> +    if (has_device && !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;
>>>>>> +    }
>>>>>
>>>>> Hmm, it is OK if the bs is not top BDS?
>>>>
>>>> I think so, yes. Generally, there's probably no reason to do that, but I
>>>> don't know why we should not allow that case. For instance, you might
>>>> want to make a backing file available read-only somewhere.
>>>>
>>>> It should be impossible to make it available writable, and it should not
>>>> be allowed to start a block-commit operation while the backing file can
>>>> be accessed by the guest, but this should be achieved using op blockers.
>>>>
>>>> What we need for this to work are fine-grained op blockers, I think. But
>>>> working around that for now by only allowing to insert top BDS won't
>>>> work, since you can still start block jobs which target top BDS, too
>>>> (e.g. blockdev-backup can write to a BDS/BB that is visible to the guest).
>>>>
>>>> All in all, I think it's fine to insert non-top BDS, but we should
>>>> definitely worry about which exact BDS one can insert once we have
>>>> fine-grained op blockers.
>>>
>>> A BDS can be written by its parent, its block backend, a block job..
>>> So I think we should have some way to avoid more than two sources writing
>>> to it, otherwise the data may be corrupted.
>>
>> Yes, and that would be op blockers.
>>
>> As I said, using blockdev-backup you can write to a BB that can be
>> written to by the guest as well. I think this is a bug, but it is a bug
>> that needs to be fixed by having better op blockers in place, which Jeff
>> Cody is working on.
> 
> I don't find such patches in the maillist.

That's because Jeff is still working on designing and writing them.

Max


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

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

* Re: [Qemu-devel] [PATCH v4 29/38] blockdev: Add blockdev-insert-medium
  2015-09-10 19:09             ` Max Reitz
@ 2015-09-11  7:30               ` Wen Congyang
  2015-09-11 17:01                 ` Max Reitz
  0 siblings, 1 reply; 67+ messages in thread
From: Wen Congyang @ 2015-09-11  7:30 UTC (permalink / raw)
  To: Max Reitz, qemu-block
  Cc: Kevin Wolf, Alberto Garcia, qemu-devel, Markus Armbruster,
	Stefan Hajnoczi, John Snow

On 09/11/2015 03:09 AM, Max Reitz wrote:
> On 10.09.2015 03:12, Wen Congyang wrote:
>> On 09/09/2015 08:59 PM, Max Reitz wrote:
>>> On 09.09.2015 12:01, Wen Congyang wrote:
>>>> On 09/09/2015 05:20 AM, Max Reitz wrote:
>>>>> On 08.09.2015 11:13, Wen Congyang wrote:
>>>>>> On 07/21/2015 01:45 AM, Max Reitz wrote:
>>>>>>> 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>
>>>>>>> ---
>>>>>>>  blockdev.c           | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>  qapi/block-core.json | 17 +++++++++++++++++
>>>>>>>  qmp-commands.hx      | 37 +++++++++++++++++++++++++++++++++++++
>>>>>>>  3 files changed, 102 insertions(+)
>>>>>>>
>>>>>>> diff --git a/blockdev.c b/blockdev.c
>>>>>>> index 481760a..a80d0e2 100644
>>>>>>> --- a/blockdev.c
>>>>>>> +++ b/blockdev.c
>>>>>>> @@ -2164,6 +2164,54 @@ 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;
>>>>>>> +    bool has_device;
>>>>>>> +
>>>>>>> +    blk = blk_by_name(device);
>>>>>>> +    if (!blk) {
>>>>>>> +        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
>>>>>>> +                  "Device '%s' not found", device);
>>>>>>> +        return;
>>>>>>> +    }
>>>>>>> +
>>>>>>> +    /* For BBs without a device, we can exchange the BDS tree at will */
>>>>>>> +    has_device = blk_get_attached_dev(blk);
>>>>>>> +
>>>>>>> +    if (has_device && !blk_dev_has_removable_media(blk)) {
>>>>>>> +        error_setg(errp, "Device '%s' is not removable", device);
>>>>>>> +        return;
>>>>>>> +    }
>>>>>>> +
>>>>>>> +    if (has_device && !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;
>>>>>>> +    }
>>>>>>
>>>>>> Hmm, it is OK if the bs is not top BDS?
>>>>>
>>>>> I think so, yes. Generally, there's probably no reason to do that, but I
>>>>> don't know why we should not allow that case. For instance, you might
>>>>> want to make a backing file available read-only somewhere.
>>>>>
>>>>> It should be impossible to make it available writable, and it should not
>>>>> be allowed to start a block-commit operation while the backing file can
>>>>> be accessed by the guest, but this should be achieved using op blockers.
>>>>>
>>>>> What we need for this to work are fine-grained op blockers, I think. But
>>>>> working around that for now by only allowing to insert top BDS won't
>>>>> work, since you can still start block jobs which target top BDS, too
>>>>> (e.g. blockdev-backup can write to a BDS/BB that is visible to the guest).
>>>>>
>>>>> All in all, I think it's fine to insert non-top BDS, but we should
>>>>> definitely worry about which exact BDS one can insert once we have
>>>>> fine-grained op blockers.
>>>>
>>>> A BDS can be written by its parent, its block backend, a block job..
>>>> So I think we should have some way to avoid more than two sources writing
>>>> to it, otherwise the data may be corrupted.
>>>
>>> Yes, and that would be op blockers.
>>>
>>> As I said, using blockdev-backup you can write to a BB that can be
>>> written to by the guest as well. I think this is a bug, but it is a bug
>>> that needs to be fixed by having better op blockers in place, which Jeff
>>> Cody is working on.
>>>
>>> Regarding this series, I don't consider this to be too big of an issue.
>>> Yes, if you are working with floppy disks, you can have the case of a
>>> block job and the guest writing to the BDS at the same time. But I can't
>>> really imagine who would use floppy disks and block jobs at the same
>>> time (people who still use floppy disks for their VMs don't strike me as
>>> the kind of people who use the management features of qemu, especially
>>> not for those floppy disks).
>>>
>>> Other than that, this function (blockdev-insert-medium) can only be used
>>> for optical ROM devices (I don't think we have CD/DVD-RW support, do
>>> we?), so it's much less of an issue there.
>>>
>>> So all in all I don't consider this too big of an issue here. If others
>>> think different, then I would delay this part of the series (which
>>> overhauls the "change" command) until we have fine-grained op blockers.
>>
>> In most cases, the user uses this command to change CD/DVD media, so it is OK.
>> But IIRC scsi disk can also be changed. So we can mark this command as experimental
>> (the command name can be x-blockdev-insert-medium).
> 
> I'd rather delay this part than mark it experimental. But then again,
> seeing that we have cases like this already (i.e. blockdev-backup) and
> nobody seems to be complaining, I still think it should be fine.

Hmm, another question, when will you post the newest patchset? Block replication is
based on this patchset.

Thanks
Wen Congyang

> 
> Max
> 

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

* Re: [Qemu-devel] [PATCH v4 29/38] blockdev: Add blockdev-insert-medium
  2015-09-11  7:30               ` Wen Congyang
@ 2015-09-11 17:01                 ` Max Reitz
  0 siblings, 0 replies; 67+ messages in thread
From: Max Reitz @ 2015-09-11 17:01 UTC (permalink / raw)
  To: Wen Congyang, qemu-block
  Cc: Kevin Wolf, Alberto Garcia, qemu-devel, Markus Armbruster,
	Stefan Hajnoczi, John Snow

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

On 11.09.2015 09:30, Wen Congyang wrote:
> On 09/11/2015 03:09 AM, Max Reitz wrote:
>> On 10.09.2015 03:12, Wen Congyang wrote:
>>> On 09/09/2015 08:59 PM, Max Reitz wrote:
>>>> On 09.09.2015 12:01, Wen Congyang wrote:
>>>>> On 09/09/2015 05:20 AM, Max Reitz wrote:
>>>>>> On 08.09.2015 11:13, Wen Congyang wrote:
>>>>>>> On 07/21/2015 01:45 AM, Max Reitz wrote:
>>>>>>>> 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>
>>>>>>>> ---
>>>>>>>>  blockdev.c           | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>  qapi/block-core.json | 17 +++++++++++++++++
>>>>>>>>  qmp-commands.hx      | 37 +++++++++++++++++++++++++++++++++++++
>>>>>>>>  3 files changed, 102 insertions(+)
>>>>>>>>
>>>>>>>> diff --git a/blockdev.c b/blockdev.c
>>>>>>>> index 481760a..a80d0e2 100644
>>>>>>>> --- a/blockdev.c
>>>>>>>> +++ b/blockdev.c
>>>>>>>> @@ -2164,6 +2164,54 @@ 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;
>>>>>>>> +    bool has_device;
>>>>>>>> +
>>>>>>>> +    blk = blk_by_name(device);
>>>>>>>> +    if (!blk) {
>>>>>>>> +        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
>>>>>>>> +                  "Device '%s' not found", device);
>>>>>>>> +        return;
>>>>>>>> +    }
>>>>>>>> +
>>>>>>>> +    /* For BBs without a device, we can exchange the BDS tree at will */
>>>>>>>> +    has_device = blk_get_attached_dev(blk);
>>>>>>>> +
>>>>>>>> +    if (has_device && !blk_dev_has_removable_media(blk)) {
>>>>>>>> +        error_setg(errp, "Device '%s' is not removable", device);
>>>>>>>> +        return;
>>>>>>>> +    }
>>>>>>>> +
>>>>>>>> +    if (has_device && !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;
>>>>>>>> +    }
>>>>>>>
>>>>>>> Hmm, it is OK if the bs is not top BDS?
>>>>>>
>>>>>> I think so, yes. Generally, there's probably no reason to do that, but I
>>>>>> don't know why we should not allow that case. For instance, you might
>>>>>> want to make a backing file available read-only somewhere.
>>>>>>
>>>>>> It should be impossible to make it available writable, and it should not
>>>>>> be allowed to start a block-commit operation while the backing file can
>>>>>> be accessed by the guest, but this should be achieved using op blockers.
>>>>>>
>>>>>> What we need for this to work are fine-grained op blockers, I think. But
>>>>>> working around that for now by only allowing to insert top BDS won't
>>>>>> work, since you can still start block jobs which target top BDS, too
>>>>>> (e.g. blockdev-backup can write to a BDS/BB that is visible to the guest).
>>>>>>
>>>>>> All in all, I think it's fine to insert non-top BDS, but we should
>>>>>> definitely worry about which exact BDS one can insert once we have
>>>>>> fine-grained op blockers.
>>>>>
>>>>> A BDS can be written by its parent, its block backend, a block job..
>>>>> So I think we should have some way to avoid more than two sources writing
>>>>> to it, otherwise the data may be corrupted.
>>>>
>>>> Yes, and that would be op blockers.
>>>>
>>>> As I said, using blockdev-backup you can write to a BB that can be
>>>> written to by the guest as well. I think this is a bug, but it is a bug
>>>> that needs to be fixed by having better op blockers in place, which Jeff
>>>> Cody is working on.
>>>>
>>>> Regarding this series, I don't consider this to be too big of an issue.
>>>> Yes, if you are working with floppy disks, you can have the case of a
>>>> block job and the guest writing to the BDS at the same time. But I can't
>>>> really imagine who would use floppy disks and block jobs at the same
>>>> time (people who still use floppy disks for their VMs don't strike me as
>>>> the kind of people who use the management features of qemu, especially
>>>> not for those floppy disks).
>>>>
>>>> Other than that, this function (blockdev-insert-medium) can only be used
>>>> for optical ROM devices (I don't think we have CD/DVD-RW support, do
>>>> we?), so it's much less of an issue there.
>>>>
>>>> So all in all I don't consider this too big of an issue here. If others
>>>> think different, then I would delay this part of the series (which
>>>> overhauls the "change" command) until we have fine-grained op blockers.
>>>
>>> In most cases, the user uses this command to change CD/DVD media, so it is OK.
>>> But IIRC scsi disk can also be changed. So we can mark this command as experimental
>>> (the command name can be x-blockdev-insert-medium).
>>
>> I'd rather delay this part than mark it experimental. But then again,
>> seeing that we have cases like this already (i.e. blockdev-backup) and
>> nobody seems to be complaining, I still think it should be fine.
> 
> Hmm, another question, when will you post the newest patchset? Block replication is
> based on this patchset.

The best I can say is "once I have the time". There are a lot of things
going on right now, not only regarding code I have to write, but also
regarding patches I have to review.

This series hasn't really been on other people's priority list for eight
months now, so I had to take up other things in between which means that
now I cannot just focus on this series alone and don't do anything else.

Be assured that I took notice that you requested a new version, though,
so I will work on it once I can.

Max


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

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

* Re: [Qemu-devel] [PATCH v4 16/38] block: Add BlockBackendRootState
  2015-07-20 17:45 ` [Qemu-devel] [PATCH v4 16/38] block: Add BlockBackendRootState Max Reitz
@ 2015-09-11 23:20   ` Eric Blake
  0 siblings, 0 replies; 67+ messages in thread
From: Eric Blake @ 2015-09-11 23:20 UTC (permalink / raw)
  To: Max Reitz, qemu-block
  Cc: Kevin Wolf, Alberto Garcia, qemu-devel, Markus Armbruster,
	Stefan Hajnoczi, John Snow

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

On 07/20/2015 11:45 AM, Max Reitz wrote:
> 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>
> ---
>  block/block-backend.c          | 37 +++++++++++++++++++++++++++++++++++++
>  include/block/block_int.h      | 10 ++++++++++
>  include/qemu/typedefs.h        |  1 +
>  include/sysemu/block-backend.h |  2 ++
>  4 files changed, 50 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] 67+ messages in thread

end of thread, other threads:[~2015-09-11 23:20 UTC | newest]

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