All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2
@ 2018-02-21 13:53 Kevin Wolf
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 01/36] block/qapi: Introduce BlockdevCreateOptions Kevin Wolf
                   ` (35 more replies)
  0 siblings, 36 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

This series implements a minimal QMP command that allows to create an
image file on the protocol level or an image format on a given block
node.

Eventually, the interface is going to change to some kind of an async
command (possibly a (non-)block job), but that will require more work on
the job infrastructure first, so let's first QAPIfy image creation in
the block drivers. In this series, I'm going for a synchronous command
that is prefixed with x- for now.

This series converts qcow2 and all protocol drivers that allow an actual
image creation. This means that drivers which only check if the already
existing storage is good enough are not converted (e.g. host_device,
iscsi). The old behaviour was useful because 'qemu-img create' wants to
create both protocol and format layer, but with the separation in QMP,
you can just leave out the protocol layer creation when the device
already exists.

Please note that for some of the protocol drivers (gluster, rbd and
sheepdog) I don't have a test setup ready. For those, I only tested
with a fake server address to check that the option are parsed correctly
up to this point and an appropriate error is returned without crashing.

If you are a maintainer of one of these protocols and you are
interested in keeping image creation working for your protocol, you
probably want to test this series on a real setup and give me some
feedback. If you don't, I'll just merge the patches and hope that they
won't break anything.

v2:
- Patch 1 ('block/qapi: Introduce BlockdevCreateOptions'):
  Added nvme as unsupported driver

- Patch 8 ('util: Add qemu_opts_to_qdict_filtered'):
  Fixed use after free with QemuOpts that contained more than one option
  with the same name, documented the behaviour with them

- Patches 9 and 10 (new):
  Added unit tests for qemu_opts_append() and
  qemu_opts_to_qdict_filtered()

- Patch 11 ('qdict: Introduce qdict_rename_keys()'):
  Added unit test, improved documentation

- Patch 12 ('qcow2: Use visitor for options in qcow2_create()'):
  Improved commit message, removed unnecessary movement of declaration

- Patches 13 and 14 ('block: x-blockdev-create QMP command'):
  Move making bdrv_is_whitelisted() public into a separate patch,
  use read-write driver whitelist instead of read-only

- Patch 17 ('gluster: Support .bdrv_co_create'):
  Rebased on top of preallocated truncate

- Patches 18-24 ('rbd: Support .bdrv_co_create'):
  QAPIfied .bdrv_open() implementation so that it can be shared with
  .bdrv_co_create() and specified servers are actually used instead of
  silently ignored

- Patch 25 ('nfs: Use QAPI options in nfs_client_open()'):
  Fixed use of uninitialised variable in the error path

- Patch 27 ('sheepdog: QAPIfy "redundacy" create option'):
  Addressed FIXME to use qemu_strtol()

- Patch 28 ('sheepdog: Support .bdrv_co_create'):
  Renamed 'backing_file' to 'backing-file', rebased on top of
  preallocated truncate


git-backport-diff compared to v1:

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

001/36:[0001] [FC] 'block/qapi: Introduce BlockdevCreateOptions'
002/36:[----] [-C] 'block/qapi: Add qcow2 create options to schema'
003/36:[----] [--] 'qcow2: Let qcow2_create() handle protocol layer'
004/36:[----] [--] 'qcow2: Pass BlockdevCreateOptions to qcow2_create2()'
005/36:[----] [-C] 'qcow2: Use BlockdevRef in qcow2_create2()'
006/36:[----] [--] 'qcow2: Use QCryptoBlockCreateOptions in qcow2_create2()'
007/36:[----] [--] 'qcow2: Handle full/falloc preallocation in qcow2_create2()'
008/36:[0007] [FC] 'util: Add qemu_opts_to_qdict_filtered()'
009/36:[down] 'test-qemu-opts: Test qemu_opts_append()'
010/36:[down] 'test-qemu-opts: Test qemu_opts_to_qdict_filtered()'
011/36:[0117] [FC] 'qdict: Introduce qdict_rename_keys()'
012/36:[0002] [FC] 'qcow2: Use visitor for options in qcow2_create()'
013/36:[down] 'block: Make bdrv_is_whitelisted() public'
014/36:[0006] [FC] 'block: x-blockdev-create QMP command'
015/36:[----] [-C] 'file-posix: Support .bdrv_co_create'
016/36:[----] [--] 'file-win32: Support .bdrv_co_create'
017/36:[0130] [FC] 'gluster: Support .bdrv_co_create'
018/36:[down] 'rbd: Fix use after free in qemu_rbd_set_keypairs() error path'
019/36:[down] 'rbd: Factor out qemu_rbd_connect()'
020/36:[down] 'rbd: Remove non-schema options from runtime_opts'
021/36:[down] 'rbd: Pass BlockdevOptionsRbd to qemu_rbd_connect()'
022/36:[0034] [FC] 'rbd: Support .bdrv_co_create'
023/36:[down] 'rbd: Assing s->snap/image_name in qemu_rbd_open()'
024/36:[down] 'rbd: Use qemu_rbd_connect() in qemu_rbd_do_create()'
025/36:[0002] [FC] 'nfs: Use QAPI options in nfs_client_open()'
026/36:[----] [-C] 'nfs: Support .bdrv_co_create'
027/36:[0013] [FC] 'sheepdog: QAPIfy "redundacy" create option'
028/36:[0049] [FC] 'sheepdog: Support .bdrv_co_create'
029/36:[----] [-C] 'ssh: Use QAPI BlockdevOptionsSsh object'
030/36:[----] [-C] 'ssh: QAPIfy host-key-check option'
031/36:[----] [--] 'ssh: Pass BlockdevOptionsSsh to connect_to_ssh()'
032/36:[----] [--] 'ssh: Support .bdrv_co_create'
033/36:[----] [--] 'file-posix: Fix no-op bdrv_truncate() with falloc preallocation'
034/36:[----] [--] 'block: Fail bdrv_truncate() with negative size'
035/36:[----] [--] 'qemu-iotests: Test qcow2 over file image creation with QMP'
036/36:[----] [--] 'qemu-iotests: Test ssh image creation over QMP'


Kevin Wolf (36):
  block/qapi: Introduce BlockdevCreateOptions
  block/qapi: Add qcow2 create options to schema
  qcow2: Let qcow2_create() handle protocol layer
  qcow2: Pass BlockdevCreateOptions to qcow2_create2()
  qcow2: Use BlockdevRef in qcow2_create2()
  qcow2: Use QCryptoBlockCreateOptions in qcow2_create2()
  qcow2: Handle full/falloc preallocation in qcow2_create2()
  util: Add qemu_opts_to_qdict_filtered()
  test-qemu-opts: Test qemu_opts_append()
  test-qemu-opts: Test qemu_opts_to_qdict_filtered()
  qdict: Introduce qdict_rename_keys()
  qcow2: Use visitor for options in qcow2_create()
  block: Make bdrv_is_whitelisted() public
  block: x-blockdev-create QMP command
  file-posix: Support .bdrv_co_create
  file-win32: Support .bdrv_co_create
  gluster: Support .bdrv_co_create
  rbd: Fix use after free in qemu_rbd_set_keypairs() error path
  rbd: Factor out qemu_rbd_connect()
  rbd: Remove non-schema options from runtime_opts
  rbd: Pass BlockdevOptionsRbd to qemu_rbd_connect()
  rbd: Support .bdrv_co_create
  rbd: Assing s->snap/image_name in qemu_rbd_open()
  rbd: Use qemu_rbd_connect() in qemu_rbd_do_create()
  nfs: Use QAPI options in nfs_client_open()
  nfs: Support .bdrv_co_create
  sheepdog: QAPIfy "redundacy" create option
  sheepdog: Support .bdrv_co_create
  ssh: Use QAPI BlockdevOptionsSsh object
  ssh: QAPIfy host-key-check option
  ssh: Pass BlockdevOptionsSsh to connect_to_ssh()
  ssh: Support .bdrv_co_create
  file-posix: Fix no-op bdrv_truncate() with falloc preallocation
  block: Fail bdrv_truncate() with negative size
  qemu-iotests: Test qcow2 over file image creation with QMP
  qemu-iotests: Test ssh image creation over QMP

 qapi/block-core.json       | 326 ++++++++++++++++++++++++++++++++-
 include/block/block.h      |   2 +
 include/block/block_int.h  |   2 +
 include/qapi/qmp/qdict.h   |   6 +
 include/qemu/option.h      |   2 +
 block.c                    |  54 +++++-
 block/create.c             |  76 ++++++++
 block/file-posix.c         |  91 +++++++---
 block/file-win32.c         |  45 ++++-
 block/gluster.c            | 135 +++++++++-----
 block/nfs.c                | 236 +++++++++++-------------
 block/qcow2.c              | 384 +++++++++++++++++++++++++--------------
 block/rbd.c                | 380 +++++++++++++++++++++------------------
 block/sheepdog.c           | 318 +++++++++++++++++++++++----------
 block/ssh.c                | 298 +++++++++++++++++--------------
 qobject/qdict.c            |  34 ++++
 tests/check-qdict.c        | 113 ++++++++++++
 tests/test-qemu-opts.c     | 253 ++++++++++++++++++++++++++
 util/qemu-option.c         |  42 ++++-
 block/Makefile.objs        |   2 +-
 tests/qemu-iotests/049.out |   8 +-
 tests/qemu-iotests/112.out |   4 +-
 tests/qemu-iotests/206     | 436 +++++++++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/206.out | 209 ++++++++++++++++++++++
 tests/qemu-iotests/207     | 261 +++++++++++++++++++++++++++
 tests/qemu-iotests/207.out |  75 ++++++++
 tests/qemu-iotests/group   |   2 +
 27 files changed, 3030 insertions(+), 764 deletions(-)
 create mode 100644 block/create.c
 create mode 100755 tests/qemu-iotests/206
 create mode 100644 tests/qemu-iotests/206.out
 create mode 100755 tests/qemu-iotests/207
 create mode 100644 tests/qemu-iotests/207.out

-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 01/36] block/qapi: Introduce BlockdevCreateOptions
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 02/36] block/qapi: Add qcow2 create options to schema Kevin Wolf
                   ` (34 subsequent siblings)
  35 siblings, 0 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

This creates a BlockdevCreateOptions union type that will contain all of
the options for image creation. We'll start out with an empty struct
type BlockdevCreateNotSupported for all drivers.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 qapi/block-core.json | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 5c5921bfb7..d256cefc79 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3359,6 +3359,68 @@
 { 'command': 'blockdev-del', 'data': { 'node-name': 'str' } }
 
 ##
+# @BlockdevCreateNotSupported:
+#
+# This is used for all drivers that don't support creating images.
+#
+# Since: 2.12
+##
+{ 'struct': 'BlockdevCreateNotSupported', 'data': {}}
+
+##
+# @BlockdevCreateOptions:
+#
+# Options for creating an image format on a given node.
+#
+# @driver           block driver to create the image format
+#
+# Since: 2.12
+##
+{ 'union': 'BlockdevCreateOptions',
+  'base': {
+      'driver':         'BlockdevDriver' },
+  'discriminator': 'driver',
+  'data': {
+      'blkdebug':       'BlockdevCreateNotSupported',
+      'blkverify':      'BlockdevCreateNotSupported',
+      'bochs':          'BlockdevCreateNotSupported',
+      'cloop':          'BlockdevCreateNotSupported',
+      'dmg':            'BlockdevCreateNotSupported',
+      'file':           'BlockdevCreateNotSupported',
+      'ftp':            'BlockdevCreateNotSupported',
+      'ftps':           'BlockdevCreateNotSupported',
+      'gluster':        'BlockdevCreateNotSupported',
+      'host_cdrom':     'BlockdevCreateNotSupported',
+      'host_device':    'BlockdevCreateNotSupported',
+      'http':           'BlockdevCreateNotSupported',
+      'https':          'BlockdevCreateNotSupported',
+      'iscsi':          'BlockdevCreateNotSupported',
+      'luks':           'BlockdevCreateNotSupported',
+      'nbd':            'BlockdevCreateNotSupported',
+      'nfs':            'BlockdevCreateNotSupported',
+      'null-aio':       'BlockdevCreateNotSupported',
+      'null-co':        'BlockdevCreateNotSupported',
+      'nvme':           'BlockdevCreateNotSupported',
+      'parallels':      'BlockdevCreateNotSupported',
+      'qcow2':          'BlockdevCreateNotSupported',
+      'qcow':           'BlockdevCreateNotSupported',
+      'qed':            'BlockdevCreateNotSupported',
+      'quorum':         'BlockdevCreateNotSupported',
+      'raw':            'BlockdevCreateNotSupported',
+      'rbd':            'BlockdevCreateNotSupported',
+      'replication':    'BlockdevCreateNotSupported',
+      'sheepdog':       'BlockdevCreateNotSupported',
+      'ssh':            'BlockdevCreateNotSupported',
+      'throttle':       'BlockdevCreateNotSupported',
+      'vdi':            'BlockdevCreateNotSupported',
+      'vhdx':           'BlockdevCreateNotSupported',
+      'vmdk':           'BlockdevCreateNotSupported',
+      'vpc':            'BlockdevCreateNotSupported',
+      'vvfat':          'BlockdevCreateNotSupported',
+      'vxhs':           'BlockdevCreateNotSupported'
+  } }
+
+##
 # @blockdev-open-tray:
 #
 # Opens a block device's tray. If there is a block driver state tree inserted as
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 02/36] block/qapi: Add qcow2 create options to schema
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 01/36] block/qapi: Introduce BlockdevCreateOptions Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 03/36] qcow2: Let qcow2_create() handle protocol layer Kevin Wolf
                   ` (33 subsequent siblings)
  35 siblings, 0 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 qapi/block-core.json | 45 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 44 insertions(+), 1 deletion(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index d256cefc79..74b864d64e 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3359,6 +3359,49 @@
 { 'command': 'blockdev-del', 'data': { 'node-name': 'str' } }
 
 ##
+# @BlockdevQcow2Version:
+#
+# @v2:  The original QCOW2 format as introduced in qemu 0.10 (version 2)
+# @v3:  The extended QCOW2 format as introduced in qemu 1.1 (version 3)
+#
+# Since: 2.12
+##
+{ 'enum': 'BlockdevQcow2Version',
+  'data': [ 'v2', 'v3' ] }
+
+
+##
+# @BlockdevCreateOptionsQcow2:
+#
+# Driver specific image creation options for qcow2.
+#
+# @file             Node to create the image format on
+# @size             Size of the virtual disk in bytes
+# @version          Compatibility level (default: v3)
+# @backing-file     File name of the backing file if a backing file
+#                   should be used
+# @backing-fmt      Name of the block driver to use for the backing file
+# @encrypt          Encryption options if the image should be encrypted
+# @cluster-size     qcow2 cluster size in bytes (default: 65536)
+# @preallocation    Preallocation mode for the new image (default: off)
+# @lazy-refcounts   True if refcounts may be updated lazily (default: off)
+# @refcount-bits    Width of reference counts in bits (default: 16)
+#
+# Since: 2.12
+##
+{ 'struct': 'BlockdevCreateOptionsQcow2',
+  'data': { 'file':             'BlockdevRef',
+            'size':             'size',
+            '*version':         'BlockdevQcow2Version',
+            '*backing-file':    'str',
+            '*backing-fmt':     'BlockdevDriver',
+            '*encrypt':         'QCryptoBlockCreateOptions',
+            '*cluster-size':    'size',
+            '*preallocation':   'PreallocMode',
+            '*lazy-refcounts':  'bool',
+            '*refcount-bits':   'int' } }
+
+##
 # @BlockdevCreateNotSupported:
 #
 # This is used for all drivers that don't support creating images.
@@ -3402,7 +3445,7 @@
       'null-co':        'BlockdevCreateNotSupported',
       'nvme':           'BlockdevCreateNotSupported',
       'parallels':      'BlockdevCreateNotSupported',
-      'qcow2':          'BlockdevCreateNotSupported',
+      'qcow2':          'BlockdevCreateOptionsQcow2',
       'qcow':           'BlockdevCreateNotSupported',
       'qed':            'BlockdevCreateNotSupported',
       'quorum':         'BlockdevCreateNotSupported',
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 03/36] qcow2: Let qcow2_create() handle protocol layer
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 01/36] block/qapi: Introduce BlockdevCreateOptions Kevin Wolf
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 02/36] block/qapi: Add qcow2 create options to schema Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 04/36] qcow2: Pass BlockdevCreateOptions to qcow2_create2() Kevin Wolf
                   ` (32 subsequent siblings)
  35 siblings, 0 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

Currently, qcow2_create() only parses the QemuOpts and then calls
qcow2_create2() for the actual image creation, which includes both the
creation of the actual file on the file system and writing a valid empty
qcow2 image into that file.

The plan is that qcow2_create2() becomes the function that implements
the functionality for a future 'blockdev-create' QMP command, which only
creates the qcow2 layer on an already opened file node.

This is a first step towards that goal: Let's move out anything that
deals with the protocol layer from qcow2_create2() into qcow2_create().
This means that qcow2_create2() doesn't need a file name any more.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 block/qcow2.c | 64 +++++++++++++++++++++++++++++++++++------------------------
 1 file changed, 38 insertions(+), 26 deletions(-)

diff --git a/block/qcow2.c b/block/qcow2.c
index 288b5299d8..dc6cdea113 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -2725,7 +2725,7 @@ static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version,
     return refcount_bits;
 }
 
-static int qcow2_create2(const char *filename, int64_t total_size,
+static int qcow2_create2(BlockDriverState *bs, int64_t total_size,
                          const char *backing_file, const char *backing_format,
                          int flags, size_t cluster_size, PreallocMode prealloc,
                          QemuOpts *opts, int version, int refcount_order,
@@ -2751,28 +2751,11 @@ static int qcow2_create2(const char *filename, int64_t total_size,
     Error *local_err = NULL;
     int ret;
 
-    if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) {
-        int64_t prealloc_size =
-            qcow2_calc_prealloc_size(total_size, cluster_size, refcount_order);
-        qemu_opt_set_number(opts, BLOCK_OPT_SIZE, prealloc_size, &error_abort);
-        qemu_opt_set(opts, BLOCK_OPT_PREALLOC, PreallocMode_str(prealloc),
-                     &error_abort);
-    }
-
-    ret = bdrv_create_file(filename, opts, &local_err);
+    blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
+    ret = blk_insert_bs(blk, bs, errp);
     if (ret < 0) {
-        error_propagate(errp, local_err);
-        return ret;
-    }
-
-    blk = blk_new_open(filename, NULL, NULL,
-                       BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
-                       &local_err);
-    if (blk == NULL) {
-        error_propagate(errp, local_err);
-        return -EIO;
+        goto out;
     }
-
     blk_set_allow_write_beyond_eof(blk, true);
 
     /* Write the header */
@@ -2827,7 +2810,8 @@ static int qcow2_create2(const char *filename, int64_t total_size,
      */
     options = qdict_new();
     qdict_put_str(options, "driver", "qcow2");
-    blk = blk_new_open(filename, NULL, options,
+    qdict_put_str(options, "file", bs->node_name);
+    blk = blk_new_open(NULL, NULL, options,
                        BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_NO_FLUSH,
                        &local_err);
     if (blk == NULL) {
@@ -2899,7 +2883,8 @@ static int qcow2_create2(const char *filename, int64_t total_size,
      */
     options = qdict_new();
     qdict_put_str(options, "driver", "qcow2");
-    blk = blk_new_open(filename, NULL, options,
+    qdict_put_str(options, "file", bs->node_name);
+    blk = blk_new_open(NULL, NULL, options,
                        BDRV_O_RDWR | BDRV_O_NO_BACKING | BDRV_O_NO_IO,
                        &local_err);
     if (blk == NULL) {
@@ -2929,6 +2914,7 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
     uint64_t refcount_bits;
     int refcount_order;
     char *encryptfmt = NULL;
+    BlockDriverState *bs = NULL;
     Error *local_err = NULL;
     int ret;
 
@@ -2997,12 +2983,38 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
 
     refcount_order = ctz32(refcount_bits);
 
-    ret = qcow2_create2(filename, size, backing_file, backing_fmt, flags,
+    /* Create and open the file (protocol layer) */
+    if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) {
+        int64_t prealloc_size =
+            qcow2_calc_prealloc_size(size, cluster_size, refcount_order);
+        qemu_opt_set_number(opts, BLOCK_OPT_SIZE, prealloc_size, &error_abort);
+        qemu_opt_set(opts, BLOCK_OPT_PREALLOC, PreallocMode_str(prealloc),
+                     &error_abort);
+    }
+
+    ret = bdrv_create_file(filename, opts, errp);
+    if (ret < 0) {
+        goto finish;
+    }
+
+    bs = bdrv_open(filename, NULL, NULL,
+                   BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
+    if (bs == NULL) {
+        ret = -EIO;
+        goto finish;
+    }
+
+    /* Create the qcow2 image (format layer) */
+    ret = qcow2_create2(bs, size, backing_file, backing_fmt, flags,
                         cluster_size, prealloc, opts, version, refcount_order,
-                        encryptfmt, &local_err);
-    error_propagate(errp, local_err);
+                        encryptfmt, errp);
+    if (ret < 0) {
+        goto finish;
+    }
 
 finish:
+    bdrv_unref(bs);
+
     g_free(backing_file);
     g_free(backing_fmt);
     g_free(encryptfmt);
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 04/36] qcow2: Pass BlockdevCreateOptions to qcow2_create2()
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (2 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 03/36] qcow2: Let qcow2_create() handle protocol layer Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 05/36] qcow2: Use BlockdevRef in qcow2_create2() Kevin Wolf
                   ` (31 subsequent siblings)
  35 siblings, 0 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

All of the simple options are now passed to qcow2_create2() in a
BlockdevCreateOptions object. Still missing: node-name and the
encryption options.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 block/qcow2.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 152 insertions(+), 38 deletions(-)

diff --git a/block/qcow2.c b/block/qcow2.c
index dc6cdea113..22194180c6 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -2665,19 +2665,26 @@ static int64_t qcow2_calc_prealloc_size(int64_t total_size,
     return meta_size + aligned_total_size;
 }
 
-static size_t qcow2_opt_get_cluster_size_del(QemuOpts *opts, Error **errp)
+static bool validate_cluster_size(size_t cluster_size, Error **errp)
 {
-    size_t cluster_size;
-    int cluster_bits;
-
-    cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE,
-                                         DEFAULT_CLUSTER_SIZE);
-    cluster_bits = ctz32(cluster_size);
+    int cluster_bits = ctz32(cluster_size);
     if (cluster_bits < MIN_CLUSTER_BITS || cluster_bits > MAX_CLUSTER_BITS ||
         (1 << cluster_bits) != cluster_size)
     {
         error_setg(errp, "Cluster size must be a power of two between %d and "
                    "%dk", 1 << MIN_CLUSTER_BITS, 1 << (MAX_CLUSTER_BITS - 10));
+        return false;
+    }
+    return true;
+}
+
+static size_t qcow2_opt_get_cluster_size_del(QemuOpts *opts, Error **errp)
+{
+    size_t cluster_size;
+
+    cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE,
+                                         DEFAULT_CLUSTER_SIZE);
+    if (!validate_cluster_size(cluster_size, errp)) {
         return 0;
     }
     return cluster_size;
@@ -2725,12 +2732,11 @@ static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version,
     return refcount_bits;
 }
 
-static int qcow2_create2(BlockDriverState *bs, int64_t total_size,
-                         const char *backing_file, const char *backing_format,
-                         int flags, size_t cluster_size, PreallocMode prealloc,
-                         QemuOpts *opts, int version, int refcount_order,
-                         const char *encryptfmt, Error **errp)
+static int qcow2_create2(BlockDriverState *bs,
+                         BlockdevCreateOptions *create_options,
+                         QemuOpts *opts, const char *encryptfmt, Error **errp)
 {
+    BlockdevCreateOptionsQcow2 *qcow2_opts;
     QDict *options;
 
     /*
@@ -2747,10 +2753,92 @@ static int qcow2_create2(BlockDriverState *bs, int64_t total_size,
      */
     BlockBackend *blk;
     QCowHeader *header;
+    size_t cluster_size;
+    int version;
+    int refcount_order;
     uint64_t* refcount_table;
     Error *local_err = NULL;
     int ret;
 
+    /* Validate options and set default values */
+    assert(create_options->driver == BLOCKDEV_DRIVER_QCOW2);
+    qcow2_opts = &create_options->u.qcow2;
+
+    if (!QEMU_IS_ALIGNED(qcow2_opts->size, BDRV_SECTOR_SIZE)) {
+        error_setg(errp, "Image size must be a multiple of 512 bytes");
+        ret = -EINVAL;
+        goto out;
+    }
+
+    if (qcow2_opts->has_version) {
+        switch (qcow2_opts->version) {
+        case BLOCKDEV_QCOW2_VERSION_V2:
+            version = 2;
+            break;
+        case BLOCKDEV_QCOW2_VERSION_V3:
+            version = 3;
+            break;
+        default:
+            g_assert_not_reached();
+        }
+    } else {
+        version = 3;
+    }
+
+    if (qcow2_opts->has_cluster_size) {
+        cluster_size = qcow2_opts->cluster_size;
+    } else {
+        cluster_size = DEFAULT_CLUSTER_SIZE;
+    }
+
+    if (!validate_cluster_size(cluster_size, errp)) {
+        return -EINVAL;
+    }
+
+    if (!qcow2_opts->has_preallocation) {
+        qcow2_opts->preallocation = PREALLOC_MODE_OFF;
+    }
+    if (qcow2_opts->has_backing_file &&
+        qcow2_opts->preallocation != PREALLOC_MODE_OFF)
+    {
+        error_setg(errp, "Backing file and preallocation cannot be used at "
+                   "the same time");
+        return -EINVAL;
+    }
+    if (qcow2_opts->has_backing_fmt && !qcow2_opts->has_backing_file) {
+        error_setg(errp, "Backing format cannot be used without backing file");
+        return -EINVAL;
+    }
+
+    if (!qcow2_opts->has_lazy_refcounts) {
+        qcow2_opts->lazy_refcounts = false;
+    }
+    if (version < 3 && qcow2_opts->lazy_refcounts) {
+        error_setg(errp, "Lazy refcounts only supported with compatibility "
+                   "level 1.1 and above (use compat=1.1 or greater)");
+        return -EINVAL;
+    }
+
+    if (!qcow2_opts->has_refcount_bits) {
+        qcow2_opts->refcount_bits = 16;
+    }
+    if (qcow2_opts->refcount_bits > 64 ||
+        !is_power_of_2(qcow2_opts->refcount_bits))
+    {
+        error_setg(errp, "Refcount width must be a power of two and may not "
+                   "exceed 64 bits");
+        return -EINVAL;
+    }
+    if (version < 3 && qcow2_opts->refcount_bits != 16) {
+        error_setg(errp, "Different refcount widths than 16 bits require "
+                   "compatibility level 1.1 or above (use compat=1.1 or "
+                   "greater)");
+        return -EINVAL;
+    }
+    refcount_order = ctz32(qcow2_opts->refcount_bits);
+
+
+    /* Create BlockBackend to write to the image */
     blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
     ret = blk_insert_bs(blk, bs, errp);
     if (ret < 0) {
@@ -2777,7 +2865,7 @@ static int qcow2_create2(BlockDriverState *bs, int64_t total_size,
     /* We'll update this to correct value later */
     header->crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
 
-    if (flags & BLOCK_FLAG_LAZY_REFCOUNTS) {
+    if (qcow2_opts->lazy_refcounts) {
         header->compatible_features |=
             cpu_to_be64(QCOW2_COMPAT_LAZY_REFCOUNTS);
     }
@@ -2839,18 +2927,26 @@ static int qcow2_create2(BlockDriverState *bs, int64_t total_size,
     }
 
     /* Okay, now that we have a valid image, let's give it the right size */
-    ret = blk_truncate(blk, total_size, PREALLOC_MODE_OFF, errp);
+    ret = blk_truncate(blk, qcow2_opts->size, PREALLOC_MODE_OFF, errp);
     if (ret < 0) {
         error_prepend(errp, "Could not resize image: ");
         goto out;
     }
 
     /* Want a backing file? There you go.*/
-    if (backing_file) {
-        ret = bdrv_change_backing_file(blk_bs(blk), backing_file, backing_format);
+    if (qcow2_opts->has_backing_file) {
+        const char *backing_format = NULL;
+
+        if (qcow2_opts->has_backing_fmt) {
+            backing_format = BlockdevDriver_str(qcow2_opts->backing_fmt);
+        }
+
+        ret = bdrv_change_backing_file(blk_bs(blk), qcow2_opts->backing_file,
+                                       backing_format);
         if (ret < 0) {
             error_setg_errno(errp, -ret, "Could not assign backing file '%s' "
-                             "with format '%s'", backing_file, backing_format);
+                             "with format '%s'", qcow2_opts->backing_file,
+                             backing_format);
             goto out;
         }
     }
@@ -2864,8 +2960,8 @@ static int qcow2_create2(BlockDriverState *bs, int64_t total_size,
     }
 
     /* And if we're supposed to preallocate metadata, do that now */
-    if (prealloc != PREALLOC_MODE_OFF) {
-        ret = preallocate(blk_bs(blk), 0, total_size);
+    if (qcow2_opts->preallocation != PREALLOC_MODE_OFF) {
+        ret = preallocate(blk_bs(blk), 0, qcow2_opts->size);
         if (ret < 0) {
             error_setg_errno(errp, -ret, "Could not preallocate metadata");
             goto out;
@@ -2903,8 +2999,10 @@ out:
 
 static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
 {
+    BlockdevCreateOptions create_options;
     char *backing_file = NULL;
     char *backing_fmt = NULL;
+    BlockdevDriver backing_drv;
     char *buf = NULL;
     uint64_t size = 0;
     int flags = 0;
@@ -2912,7 +3010,6 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
     PreallocMode prealloc;
     int version;
     uint64_t refcount_bits;
-    int refcount_order;
     char *encryptfmt = NULL;
     BlockDriverState *bs = NULL;
     Error *local_err = NULL;
@@ -2923,6 +3020,13 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
                     BDRV_SECTOR_SIZE);
     backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
     backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT);
+    backing_drv = qapi_enum_parse(&BlockdevDriver_lookup, backing_fmt,
+                                  0, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        ret = -EINVAL;
+        goto finish;
+    }
     encryptfmt = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT);
     if (encryptfmt) {
         if (qemu_opt_get(opts, BLOCK_OPT_ENCRYPT)) {
@@ -2960,20 +3064,6 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
         flags |= BLOCK_FLAG_LAZY_REFCOUNTS;
     }
 
-    if (backing_file && prealloc != PREALLOC_MODE_OFF) {
-        error_setg(errp, "Backing file and preallocation cannot be used at "
-                   "the same time");
-        ret = -EINVAL;
-        goto finish;
-    }
-
-    if (version < 3 && (flags & BLOCK_FLAG_LAZY_REFCOUNTS)) {
-        error_setg(errp, "Lazy refcounts only supported with compatibility "
-                   "level 1.1 and above (use compat=1.1 or greater)");
-        ret = -EINVAL;
-        goto finish;
-    }
-
     refcount_bits = qcow2_opt_get_refcount_bits_del(opts, version, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
@@ -2981,10 +3071,10 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
         goto finish;
     }
 
-    refcount_order = ctz32(refcount_bits);
 
     /* Create and open the file (protocol layer) */
     if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) {
+        int refcount_order = ctz32(refcount_bits);
         int64_t prealloc_size =
             qcow2_calc_prealloc_size(size, cluster_size, refcount_order);
         qemu_opt_set_number(opts, BLOCK_OPT_SIZE, prealloc_size, &error_abort);
@@ -3005,9 +3095,33 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
     }
 
     /* Create the qcow2 image (format layer) */
-    ret = qcow2_create2(bs, size, backing_file, backing_fmt, flags,
-                        cluster_size, prealloc, opts, version, refcount_order,
-                        encryptfmt, errp);
+    create_options = (BlockdevCreateOptions) {
+        .driver         = BLOCKDEV_DRIVER_QCOW2,
+        .u.qcow2        = {
+            .file               = &(BlockdevRef) {
+                .type               = QTYPE_QSTRING,
+                .u.reference        = bs->node_name,
+            },
+            .size               = size,
+            .has_version        = true,
+            .version            = version == 2
+                                  ? BLOCKDEV_QCOW2_VERSION_V2
+                                  : BLOCKDEV_QCOW2_VERSION_V3,
+            .has_backing_file   = (backing_file != NULL),
+            .backing_file       = backing_file,
+            .has_backing_fmt    = (backing_fmt != NULL),
+            .backing_fmt        = backing_drv,
+            .has_cluster_size   = true,
+            .cluster_size       = cluster_size,
+            .has_preallocation  = true,
+            .preallocation      = prealloc,
+            .has_lazy_refcounts = true,
+            .lazy_refcounts     = (flags & BLOCK_FLAG_LAZY_REFCOUNTS),
+            .has_refcount_bits  = true,
+            .refcount_bits      = refcount_bits,
+        },
+    };
+    ret = qcow2_create2(bs, &create_options, opts, encryptfmt, errp);
     if (ret < 0) {
         goto finish;
     }
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 05/36] qcow2: Use BlockdevRef in qcow2_create2()
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (3 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 04/36] qcow2: Pass BlockdevCreateOptions to qcow2_create2() Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 06/36] qcow2: Use QCryptoBlockCreateOptions " Kevin Wolf
                   ` (30 subsequent siblings)
  35 siblings, 0 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

Instead of passing a separate BlockDriverState* into qcow2_create2(),
make use of the BlockdevRef that is included in BlockdevCreateOptions.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 include/block/block.h |  1 +
 block.c               | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 block/qcow2.c         | 38 ++++++++++++++++++++++++--------------
 3 files changed, 72 insertions(+), 14 deletions(-)

diff --git a/include/block/block.h b/include/block/block.h
index 947e8876cd..54fe8b7a0e 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -245,6 +245,7 @@ BdrvChild *bdrv_open_child(const char *filename,
                            BlockDriverState* parent,
                            const BdrvChildRole *child_role,
                            bool allow_none, Error **errp);
+BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp);
 void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
                          Error **errp);
 int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
diff --git a/block.c b/block.c
index 814e5a02da..c0e343d278 100644
--- a/block.c
+++ b/block.c
@@ -35,6 +35,8 @@
 #include "qapi/qmp/qerror.h"
 #include "qapi/qmp/qjson.h"
 #include "qapi/qmp/qstring.h"
+#include "qapi/qobject-output-visitor.h"
+#include "qapi-visit.h"
 #include "sysemu/block-backend.h"
 #include "sysemu/sysemu.h"
 #include "qemu/notify.h"
@@ -2408,6 +2410,51 @@ BdrvChild *bdrv_open_child(const char *filename,
     return c;
 }
 
+/* TODO Future callers may need to specify parent/child_role in order for
+ * option inheritance to work. Existing callers use it for the root node. */
+BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp)
+{
+    BlockDriverState *bs = NULL;
+    Error *local_err = NULL;
+    QObject *obj = NULL;
+    QDict *qdict = NULL;
+    const char *reference = NULL;
+    Visitor *v = NULL;
+
+    if (ref->type == QTYPE_QSTRING) {
+        reference = ref->u.reference;
+    } else {
+        BlockdevOptions *options = &ref->u.definition;
+        assert(ref->type == QTYPE_QDICT);
+
+        v = qobject_output_visitor_new(&obj);
+        visit_type_BlockdevOptions(v, NULL, &options, &local_err);
+        if (local_err) {
+            error_propagate(errp, local_err);
+            goto fail;
+        }
+        visit_complete(v, &obj);
+
+        qdict = qobject_to_qdict(obj);
+        qdict_flatten(qdict);
+
+        /* bdrv_open_inherit() defaults to the values in bdrv_flags (for
+         * compatibility with other callers) rather than what we want as the
+         * real defaults. Apply the defaults here instead. */
+        qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
+        qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
+        qdict_set_default_str(qdict, BDRV_OPT_READ_ONLY, "off");
+    }
+
+    bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, errp);
+    obj = NULL;
+
+fail:
+    qobject_decref(obj);
+    visit_free(v);
+    return bs;
+}
+
 static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
                                                    int flags,
                                                    QDict *snapshot_options,
diff --git a/block/qcow2.c b/block/qcow2.c
index 22194180c6..b34924b0f0 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -2732,8 +2732,7 @@ static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version,
     return refcount_bits;
 }
 
-static int qcow2_create2(BlockDriverState *bs,
-                         BlockdevCreateOptions *create_options,
+static int qcow2_create2(BlockdevCreateOptions *create_options,
                          QemuOpts *opts, const char *encryptfmt, Error **errp)
 {
     BlockdevCreateOptionsQcow2 *qcow2_opts;
@@ -2751,7 +2750,8 @@ static int qcow2_create2(BlockDriverState *bs,
      * 2 GB for 64k clusters, and we don't want to have a 2 GB initial file
      * size for any qcow2 image.
      */
-    BlockBackend *blk;
+    BlockBackend *blk = NULL;
+    BlockDriverState *bs = NULL;
     QCowHeader *header;
     size_t cluster_size;
     int version;
@@ -2760,10 +2760,15 @@ static int qcow2_create2(BlockDriverState *bs,
     Error *local_err = NULL;
     int ret;
 
-    /* Validate options and set default values */
     assert(create_options->driver == BLOCKDEV_DRIVER_QCOW2);
     qcow2_opts = &create_options->u.qcow2;
 
+    bs = bdrv_open_blockdev_ref(qcow2_opts->file, errp);
+    if (bs == NULL) {
+        return -EIO;
+    }
+
+    /* Validate options and set default values */
     if (!QEMU_IS_ALIGNED(qcow2_opts->size, BDRV_SECTOR_SIZE)) {
         error_setg(errp, "Image size must be a multiple of 512 bytes");
         ret = -EINVAL;
@@ -2792,7 +2797,8 @@ static int qcow2_create2(BlockDriverState *bs,
     }
 
     if (!validate_cluster_size(cluster_size, errp)) {
-        return -EINVAL;
+        ret = -EINVAL;
+        goto out;
     }
 
     if (!qcow2_opts->has_preallocation) {
@@ -2803,11 +2809,13 @@ static int qcow2_create2(BlockDriverState *bs,
     {
         error_setg(errp, "Backing file and preallocation cannot be used at "
                    "the same time");
-        return -EINVAL;
+        ret = -EINVAL;
+        goto out;
     }
     if (qcow2_opts->has_backing_fmt && !qcow2_opts->has_backing_file) {
         error_setg(errp, "Backing format cannot be used without backing file");
-        return -EINVAL;
+        ret = -EINVAL;
+        goto out;
     }
 
     if (!qcow2_opts->has_lazy_refcounts) {
@@ -2816,7 +2824,8 @@ static int qcow2_create2(BlockDriverState *bs,
     if (version < 3 && qcow2_opts->lazy_refcounts) {
         error_setg(errp, "Lazy refcounts only supported with compatibility "
                    "level 1.1 and above (use compat=1.1 or greater)");
-        return -EINVAL;
+        ret = -EINVAL;
+        goto out;
     }
 
     if (!qcow2_opts->has_refcount_bits) {
@@ -2827,13 +2836,15 @@ static int qcow2_create2(BlockDriverState *bs,
     {
         error_setg(errp, "Refcount width must be a power of two and may not "
                    "exceed 64 bits");
-        return -EINVAL;
+        ret = -EINVAL;
+        goto out;
     }
     if (version < 3 && qcow2_opts->refcount_bits != 16) {
         error_setg(errp, "Different refcount widths than 16 bits require "
                    "compatibility level 1.1 or above (use compat=1.1 or "
                    "greater)");
-        return -EINVAL;
+        ret = -EINVAL;
+        goto out;
     }
     refcount_order = ctz32(qcow2_opts->refcount_bits);
 
@@ -2991,9 +3002,8 @@ static int qcow2_create2(BlockDriverState *bs,
 
     ret = 0;
 out:
-    if (blk) {
-        blk_unref(blk);
-    }
+    blk_unref(blk);
+    bdrv_unref(bs);
     return ret;
 }
 
@@ -3121,7 +3131,7 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
             .refcount_bits      = refcount_bits,
         },
     };
-    ret = qcow2_create2(bs, &create_options, opts, encryptfmt, errp);
+    ret = qcow2_create2(&create_options, opts, encryptfmt, errp);
     if (ret < 0) {
         goto finish;
     }
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 06/36] qcow2: Use QCryptoBlockCreateOptions in qcow2_create2()
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (4 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 05/36] qcow2: Use BlockdevRef in qcow2_create2() Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 07/36] qcow2: Handle full/falloc preallocation " Kevin Wolf
                   ` (29 subsequent siblings)
  35 siblings, 0 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

Instead of passing the encryption format name and the QemuOpts down, use
the QCryptoBlockCreateOptions contained in BlockdevCreateOptions.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 block/qcow2.c | 62 +++++++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 45 insertions(+), 17 deletions(-)

diff --git a/block/qcow2.c b/block/qcow2.c
index b34924b0f0..9a2028b3cf 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -2414,13 +2414,10 @@ static int qcow2_crypt_method_from_format(const char *encryptfmt)
     }
 }
 
-static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
-                                   QemuOpts *opts, Error **errp)
+static QCryptoBlockCreateOptions *
+qcow2_parse_encryption(const char *encryptfmt, QemuOpts *opts, Error **errp)
 {
-    BDRVQcow2State *s = bs->opaque;
     QCryptoBlockCreateOptions *cryptoopts = NULL;
-    QCryptoBlock *crypto = NULL;
-    int ret = -EINVAL;
     QDict *options, *encryptopts;
     int fmt;
 
@@ -2443,10 +2440,31 @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
         error_setg(errp, "Unknown encryption format '%s'", encryptfmt);
         break;
     }
-    if (!cryptoopts) {
-        ret = -EINVAL;
-        goto out;
+
+    QDECREF(encryptopts);
+    return cryptoopts;
+}
+
+static int qcow2_set_up_encryption(BlockDriverState *bs,
+                                   QCryptoBlockCreateOptions *cryptoopts,
+                                   Error **errp)
+{
+    BDRVQcow2State *s = bs->opaque;
+    QCryptoBlock *crypto = NULL;
+    int fmt, ret;
+
+    switch (cryptoopts->format) {
+    case Q_CRYPTO_BLOCK_FORMAT_LUKS:
+        fmt = QCOW_CRYPT_LUKS;
+        break;
+    case Q_CRYPTO_BLOCK_FORMAT_QCOW:
+        fmt = QCOW_CRYPT_AES;
+        break;
+    default:
+        error_setg(errp, "Crypto format not supported in qcow2");
+        return -EINVAL;
     }
+
     s->crypt_method_header = fmt;
 
     crypto = qcrypto_block_create(cryptoopts, "encrypt.",
@@ -2454,8 +2472,7 @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
                                   qcow2_crypto_hdr_write_func,
                                   bs, errp);
     if (!crypto) {
-        ret = -EINVAL;
-        goto out;
+        return -EINVAL;
     }
 
     ret = qcow2_update_header(bs);
@@ -2464,10 +2481,9 @@ static int qcow2_set_up_encryption(BlockDriverState *bs, const char *encryptfmt,
         goto out;
     }
 
+    ret = 0;
  out:
-    QDECREF(encryptopts);
     qcrypto_block_free(crypto);
-    qapi_free_QCryptoBlockCreateOptions(cryptoopts);
     return ret;
 }
 
@@ -2732,8 +2748,7 @@ static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version,
     return refcount_bits;
 }
 
-static int qcow2_create2(BlockdevCreateOptions *create_options,
-                         QemuOpts *opts, const char *encryptfmt, Error **errp)
+static int qcow2_create2(BlockdevCreateOptions *create_options, Error **errp)
 {
     BlockdevCreateOptionsQcow2 *qcow2_opts;
     QDict *options;
@@ -2963,8 +2978,8 @@ static int qcow2_create2(BlockdevCreateOptions *create_options,
     }
 
     /* Want encryption? There you go. */
-    if (encryptfmt) {
-        ret = qcow2_set_up_encryption(blk_bs(blk), encryptfmt, opts, errp);
+    if (qcow2_opts->has_encrypt) {
+        ret = qcow2_set_up_encryption(blk_bs(blk), qcow2_opts->encrypt, errp);
         if (ret < 0) {
             goto out;
         }
@@ -3021,6 +3036,7 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
     int version;
     uint64_t refcount_bits;
     char *encryptfmt = NULL;
+    QCryptoBlockCreateOptions *cryptoopts = NULL;
     BlockDriverState *bs = NULL;
     Error *local_err = NULL;
     int ret;
@@ -3037,6 +3053,7 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
         ret = -EINVAL;
         goto finish;
     }
+
     encryptfmt = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT);
     if (encryptfmt) {
         if (qemu_opt_get(opts, BLOCK_OPT_ENCRYPT)) {
@@ -3048,6 +3065,14 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
     } else if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
         encryptfmt = g_strdup("aes");
     }
+    if (encryptfmt) {
+        cryptoopts = qcow2_parse_encryption(encryptfmt, opts, errp);
+        if (cryptoopts == NULL) {
+            ret = -EINVAL;
+            goto finish;
+        }
+    }
+
     cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
@@ -3121,6 +3146,8 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
             .backing_file       = backing_file,
             .has_backing_fmt    = (backing_fmt != NULL),
             .backing_fmt        = backing_drv,
+            .has_encrypt        = (encryptfmt != NULL),
+            .encrypt            = cryptoopts,
             .has_cluster_size   = true,
             .cluster_size       = cluster_size,
             .has_preallocation  = true,
@@ -3131,7 +3158,7 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
             .refcount_bits      = refcount_bits,
         },
     };
-    ret = qcow2_create2(&create_options, opts, encryptfmt, errp);
+    ret = qcow2_create2(&create_options, errp);
     if (ret < 0) {
         goto finish;
     }
@@ -3139,6 +3166,7 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
 finish:
     bdrv_unref(bs);
 
+    qapi_free_QCryptoBlockCreateOptions(cryptoopts);
     g_free(backing_file);
     g_free(backing_fmt);
     g_free(encryptfmt);
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 07/36] qcow2: Handle full/falloc preallocation in qcow2_create2()
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (5 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 06/36] qcow2: Use QCryptoBlockCreateOptions " Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 08/36] util: Add qemu_opts_to_qdict_filtered() Kevin Wolf
                   ` (28 subsequent siblings)
  35 siblings, 0 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

Once qcow2_create2() can be called directly on an already existing node,
we must provide the 'full' and 'falloc' preallocation modes outside of
creating the image on the protocol layer. Fortunately, we have
preallocated truncate now which can provide this functionality.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 block/qcow2.c | 28 +++++++++++++++++++---------
 1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/block/qcow2.c b/block/qcow2.c
index 9a2028b3cf..64bf2863cd 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -2872,6 +2872,25 @@ static int qcow2_create2(BlockdevCreateOptions *create_options, Error **errp)
     }
     blk_set_allow_write_beyond_eof(blk, true);
 
+    /* Clear the protocol layer and preallocate it if necessary */
+    ret = blk_truncate(blk, 0, PREALLOC_MODE_OFF, errp);
+    if (ret < 0) {
+        goto out;
+    }
+
+    if (qcow2_opts->preallocation == PREALLOC_MODE_FULL ||
+        qcow2_opts->preallocation == PREALLOC_MODE_FALLOC)
+    {
+        int64_t prealloc_size =
+            qcow2_calc_prealloc_size(qcow2_opts->size, cluster_size,
+                                     refcount_order);
+
+        ret = blk_truncate(blk, prealloc_size, qcow2_opts->preallocation, errp);
+        if (ret < 0) {
+            goto out;
+        }
+    }
+
     /* Write the header */
     QEMU_BUILD_BUG_ON((1 << MIN_CLUSTER_BITS) < sizeof(*header));
     header = g_malloc0(cluster_size);
@@ -3108,15 +3127,6 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
 
 
     /* Create and open the file (protocol layer) */
-    if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) {
-        int refcount_order = ctz32(refcount_bits);
-        int64_t prealloc_size =
-            qcow2_calc_prealloc_size(size, cluster_size, refcount_order);
-        qemu_opt_set_number(opts, BLOCK_OPT_SIZE, prealloc_size, &error_abort);
-        qemu_opt_set(opts, BLOCK_OPT_PREALLOC, PreallocMode_str(prealloc),
-                     &error_abort);
-    }
-
     ret = bdrv_create_file(filename, opts, errp);
     if (ret < 0) {
         goto finish;
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 08/36] util: Add qemu_opts_to_qdict_filtered()
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (6 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 07/36] qcow2: Handle full/falloc preallocation " Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-21 20:38   ` Eric Blake
  2018-02-22 22:03   ` Max Reitz
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 09/36] test-qemu-opts: Test qemu_opts_append() Kevin Wolf
                   ` (27 subsequent siblings)
  35 siblings, 2 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

This allows, given a QemuOpts for a QemuOptsList that was merged from
multiple QemuOptsList, to only consider those options that exist in one
specific list. Block drivers need this to separate format-layer create
options from protocol-level options.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 include/qemu/option.h |  2 ++
 util/qemu-option.c    | 42 +++++++++++++++++++++++++++++++++++++-----
 2 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/include/qemu/option.h b/include/qemu/option.h
index b127fb6db6..306fdb5f7a 100644
--- a/include/qemu/option.h
+++ b/include/qemu/option.h
@@ -124,6 +124,8 @@ void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
                             int permit_abbrev);
 QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
                                Error **errp);
+QDict *qemu_opts_to_qdict_filtered(QemuOpts *opts, QDict *qdict,
+                                   QemuOptsList *list, bool del);
 QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict);
 void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp);
 
diff --git a/util/qemu-option.c b/util/qemu-option.c
index a401e936da..2b412eff5e 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -1007,14 +1007,23 @@ void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp)
 }
 
 /*
- * Convert from QemuOpts to QDict.
- * The QDict values are of type QString.
+ * Convert from QemuOpts to QDict. The QDict values are of type QString.
+ *
+ * If @list is given, only add those options to the QDict that are contained in
+ * the list. If @del is true, any options added to the QDict are removed from
+ * the QemuOpts, otherwise they remain there.
+ *
+ * If two options in @opts have the same name, they are processed in order
+ * so that the last one wins (consistent with the reverse iteration in
+ * qemu_opt_find()), but all of them are deleted if @del is true.
+ *
  * TODO We'll want to use types appropriate for opt->desc->type, but
  * this is enough for now.
  */
-QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
+QDict *qemu_opts_to_qdict_filtered(QemuOpts *opts, QDict *qdict,
+                                   QemuOptsList *list, bool del)
 {
-    QemuOpt *opt;
+    QemuOpt *opt, *next;
 
     if (!qdict) {
         qdict = qdict_new();
@@ -1022,12 +1031,35 @@ QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
     if (opts->id) {
         qdict_put_str(qdict, "id", opts->id);
     }
-    QTAILQ_FOREACH(opt, &opts->head, next) {
+    QTAILQ_FOREACH_SAFE(opt, &opts->head, next, next) {
+        if (list) {
+            QemuOptDesc *desc;
+            bool found = false;
+            for (desc = list->desc; desc->name; desc++) {
+                if (!strcmp(desc->name, opt->name)) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                continue;
+            }
+        }
         qdict_put_str(qdict, opt->name, opt->str);
+        if (del) {
+            qemu_opt_del(opt);
+        }
     }
     return qdict;
 }
 
+/* Copy all options in a QemuOpts to the given QDict. See
+ * qemu_opts_to_qdict_filtered() for details. */
+QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
+{
+    return qemu_opts_to_qdict_filtered(opts, qdict, NULL, false);
+}
+
 /* Validate parsed opts against descriptions where no
  * descriptions were provided in the QemuOptsList.
  */
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 09/36] test-qemu-opts: Test qemu_opts_append()
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (7 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 08/36] util: Add qemu_opts_to_qdict_filtered() Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-21 20:53   ` Eric Blake
  2018-02-22 22:19   ` Max Reitz
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 10/36] test-qemu-opts: Test qemu_opts_to_qdict_filtered() Kevin Wolf
                   ` (26 subsequent siblings)
  35 siblings, 2 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

Basic test for merging two QemuOptsLists.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 tests/test-qemu-opts.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)

diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c
index 5d5a3daa7b..6c3183390b 100644
--- a/tests/test-qemu-opts.c
+++ b/tests/test-qemu-opts.c
@@ -23,6 +23,8 @@ static QemuOptsList opts_list_01 = {
         {
             .name = "str1",
             .type = QEMU_OPT_STRING,
+            .help = "Help texts are preserved in qemu_opts_append",
+            .def_value_str = "default",
         },{
             .name = "str2",
             .type = QEMU_OPT_STRING,
@@ -32,6 +34,7 @@ static QemuOptsList opts_list_01 = {
         },{
             .name = "number1",
             .type = QEMU_OPT_NUMBER,
+            .help = "Having help texts only for some options is okay",
         },{
             .name = "number2",
             .type = QEMU_OPT_NUMBER,
@@ -743,6 +746,129 @@ static void test_opts_parse_size(void)
     qemu_opts_reset(&opts_list_02);
 }
 
+static void append_verify_list_01(QemuOptDesc *desc, bool with_overlapping)
+{
+    int i = 0;
+
+    if (with_overlapping) {
+        g_assert_cmpstr(desc[i].name, ==, "str1");
+        g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
+        g_assert_cmpstr(desc[i].help, ==,
+                        "Help texts are preserved in qemu_opts_append");
+        g_assert_cmpstr(desc[i].def_value_str, ==, "default");
+        i++;
+
+        g_assert_cmpstr(desc[i].name, ==, "str2");
+        g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
+        g_assert_cmpstr(desc[i].help, ==, NULL);
+        g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+        i++;
+    }
+
+    g_assert_cmpstr(desc[i].name, ==, "str3");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
+    g_assert_cmpstr(desc[i].help, ==, NULL);
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+    i++;
+
+    g_assert_cmpstr(desc[i].name, ==, "number1");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_NUMBER);
+    g_assert_cmpstr(desc[i].help, ==,
+                    "Having help texts only for some options is okay");
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+    i++;
+
+    g_assert_cmpstr(desc[i].name, ==, "number2");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_NUMBER);
+    g_assert_cmpstr(desc[i].help, ==, NULL);
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+    i++;
+
+    g_assert_cmpstr(desc[i].name, ==, NULL);
+}
+
+static void append_verify_list_02(QemuOptDesc *desc)
+{
+    int i = 0;
+
+    g_assert_cmpstr(desc[i].name, ==, "str1");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
+    g_assert_cmpstr(desc[i].help, ==, NULL);
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+    i++;
+
+    g_assert_cmpstr(desc[i].name, ==, "str2");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_STRING);
+    g_assert_cmpstr(desc[i].help, ==, NULL);
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+    i++;
+
+    g_assert_cmpstr(desc[i].name, ==, "bool1");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_BOOL);
+    g_assert_cmpstr(desc[i].help, ==, NULL);
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+    i++;
+
+    g_assert_cmpstr(desc[i].name, ==, "bool2");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_BOOL);
+    g_assert_cmpstr(desc[i].help, ==, NULL);
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+    i++;
+
+    g_assert_cmpstr(desc[i].name, ==, "size1");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_SIZE);
+    g_assert_cmpstr(desc[i].help, ==, NULL);
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+    i++;
+
+    g_assert_cmpstr(desc[i].name, ==, "size2");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_SIZE);
+    g_assert_cmpstr(desc[i].help, ==, NULL);
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+    i++;
+
+    g_assert_cmpstr(desc[i].name, ==, "size3");
+    g_assert_cmpint(desc[i].type, ==, QEMU_OPT_SIZE);
+    g_assert_cmpstr(desc[i].help, ==, NULL);
+    g_assert_cmpstr(desc[i].def_value_str, ==, NULL);
+}
+
+static void test_opts_append_to_null(void)
+{
+    QemuOptsList *merged;
+
+    merged = qemu_opts_append(NULL, &opts_list_01);
+    g_assert(merged != &opts_list_01);
+
+    g_assert_cmpstr(merged->name, ==, NULL);
+    g_assert_cmpstr(merged->implied_opt_name, ==, NULL);
+    g_assert_false(merged->merge_lists);
+
+    append_verify_list_01(merged->desc, true);
+
+    qemu_opts_free(merged);
+}
+
+static void test_opts_append(void)
+{
+    QemuOptsList *first, *merged;
+
+    first = qemu_opts_append(NULL, &opts_list_02);
+    merged = qemu_opts_append(first, &opts_list_01);
+    g_assert(first != &opts_list_02);
+    g_assert(merged != &opts_list_01);
+
+    g_assert_cmpstr(merged->name, ==, NULL);
+    g_assert_cmpstr(merged->implied_opt_name, ==, NULL);
+    g_assert_false(merged->merge_lists);
+
+    append_verify_list_02(&merged->desc[0]);
+    append_verify_list_01(&merged->desc[7], false);
+
+    qemu_opts_free(merged);
+}
+
+
 int main(int argc, char *argv[])
 {
     register_opts();
@@ -761,6 +887,8 @@ int main(int argc, char *argv[])
     g_test_add_func("/qemu-opts/opts_parse/bool", test_opts_parse_bool);
     g_test_add_func("/qemu-opts/opts_parse/number", test_opts_parse_number);
     g_test_add_func("/qemu-opts/opts_parse/size", test_opts_parse_size);
+    g_test_add_func("/qemu-opts/append_to_null", test_opts_append_to_null);
+    g_test_add_func("/qemu-opts/append", test_opts_append);
     g_test_run();
     return 0;
 }
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 10/36] test-qemu-opts: Test qemu_opts_to_qdict_filtered()
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (8 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 09/36] test-qemu-opts: Test qemu_opts_append() Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-21 20:57   ` Eric Blake
  2018-02-22 22:26   ` Max Reitz
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 11/36] qdict: Introduce qdict_rename_keys() Kevin Wolf
                   ` (25 subsequent siblings)
  35 siblings, 2 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 tests/test-qemu-opts.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 125 insertions(+)

diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c
index 6c3183390b..2c422abcd4 100644
--- a/tests/test-qemu-opts.c
+++ b/tests/test-qemu-opts.c
@@ -10,6 +10,7 @@
 #include "qemu/osdep.h"
 #include "qemu/cutils.h"
 #include "qemu/option.h"
+#include "qemu/option_int.h"
 #include "qapi/error.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qstring.h"
@@ -868,6 +869,127 @@ static void test_opts_append(void)
     qemu_opts_free(merged);
 }
 
+static void test_opts_to_qdict_basic(void)
+{
+    QemuOpts *opts;
+    QDict *dict;
+
+    opts = qemu_opts_parse(&opts_list_01, "str1=foo,str2=,str3=bar,number1=42",
+                           false, &error_abort);
+    g_assert(opts != NULL);
+
+    dict = qemu_opts_to_qdict(opts, NULL);
+    g_assert(dict != NULL);
+
+    g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
+    g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
+    g_assert_cmpstr(qdict_get_str(dict, "str3"), ==, "bar");
+    g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42");
+    g_assert_false(qdict_haskey(dict, "number2"));
+
+    QDECREF(dict);
+    qemu_opts_del(opts);
+}
+
+static void test_opts_to_qdict_filtered(void)
+{
+    QemuOptsList *first, *merged;
+    QemuOpts *opts;
+    QDict *dict;
+
+    first = qemu_opts_append(NULL, &opts_list_02);
+    merged = qemu_opts_append(first, &opts_list_01);
+
+    opts = qemu_opts_parse(merged,
+                           "str1=foo,str2=,str3=bar,bool1=off,number1=42",
+                           false, &error_abort);
+    g_assert(opts != NULL);
+
+    /* Convert to QDict without deleting from opts */
+    dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_01, false);
+    g_assert(dict != NULL);
+    g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
+    g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
+    g_assert_cmpstr(qdict_get_str(dict, "str3"), ==, "bar");
+    g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42");
+    g_assert_false(qdict_haskey(dict, "number2"));
+    g_assert_false(qdict_haskey(dict, "bool1"));
+    QDECREF(dict);
+
+    dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_02, false);
+    g_assert(dict != NULL);
+    g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
+    g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
+    g_assert_cmpstr(qdict_get_str(dict, "bool1"), ==, "off");
+    g_assert_false(qdict_haskey(dict, "str3"));
+    g_assert_false(qdict_haskey(dict, "number1"));
+    g_assert_false(qdict_haskey(dict, "number2"));
+    QDECREF(dict);
+
+    /* Now delete converted options from opts */
+    dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_01, true);
+    g_assert(dict != NULL);
+    g_assert_cmpstr(qdict_get_str(dict, "str1"), ==, "foo");
+    g_assert_cmpstr(qdict_get_str(dict, "str2"), ==, "");
+    g_assert_cmpstr(qdict_get_str(dict, "str3"), ==, "bar");
+    g_assert_cmpstr(qdict_get_str(dict, "number1"), ==, "42");
+    g_assert_false(qdict_haskey(dict, "number2"));
+    g_assert_false(qdict_haskey(dict, "bool1"));
+    QDECREF(dict);
+
+    dict = qemu_opts_to_qdict_filtered(opts, NULL, &opts_list_02, true);
+    g_assert(dict != NULL);
+    g_assert_cmpstr(qdict_get_str(dict, "bool1"), ==, "off");
+    g_assert_false(qdict_haskey(dict, "str1"));
+    g_assert_false(qdict_haskey(dict, "str2"));
+    g_assert_false(qdict_haskey(dict, "str3"));
+    g_assert_false(qdict_haskey(dict, "number1"));
+    g_assert_false(qdict_haskey(dict, "number2"));
+    QDECREF(dict);
+
+    g_assert_true(QTAILQ_EMPTY(&opts->head));
+
+    qemu_opts_del(opts);
+    qemu_opts_free(merged);
+}
+
+static void test_opts_to_qdict_duplicates(void)
+{
+    QemuOpts *opts;
+    QemuOpt *opt;
+    QDict *dict;
+
+    opts = qemu_opts_parse(&opts_list_03, "foo=a,foo=b", false, &error_abort);
+    g_assert(opts != NULL);
+
+    /* Verify that opts has two options with the same name */
+    opt = QTAILQ_FIRST(&opts->head);
+    g_assert_cmpstr(opt->name, ==, "foo");
+    g_assert_cmpstr(opt->str , ==, "a");
+
+    opt = QTAILQ_NEXT(opt, next);
+    g_assert_cmpstr(opt->name, ==, "foo");
+    g_assert_cmpstr(opt->str , ==, "b");
+
+    opt = QTAILQ_NEXT(opt, next);
+    g_assert(opt == NULL);
+
+    /* In the conversion to QDict, the last one wins */
+    dict = qemu_opts_to_qdict(opts, NULL);
+    g_assert(dict != NULL);
+    g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "b");
+    QDECREF(dict);
+
+    /* The last one still wins if entries are deleted, and both are deleted */
+    dict = qemu_opts_to_qdict_filtered(opts, NULL, NULL, true);
+    g_assert(dict != NULL);
+    g_assert_cmpstr(qdict_get_str(dict, "foo"), ==, "b");
+    QDECREF(dict);
+
+    g_assert_true(QTAILQ_EMPTY(&opts->head));
+
+    qemu_opts_del(opts);
+}
 
 int main(int argc, char *argv[])
 {
@@ -889,6 +1011,9 @@ int main(int argc, char *argv[])
     g_test_add_func("/qemu-opts/opts_parse/size", test_opts_parse_size);
     g_test_add_func("/qemu-opts/append_to_null", test_opts_append_to_null);
     g_test_add_func("/qemu-opts/append", test_opts_append);
+    g_test_add_func("/qemu-opts/to_qdict/basic", test_opts_to_qdict_basic);
+    g_test_add_func("/qemu-opts/to_qdict/filtered", test_opts_to_qdict_filtered);
+    g_test_add_func("/qemu-opts/to_qdict/duplicates", test_opts_to_qdict_duplicates);
     g_test_run();
     return 0;
 }
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 11/36] qdict: Introduce qdict_rename_keys()
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (9 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 10/36] test-qemu-opts: Test qemu_opts_to_qdict_filtered() Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-22 22:40   ` Max Reitz
  2018-02-22 23:13   ` Eric Blake
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 12/36] qcow2: Use visitor for options in qcow2_create() Kevin Wolf
                   ` (24 subsequent siblings)
  35 siblings, 2 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

A few block drivers will need to rename .bdrv_create options for their
QAPIfication, so let's have a helper function for that.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 include/qapi/qmp/qdict.h |   6 +++
 qobject/qdict.c          |  34 ++++++++++++++
 tests/check-qdict.c      | 113 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 153 insertions(+)

diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
index ff6f7842c3..7c6d844549 100644
--- a/include/qapi/qmp/qdict.h
+++ b/include/qapi/qmp/qdict.h
@@ -81,4 +81,10 @@ QObject *qdict_crumple(const QDict *src, Error **errp);
 
 void qdict_join(QDict *dest, QDict *src, bool overwrite);
 
+typedef struct QDictRenames {
+    const char *from;
+    const char *to;
+} QDictRenames;
+bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp);
+
 #endif /* QDICT_H */
diff --git a/qobject/qdict.c b/qobject/qdict.c
index 23df84f9cd..229b8c840b 100644
--- a/qobject/qdict.c
+++ b/qobject/qdict.c
@@ -1072,3 +1072,37 @@ void qdict_join(QDict *dest, QDict *src, bool overwrite)
         entry = next;
     }
 }
+
+/**
+ * qdict_rename_keys(): Rename keys in qdict according to the replacements
+ * specified in the array renames. The array must be terminated by an entry
+ * with from = NULL.
+ *
+ * The renames are performed individually in the order of the array, so entries
+ * may be renamed multiple times and may or may not conflict depending on the
+ * order of the renames array.
+ *
+ * Returns true for success, false in error cases.
+ */
+bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp)
+{
+    QObject *qobj;
+
+    while (renames->from) {
+        if (qdict_haskey(qdict, renames->from)) {
+            if (qdict_haskey(qdict, renames->to)) {
+                error_setg(errp, "'%s' and its alias '%s' can't be used at the "
+                           "same time", renames->to, renames->from);
+                return false;
+            }
+
+            qobj = qdict_get(qdict, renames->from);
+            qobject_incref(qobj);
+            qdict_put_obj(qdict, renames->to, qobj);
+            qdict_del(qdict, renames->from);
+        }
+
+        renames++;
+    }
+    return true;
+}
diff --git a/tests/check-qdict.c b/tests/check-qdict.c
index ec628f3453..5f8f3be9ff 100644
--- a/tests/check-qdict.c
+++ b/tests/check-qdict.c
@@ -665,6 +665,117 @@ static void qdict_crumple_test_empty(void)
     QDECREF(dst);
 }
 
+static void qdict_rename_keys_test(void)
+{
+    QDict *dict = qdict_new();
+    QDict *copy;
+    QDictRenames *renames;
+    Error *local_err = NULL;
+
+    qdict_put_str(dict, "abc", "foo");
+    qdict_put_str(dict, "abcdef", "bar");
+    qdict_put_int(dict, "number", 42);
+    qdict_put_bool(dict, "flag", true);
+    qdict_put_null(dict, "nothing");
+
+    /* Empty rename list */
+    renames = (QDictRenames[]) {
+        { NULL, "this can be anything" }
+    };
+    copy = qdict_clone_shallow(dict);
+    qdict_rename_keys(copy, renames, &error_abort);
+
+    g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
+    g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
+    g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42);
+    g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true);
+    g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL);
+
+    QDECREF(copy);
+
+    /* Simple rename of all entries */
+    renames = (QDictRenames[]) {
+        { "abc",        "str1" },
+        { "abcdef",     "str2" },
+        { "number",     "int" },
+        { "flag",       "bool" },
+        { "nothing",    "null" },
+        { NULL , NULL }
+    };
+    copy = qdict_clone_shallow(dict);
+    qdict_rename_keys(copy, renames, &error_abort);
+
+    g_assert(!qdict_haskey(copy, "abc"));
+    g_assert(!qdict_haskey(copy, "abcdef"));
+    g_assert(!qdict_haskey(copy, "number"));
+    g_assert(!qdict_haskey(copy, "flag"));
+    g_assert(!qdict_haskey(copy, "nothing"));
+
+    g_assert_cmpstr(qdict_get_str(copy, "str1"), ==, "foo");
+    g_assert_cmpstr(qdict_get_str(copy, "str2"), ==, "bar");
+    g_assert_cmpint(qdict_get_int(copy, "int"), ==, 42);
+    g_assert_cmpint(qdict_get_bool(copy, "bool"), ==, true);
+    g_assert(qobject_type(qdict_get(copy, "null")) == QTYPE_QNULL);
+
+    QDECREF(copy);
+
+    /* Renames are processed top to bottom */
+    renames = (QDictRenames[]) {
+        { "abc",        "tmp" },
+        { "abcdef",     "abc" },
+        { "number",     "abcdef" },
+        { "flag",       "number" },
+        { "nothing",    "flag" },
+        { "tmp",        "nothing" },
+        { NULL , NULL }
+    };
+    copy = qdict_clone_shallow(dict);
+    qdict_rename_keys(copy, renames, &error_abort);
+
+    g_assert_cmpstr(qdict_get_str(copy, "nothing"), ==, "foo");
+    g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "bar");
+    g_assert_cmpint(qdict_get_int(copy, "abcdef"), ==, 42);
+    g_assert_cmpint(qdict_get_bool(copy, "number"), ==, true);
+    g_assert(qobject_type(qdict_get(copy, "flag")) == QTYPE_QNULL);
+    g_assert(!qdict_haskey(copy, "tmp"));
+
+    QDECREF(copy);
+
+    /* Conflicting renam */
+    renames = (QDictRenames[]) {
+        { "abcdef",     "abc" },
+        { NULL , NULL }
+    };
+    copy = qdict_clone_shallow(dict);
+    qdict_rename_keys(copy, renames, &local_err);
+
+    g_assert(local_err != NULL);
+    error_free(local_err);
+    local_err = NULL;
+
+    g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
+    g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
+    g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42);
+    g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true);
+    g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL);
+
+    QDECREF(copy);
+
+    /* Renames in an empty dict */
+    renames = (QDictRenames[]) {
+        { "abcdef",     "abc" },
+        { NULL , NULL }
+    };
+
+    QDECREF(dict);
+    dict = qdict_new();
+
+    qdict_rename_keys(dict, renames, &error_abort);
+    g_assert(qdict_first(dict) == NULL);
+
+    QDECREF(dict);
+}
+
 static void qdict_crumple_test_bad_inputs(void)
 {
     QDict *src;
@@ -880,6 +991,8 @@ int main(int argc, char **argv)
     g_test_add_func("/public/crumple/bad_inputs",
                     qdict_crumple_test_bad_inputs);
 
+    g_test_add_func("/public/rename_keys", qdict_rename_keys_test);
+
     /* The Big one */
     if (g_test_slow()) {
         g_test_add_func("/stress/test", qdict_stress_test);
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 12/36] qcow2: Use visitor for options in qcow2_create()
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (10 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 11/36] qdict: Introduce qdict_rename_keys() Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 13/36] block: Make bdrv_is_whitelisted() public Kevin Wolf
                   ` (23 subsequent siblings)
  35 siblings, 0 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

Instead of manually creating the BlockdevCreateOptions object, use a
visitor to parse the given options into the QAPI object.

This involves translation from the old command line syntax to the syntax
mandated by the QAPI schema. Option names are still checked against
qcow2_create_opts, so only the old option names are allowed on the
command line, even if they are translated in qcow2_create().

In contrast, new option values are optionally recognised besides the old
values: 'compat' accepts 'v2'/'v3' as an alias for '0.10'/'1.1', and
'encrypt.format' accepts 'qcow' as an alias for 'aes' now.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/qcow2.c              | 217 ++++++++++++++++-----------------------------
 tests/qemu-iotests/049.out |   8 +-
 tests/qemu-iotests/112.out |   4 +-
 3 files changed, 83 insertions(+), 146 deletions(-)

diff --git a/block/qcow2.c b/block/qcow2.c
index 64bf2863cd..58737d0833 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -38,7 +38,7 @@
 #include "qemu/option_int.h"
 #include "qemu/cutils.h"
 #include "qemu/bswap.h"
-#include "qapi/opts-visitor.h"
+#include "qapi/qobject-input-visitor.h"
 #include "qapi-visit.h"
 #include "block/crypto.h"
 
@@ -2414,37 +2414,6 @@ static int qcow2_crypt_method_from_format(const char *encryptfmt)
     }
 }
 
-static QCryptoBlockCreateOptions *
-qcow2_parse_encryption(const char *encryptfmt, QemuOpts *opts, Error **errp)
-{
-    QCryptoBlockCreateOptions *cryptoopts = NULL;
-    QDict *options, *encryptopts;
-    int fmt;
-
-    options = qemu_opts_to_qdict(opts, NULL);
-    qdict_extract_subqdict(options, &encryptopts, "encrypt.");
-    QDECREF(options);
-
-    fmt = qcow2_crypt_method_from_format(encryptfmt);
-
-    switch (fmt) {
-    case QCOW_CRYPT_LUKS:
-        cryptoopts = block_crypto_create_opts_init(
-            Q_CRYPTO_BLOCK_FORMAT_LUKS, encryptopts, errp);
-        break;
-    case QCOW_CRYPT_AES:
-        cryptoopts = block_crypto_create_opts_init(
-            Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp);
-        break;
-    default:
-        error_setg(errp, "Unknown encryption format '%s'", encryptfmt);
-        break;
-    }
-
-    QDECREF(encryptopts);
-    return cryptoopts;
-}
-
 static int qcow2_set_up_encryption(BlockDriverState *bs,
                                    QCryptoBlockCreateOptions *cryptoopts,
                                    Error **errp)
@@ -2838,7 +2807,7 @@ static int qcow2_create2(BlockdevCreateOptions *create_options, Error **errp)
     }
     if (version < 3 && qcow2_opts->lazy_refcounts) {
         error_setg(errp, "Lazy refcounts only supported with compatibility "
-                   "level 1.1 and above (use compat=1.1 or greater)");
+                   "level 1.1 and above (use version=v3 or greater)");
         ret = -EINVAL;
         goto out;
     }
@@ -2856,7 +2825,7 @@ static int qcow2_create2(BlockdevCreateOptions *create_options, Error **errp)
     }
     if (version < 3 && qcow2_opts->refcount_bits != 16) {
         error_setg(errp, "Different refcount widths than 16 bits require "
-                   "compatibility level 1.1 or above (use compat=1.1 or "
+                   "compatibility level 1.1 or above (use version=v3 or "
                    "greater)");
         ret = -EINVAL;
         goto out;
@@ -3043,144 +3012,112 @@ out:
 
 static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
 {
-    BlockdevCreateOptions create_options;
-    char *backing_file = NULL;
-    char *backing_fmt = NULL;
-    BlockdevDriver backing_drv;
-    char *buf = NULL;
-    uint64_t size = 0;
-    int flags = 0;
-    size_t cluster_size = DEFAULT_CLUSTER_SIZE;
-    PreallocMode prealloc;
-    int version;
-    uint64_t refcount_bits;
-    char *encryptfmt = NULL;
-    QCryptoBlockCreateOptions *cryptoopts = NULL;
+    BlockdevCreateOptions *create_options = NULL;
+    QDict *qdict = NULL;
+    QObject *qobj;
+    Visitor *v;
     BlockDriverState *bs = NULL;
     Error *local_err = NULL;
+    const char *val;
     int ret;
 
-    /* Read out options */
-    size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
-                    BDRV_SECTOR_SIZE);
-    backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
-    backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT);
-    backing_drv = qapi_enum_parse(&BlockdevDriver_lookup, backing_fmt,
-                                  0, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+    /* Only the keyval visitor supports the dotted syntax needed for
+     * encryption, so go through a QDict before getting a QAPI type. Ignore
+     * options meant for the protocol layer so that the visitor doesn't
+     * complain. */
+    qdict = qemu_opts_to_qdict_filtered(opts, NULL, bdrv_qcow2.create_opts,
+                                        true);
+
+    /* Handle encryption options */
+    val = qdict_get_try_str(qdict, BLOCK_OPT_ENCRYPT);
+    if (val && !strcmp(val, "on")) {
+        qdict_put_str(qdict, BLOCK_OPT_ENCRYPT, "qcow");
+    } else if (val && !strcmp(val, "off")) {
+        qdict_del(qdict, BLOCK_OPT_ENCRYPT);
+    }
+
+    val = qdict_get_try_str(qdict, BLOCK_OPT_ENCRYPT_FORMAT);
+    if (val && !strcmp(val, "aes")) {
+        qdict_put_str(qdict, BLOCK_OPT_ENCRYPT_FORMAT, "qcow");
+    }
+
+    /* Convert compat=0.10/1.1 into compat=v2/v3, to be renamed into
+     * version=v2/v3 below. */
+    val = qdict_get_try_str(qdict, BLOCK_OPT_COMPAT_LEVEL);
+    if (val && !strcmp(val, "0.10")) {
+        qdict_put_str(qdict, BLOCK_OPT_COMPAT_LEVEL, "v2");
+    } else if (val && !strcmp(val, "1.1")) {
+        qdict_put_str(qdict, BLOCK_OPT_COMPAT_LEVEL, "v3");
+    }
+
+    /* Change legacy command line options into QMP ones */
+    static const QDictRenames opt_renames[] = {
+        { BLOCK_OPT_BACKING_FILE,       "backing-file" },
+        { BLOCK_OPT_BACKING_FMT,        "backing-fmt" },
+        { BLOCK_OPT_CLUSTER_SIZE,       "cluster-size" },
+        { BLOCK_OPT_LAZY_REFCOUNTS,     "lazy-refcounts" },
+        { BLOCK_OPT_REFCOUNT_BITS,      "refcount-bits" },
+        { BLOCK_OPT_ENCRYPT,            BLOCK_OPT_ENCRYPT_FORMAT },
+        { BLOCK_OPT_COMPAT_LEVEL,       "version" },
+        { NULL, NULL },
+    };
+
+    if (!qdict_rename_keys(qdict, opt_renames, errp)) {
         ret = -EINVAL;
         goto finish;
     }
 
-    encryptfmt = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT);
-    if (encryptfmt) {
-        if (qemu_opt_get(opts, BLOCK_OPT_ENCRYPT)) {
-            error_setg(errp, "Options " BLOCK_OPT_ENCRYPT " and "
-                       BLOCK_OPT_ENCRYPT_FORMAT " are mutually exclusive");
-            ret = -EINVAL;
-            goto finish;
-        }
-    } else if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
-        encryptfmt = g_strdup("aes");
-    }
-    if (encryptfmt) {
-        cryptoopts = qcow2_parse_encryption(encryptfmt, opts, errp);
-        if (cryptoopts == NULL) {
-            ret = -EINVAL;
-            goto finish;
-        }
-    }
-
-    cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        ret = -EINVAL;
+    /* Create and open the file (protocol layer) */
+    ret = bdrv_create_file(filename, opts, errp);
+    if (ret < 0) {
         goto finish;
     }
-    buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
-    prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
-                               PREALLOC_MODE_OFF, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        ret = -EINVAL;
+
+    bs = bdrv_open(filename, NULL, NULL,
+                   BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
+    if (bs == NULL) {
+        ret = -EIO;
         goto finish;
     }
 
-    version = qcow2_opt_get_version_del(opts, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+    /* Set 'driver' and 'node' options */
+    qdict_put_str(qdict, "driver", "qcow2");
+    qdict_put_str(qdict, "file", bs->node_name);
+
+    /* Now get the QAPI type BlockdevCreateOptions */
+    qobj = qdict_crumple(qdict, errp);
+    QDECREF(qdict);
+    qdict = qobject_to_qdict(qobj);
+    if (qdict == NULL) {
         ret = -EINVAL;
         goto finish;
     }
 
-    if (qemu_opt_get_bool_del(opts, BLOCK_OPT_LAZY_REFCOUNTS, false)) {
-        flags |= BLOCK_FLAG_LAZY_REFCOUNTS;
-    }
+    v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
+    visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
+    visit_free(v);
 
-    refcount_bits = qcow2_opt_get_refcount_bits_del(opts, version, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         ret = -EINVAL;
         goto finish;
     }
 
-
-    /* Create and open the file (protocol layer) */
-    ret = bdrv_create_file(filename, opts, errp);
-    if (ret < 0) {
-        goto finish;
-    }
-
-    bs = bdrv_open(filename, NULL, NULL,
-                   BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
-    if (bs == NULL) {
-        ret = -EIO;
-        goto finish;
-    }
+    /* Silently round up size */
+    create_options->u.qcow2.size = ROUND_UP(create_options->u.qcow2.size,
+                                            BDRV_SECTOR_SIZE);
 
     /* Create the qcow2 image (format layer) */
-    create_options = (BlockdevCreateOptions) {
-        .driver         = BLOCKDEV_DRIVER_QCOW2,
-        .u.qcow2        = {
-            .file               = &(BlockdevRef) {
-                .type               = QTYPE_QSTRING,
-                .u.reference        = bs->node_name,
-            },
-            .size               = size,
-            .has_version        = true,
-            .version            = version == 2
-                                  ? BLOCKDEV_QCOW2_VERSION_V2
-                                  : BLOCKDEV_QCOW2_VERSION_V3,
-            .has_backing_file   = (backing_file != NULL),
-            .backing_file       = backing_file,
-            .has_backing_fmt    = (backing_fmt != NULL),
-            .backing_fmt        = backing_drv,
-            .has_encrypt        = (encryptfmt != NULL),
-            .encrypt            = cryptoopts,
-            .has_cluster_size   = true,
-            .cluster_size       = cluster_size,
-            .has_preallocation  = true,
-            .preallocation      = prealloc,
-            .has_lazy_refcounts = true,
-            .lazy_refcounts     = (flags & BLOCK_FLAG_LAZY_REFCOUNTS),
-            .has_refcount_bits  = true,
-            .refcount_bits      = refcount_bits,
-        },
-    };
-    ret = qcow2_create2(&create_options, errp);
+    ret = qcow2_create2(create_options, errp);
     if (ret < 0) {
         goto finish;
     }
 
+    ret = 0;
 finish:
+    QDECREF(qdict);
     bdrv_unref(bs);
-
-    qapi_free_QCryptoBlockCreateOptions(cryptoopts);
-    g_free(backing_file);
-    g_free(backing_fmt);
-    g_free(encryptfmt);
-    g_free(buf);
+    qapi_free_BlockdevCreateOptions(create_options);
     return ret;
 }
 
diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out
index 003247023e..0871bff564 100644
--- a/tests/qemu-iotests/049.out
+++ b/tests/qemu-iotests/049.out
@@ -166,11 +166,11 @@ qemu-img create -f qcow2 -o compat=1.1 TEST_DIR/t.qcow2 64M
 Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 cluster_size=65536 lazy_refcounts=off refcount_bits=16
 
 qemu-img create -f qcow2 -o compat=0.42 TEST_DIR/t.qcow2 64M
-qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: '0.42'
+qemu-img: TEST_DIR/t.qcow2: Invalid parameter '0.42'
 Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.42 cluster_size=65536 lazy_refcounts=off refcount_bits=16
 
 qemu-img create -f qcow2 -o compat=foobar TEST_DIR/t.qcow2 64M
-qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: 'foobar'
+qemu-img: TEST_DIR/t.qcow2: Invalid parameter 'foobar'
 Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=foobar cluster_size=65536 lazy_refcounts=off refcount_bits=16
 
 == Check preallocation option ==
@@ -182,7 +182,7 @@ qemu-img create -f qcow2 -o preallocation=metadata TEST_DIR/t.qcow2 64M
 Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=metadata lazy_refcounts=off refcount_bits=16
 
 qemu-img create -f qcow2 -o preallocation=1234 TEST_DIR/t.qcow2 64M
-qemu-img: TEST_DIR/t.qcow2: invalid parameter value: 1234
+qemu-img: TEST_DIR/t.qcow2: Invalid parameter '1234'
 Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 cluster_size=65536 preallocation=1234 lazy_refcounts=off refcount_bits=16
 
 == Check encryption option ==
@@ -205,7 +205,7 @@ qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=off TEST_DIR/t.qcow2 64M
 Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=off refcount_bits=16
 
 qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=on TEST_DIR/t.qcow2 64M
-qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater)
+qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater)
 Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 cluster_size=65536 lazy_refcounts=on refcount_bits=16
 
 *** done
diff --git a/tests/qemu-iotests/112.out b/tests/qemu-iotests/112.out
index 81b04d1452..86f041075d 100644
--- a/tests/qemu-iotests/112.out
+++ b/tests/qemu-iotests/112.out
@@ -21,9 +21,9 @@ refcount bits: 16
 
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
 refcount bits: 16
-qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use or greater)
+qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater)
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
-qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use or greater)
+qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater)
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
 
 === Snapshot limit on refcount_bits=1 ===
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 13/36] block: Make bdrv_is_whitelisted() public
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (11 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 12/36] qcow2: Use visitor for options in qcow2_create() Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-22 22:45   ` Max Reitz
  2018-02-22 23:17   ` Eric Blake
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 14/36] block: x-blockdev-create QMP command Kevin Wolf
                   ` (22 subsequent siblings)
  35 siblings, 2 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

We'll use a separate source file for image creation, and we need to
check there whether the requested driver is whitelisted.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 include/block/block.h | 1 +
 block.c               | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/block/block.h b/include/block/block.h
index 54fe8b7a0e..cfce88cbda 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -225,6 +225,7 @@ char *bdrv_perm_names(uint64_t perm);
 void bdrv_init(void);
 void bdrv_init_with_whitelist(void);
 bool bdrv_uses_whitelist(void);
+int bdrv_is_whitelisted(BlockDriver *drv, bool read_only);
 BlockDriver *bdrv_find_protocol(const char *filename,
                                 bool allow_protocol_prefix,
                                 Error **errp);
diff --git a/block.c b/block.c
index c0e343d278..4a7e448226 100644
--- a/block.c
+++ b/block.c
@@ -372,7 +372,7 @@ BlockDriver *bdrv_find_format(const char *format_name)
     return bdrv_do_find_format(format_name);
 }
 
-static int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
+int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
 {
     static const char *whitelist_rw[] = {
         CONFIG_BDRV_RW_WHITELIST
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 14/36] block: x-blockdev-create QMP command
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (12 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 13/36] block: Make bdrv_is_whitelisted() public Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-22 22:50   ` Max Reitz
  2018-02-22 23:19   ` Eric Blake
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 15/36] file-posix: Support .bdrv_co_create Kevin Wolf
                   ` (21 subsequent siblings)
  35 siblings, 2 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

This adds a synchronous x-blockdev-create QMP command that can create
qcow2 images on a given node name.

We don't want to block while creating an image, so this is not the final
interface in all aspects, but BlockdevCreateOptionsQcow2 and
.bdrv_co_create() are what they actually might look like in the end. In
any case, this should be good enough to test whether we interpret
BlockdevCreateOptions as we should.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 qapi/block-core.json      | 12 ++++++++
 include/block/block_int.h |  2 ++
 block/create.c            | 76 +++++++++++++++++++++++++++++++++++++++++++++++
 block/qcow2.c             |  3 +-
 block/Makefile.objs       |  2 +-
 5 files changed, 93 insertions(+), 2 deletions(-)
 create mode 100644 block/create.c

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 74b864d64e..359195a1a3 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3464,6 +3464,18 @@
   } }
 
 ##
+# @x-blockdev-create:
+#
+# Create an image format on a given node.
+# TODO Replace with something asynchronous (block job?)
+#
+# Since: 2.12
+##
+{ 'command': 'x-blockdev-create',
+  'data': 'BlockdevCreateOptions',
+  'boxed': true }
+
+##
 # @blockdev-open-tray:
 #
 # Opens a block device's tray. If there is a block driver state tree inserted as
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 5ae7738cf8..0b43fae782 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -128,6 +128,8 @@ struct BlockDriver {
     int (*bdrv_file_open)(BlockDriverState *bs, QDict *options, int flags,
                           Error **errp);
     void (*bdrv_close)(BlockDriverState *bs);
+    int coroutine_fn (*bdrv_co_create)(BlockdevCreateOptions *opts,
+                                       Error **errp);
     int (*bdrv_create)(const char *filename, QemuOpts *opts, Error **errp);
     int (*bdrv_make_empty)(BlockDriverState *bs);
 
diff --git a/block/create.c b/block/create.c
new file mode 100644
index 0000000000..dfd31eca37
--- /dev/null
+++ b/block/create.c
@@ -0,0 +1,76 @@
+/*
+ * Block layer code related to image creation
+ *
+ * Copyright (c) 2018 Kevin Wolf <kwolf@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "block/block_int.h"
+#include "qmp-commands.h"
+#include "qapi/error.h"
+
+typedef struct BlockdevCreateCo {
+    BlockDriver *drv;
+    BlockdevCreateOptions *opts;
+    int ret;
+    Error **errp;
+} BlockdevCreateCo;
+
+static void coroutine_fn bdrv_co_create_co_entry(void *opaque)
+{
+    BlockdevCreateCo *cco = opaque;
+    cco->ret = cco->drv->bdrv_co_create(cco->opts, cco->errp);
+}
+
+void qmp_x_blockdev_create(BlockdevCreateOptions *options, Error **errp)
+{
+    const char *fmt = BlockdevDriver_str(options->driver);
+    BlockDriver *drv = bdrv_find_format(fmt);
+    Coroutine *co;
+    BlockdevCreateCo cco;
+
+    /* If the driver is in the schema, we know that it exists. But it may not
+     * be whitelisted. */
+    assert(drv);
+    if (bdrv_uses_whitelist() && !bdrv_is_whitelisted(drv, false)) {
+        error_setg(errp, "Driver is not whitelisted");
+        return;
+    }
+
+    /* Call callback if it exists */
+    if (!drv->bdrv_co_create) {
+        error_setg(errp, "Driver does not support blockdev-create");
+        return;
+    }
+
+    cco = (BlockdevCreateCo) {
+        .drv = drv,
+        .opts = options,
+        .ret = -EINPROGRESS,
+        .errp = errp,
+    };
+
+    co = qemu_coroutine_create(bdrv_co_create_co_entry, &cco);
+    qemu_coroutine_enter(co);
+    while (cco.ret == -EINPROGRESS) {
+        aio_poll(qemu_get_aio_context(), true);
+    }
+}
diff --git a/block/qcow2.c b/block/qcow2.c
index 58737d0833..8acb36b0af 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -4463,7 +4463,8 @@ BlockDriver bdrv_qcow2 = {
     .bdrv_reopen_abort    = qcow2_reopen_abort,
     .bdrv_join_options    = qcow2_join_options,
     .bdrv_child_perm      = bdrv_format_default_perms,
-    .bdrv_create        = qcow2_create,
+    .bdrv_create          = qcow2_create,
+    .bdrv_co_create       = qcow2_create2,
     .bdrv_has_zero_init = bdrv_has_zero_init_1,
     .bdrv_co_block_status = qcow2_co_block_status,
 
diff --git a/block/Makefile.objs b/block/Makefile.objs
index aede94f105..d644bac60a 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -9,7 +9,7 @@ block-obj-y += block-backend.o snapshot.o qapi.o
 block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o
 block-obj-$(CONFIG_POSIX) += file-posix.o
 block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
-block-obj-y += null.o mirror.o commit.o io.o
+block-obj-y += null.o mirror.o commit.o io.o create.o
 block-obj-y += throttle-groups.o
 block-obj-$(CONFIG_LINUX) += nvme.o
 
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 15/36] file-posix: Support .bdrv_co_create
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (13 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 14/36] block: x-blockdev-create QMP command Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-22 23:34   ` Eric Blake
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 16/36] file-win32: " Kevin Wolf
                   ` (20 subsequent siblings)
  35 siblings, 1 reply; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

This adds the .bdrv_co_create driver callback to file, which enables
image creation over QMP.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 qapi/block-core.json | 20 +++++++++++++-
 block/file-posix.c   | 77 +++++++++++++++++++++++++++++++++++++---------------
 2 files changed, 74 insertions(+), 23 deletions(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 359195a1a3..0040795603 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3359,6 +3359,24 @@
 { 'command': 'blockdev-del', 'data': { 'node-name': 'str' } }
 
 ##
+# @BlockdevCreateOptionsFile:
+#
+# Driver specific image creation options for file.
+#
+# @filename         Filename for the new image file
+# @size             Size of the virtual disk in bytes
+# @preallocation    Preallocation mode for the new image (default: off)
+# @nocow            Turn off copy-on-write (valid only on btrfs; default: off)
+#
+# Since: 2.12
+##
+{ 'struct': 'BlockdevCreateOptionsFile',
+  'data': { 'filename':         'str',
+            'size':             'size',
+            '*preallocation':   'PreallocMode',
+            '*nocow':           'bool' } }
+
+##
 # @BlockdevQcow2Version:
 #
 # @v2:  The original QCOW2 format as introduced in qemu 0.10 (version 2)
@@ -3429,7 +3447,7 @@
       'bochs':          'BlockdevCreateNotSupported',
       'cloop':          'BlockdevCreateNotSupported',
       'dmg':            'BlockdevCreateNotSupported',
-      'file':           'BlockdevCreateNotSupported',
+      'file':           'BlockdevCreateOptionsFile',
       'ftp':            'BlockdevCreateNotSupported',
       'ftps':           'BlockdevCreateNotSupported',
       'gluster':        'BlockdevCreateNotSupported',
diff --git a/block/file-posix.c b/block/file-posix.c
index f1591c3849..ba14ed9459 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -1982,33 +1982,25 @@ static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
     return (int64_t)st.st_blocks * 512;
 }
 
-static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
+static int raw_co_create(BlockdevCreateOptions *options, Error **errp)
 {
+    BlockdevCreateOptionsFile *file_opts;
     int fd;
     int result = 0;
-    int64_t total_size = 0;
-    bool nocow = false;
-    PreallocMode prealloc;
-    char *buf = NULL;
-    Error *local_err = NULL;
 
-    strstart(filename, "file:", &filename);
+    /* Validate options and set default values */
+    assert(options->driver == BLOCKDEV_DRIVER_FILE);
+    file_opts = &options->u.file;
 
-    /* Read out options */
-    total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
-                          BDRV_SECTOR_SIZE);
-    nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false);
-    buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
-    prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
-                               PREALLOC_MODE_OFF, &local_err);
-    g_free(buf);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        result = -EINVAL;
-        goto out;
+    if (!file_opts->has_nocow) {
+        file_opts->nocow = false;
+    }
+    if (!file_opts->has_preallocation) {
+        file_opts->preallocation = PREALLOC_MODE_OFF;
     }
 
-    fd = qemu_open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
+    /* Create file */
+    fd = qemu_open(file_opts->filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
                    0644);
     if (fd < 0) {
         result = -errno;
@@ -2016,7 +2008,7 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
         goto out;
     }
 
-    if (nocow) {
+    if (file_opts->nocow) {
 #ifdef __linux__
         /* Set NOCOW flag to solve performance issue on fs like btrfs.
          * This is an optimisation. The FS_IOC_SETFLAGS ioctl return value
@@ -2031,7 +2023,8 @@ static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
 #endif
     }
 
-    result = raw_regular_truncate(fd, total_size, prealloc, errp);
+    result = raw_regular_truncate(fd, file_opts->size, file_opts->preallocation,
+                                  errp);
     if (result < 0) {
         goto out_close;
     }
@@ -2045,6 +2038,45 @@ out:
     return result;
 }
 
+static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
+{
+    BlockdevCreateOptions options;
+    int64_t total_size = 0;
+    bool nocow = false;
+    PreallocMode prealloc;
+    char *buf = NULL;
+    Error *local_err = NULL;
+
+    /* Skip file: protocol prefix */
+    strstart(filename, "file:", &filename);
+
+    /* Read out options */
+    total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
+                          BDRV_SECTOR_SIZE);
+    nocow = qemu_opt_get_bool(opts, BLOCK_OPT_NOCOW, false);
+    buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
+    prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
+                               PREALLOC_MODE_OFF, &local_err);
+    g_free(buf);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return -EINVAL;
+    }
+
+    options = (BlockdevCreateOptions) {
+        .driver     = BLOCKDEV_DRIVER_FILE,
+        .u.file     = {
+            .filename           = (char *) filename,
+            .size               = total_size,
+            .has_preallocation  = true,
+            .preallocation      = prealloc,
+            .has_nocow          = true,
+            .nocow              = nocow,
+        },
+    };
+    return raw_co_create(&options, errp);
+}
+
 /*
  * Find allocation range in @bs around offset @start.
  * May change underlying file descriptor's file offset.
@@ -2276,6 +2308,7 @@ BlockDriver bdrv_file = {
     .bdrv_reopen_commit = raw_reopen_commit,
     .bdrv_reopen_abort = raw_reopen_abort,
     .bdrv_close = raw_close,
+    .bdrv_co_create = raw_co_create,
     .bdrv_create = raw_create,
     .bdrv_has_zero_init = bdrv_has_zero_init_1,
     .bdrv_co_block_status = raw_co_block_status,
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 16/36] file-win32: Support .bdrv_co_create
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (14 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 15/36] file-posix: Support .bdrv_co_create Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-23 14:46   ` Eric Blake
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 17/36] gluster: " Kevin Wolf
                   ` (19 subsequent siblings)
  35 siblings, 1 reply; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

This adds the .bdrv_co_create driver callback to file-win32, which
enables image creation over QMP.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 block/file-win32.c | 45 +++++++++++++++++++++++++++++++++++++--------
 1 file changed, 37 insertions(+), 8 deletions(-)

diff --git a/block/file-win32.c b/block/file-win32.c
index f24c7bb92c..d572cde357 100644
--- a/block/file-win32.c
+++ b/block/file-win32.c
@@ -553,29 +553,58 @@ static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
     return st.st_size;
 }
 
-static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
+static int raw_co_create(BlockdevCreateOptions *options, Error **errp)
 {
+    BlockdevCreateOptionsFile *file_opts;
     int fd;
-    int64_t total_size = 0;
 
-    strstart(filename, "file:", &filename);
+    assert(options->driver == BLOCKDEV_DRIVER_FILE);
+    file_opts = &options->u.file;
 
-    /* Read out options */
-    total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
-                          BDRV_SECTOR_SIZE);
+    if (file_opts->has_preallocation) {
+        error_setg(errp, "Preallocation is not supported on Windows");
+        return -EINVAL;
+    }
+    if (file_opts->has_nocow) {
+        error_setg(errp, "nocow is not supported on Windows");
+        return -EINVAL;
+    }
 
-    fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
+    fd = qemu_open(file_opts->filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
                    0644);
     if (fd < 0) {
         error_setg_errno(errp, errno, "Could not create file");
         return -EIO;
     }
     set_sparse(fd);
-    ftruncate(fd, total_size);
+    ftruncate(fd, file_opts->size);
     qemu_close(fd);
+
     return 0;
 }
 
+static int raw_create(const char *filename, QemuOpts *opts, Error **errp)
+{
+    BlockdevCreateOptions options;
+    int64_t total_size = 0;
+
+    strstart(filename, "file:", &filename);
+
+    /* Read out options */
+    total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
+                          BDRV_SECTOR_SIZE);
+
+    options = (BlockdevCreateOptions) {
+        .driver     = BLOCKDEV_DRIVER_FILE,
+        .u.file     = {
+            .filename           = (char *) filename,
+            .size               = total_size,
+            .has_preallocation  = false,
+            .has_nocow          = false,
+        },
+    };
+    return raw_co_create(&options, errp);
+}
 
 static QemuOptsList raw_create_opts = {
     .name = "raw-create-opts",
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 17/36] gluster: Support .bdrv_co_create
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (15 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 16/36] file-win32: " Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-22 23:01   ` Max Reitz
  2018-02-23 15:10   ` Eric Blake
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 18/36] rbd: Fix use after free in qemu_rbd_set_keypairs() error path Kevin Wolf
                   ` (18 subsequent siblings)
  35 siblings, 2 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

This adds the .bdrv_co_create driver callback to gluster, which enables
image creation over QMP.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 qapi/block-core.json |  18 ++++++-
 block/gluster.c      | 135 ++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 108 insertions(+), 45 deletions(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 0040795603..74021c51d7 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3377,6 +3377,22 @@
             '*nocow':           'bool' } }
 
 ##
+# @BlockdevCreateOptionsGluster:
+#
+# Driver specific image creation options for gluster.
+#
+# @location         Where to store the new image file
+# @size             Size of the virtual disk in bytes
+# @preallocation    Preallocation mode for the new image (default: off)
+#
+# Since: 2.12
+##
+{ 'struct': 'BlockdevCreateOptionsGluster',
+  'data': { 'location':         'BlockdevOptionsGluster',
+            'size':             'size',
+            '*preallocation':   'PreallocMode' } }
+
+##
 # @BlockdevQcow2Version:
 #
 # @v2:  The original QCOW2 format as introduced in qemu 0.10 (version 2)
@@ -3450,7 +3466,7 @@
       'file':           'BlockdevCreateOptionsFile',
       'ftp':            'BlockdevCreateNotSupported',
       'ftps':           'BlockdevCreateNotSupported',
-      'gluster':        'BlockdevCreateNotSupported',
+      'gluster':        'BlockdevCreateOptionsGluster',
       'host_cdrom':     'BlockdevCreateNotSupported',
       'host_device':    'BlockdevCreateNotSupported',
       'http':           'BlockdevCreateNotSupported',
diff --git a/block/gluster.c b/block/gluster.c
index 1a07d221d1..6e2f0e3185 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -655,9 +655,11 @@ out:
     return -errno;
 }
 
-static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
-                                      const char *filename,
-                                      QDict *options, Error **errp)
+/* Converts options given in @filename and the @options QDict into the QAPI
+ * object @gconf. */
+static int qemu_gluster_parse(BlockdevOptionsGluster *gconf,
+                              const char *filename,
+                              QDict *options, Error **errp)
 {
     int ret;
     if (filename) {
@@ -668,8 +670,7 @@ static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
                                     "[host[:port]]volume/path[?socket=...]"
                                     "[,file.debug=N]"
                                     "[,file.logfile=/path/filename.log]\n");
-            errno = -ret;
-            return NULL;
+            return ret;
         }
     } else {
         ret = qemu_gluster_parse_json(gconf, options, errp);
@@ -685,10 +686,23 @@ static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
                              "file.server.1.transport=unix,"
                              "file.server.1.socket=/var/run/glusterd.socket ..."
                              "\n");
-            errno = -ret;
-            return NULL;
+            return ret;
         }
+    }
 
+    return 0;
+}
+
+static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
+                                      const char *filename,
+                                      QDict *options, Error **errp)
+{
+    int ret;
+
+    ret = qemu_gluster_parse(gconf, filename, options, errp);
+    if (ret < 0) {
+        errno = -ret;
+        return NULL;
     }
 
     return qemu_gluster_glfs_init(gconf, errp);
@@ -1021,19 +1035,71 @@ static int qemu_gluster_do_truncate(struct glfs_fd *fd, int64_t offset,
     return 0;
 }
 
-static int qemu_gluster_create(const char *filename,
-                               QemuOpts *opts, Error **errp)
+static int qemu_gluster_co_create(BlockdevCreateOptions *options,
+                                  Error **errp)
 {
-    BlockdevOptionsGluster *gconf;
+    BlockdevCreateOptionsGluster *opts = &options->u.gluster;
     struct glfs *glfs;
     struct glfs_fd *fd = NULL;
     int ret = 0;
-    PreallocMode prealloc;
-    int64_t total_size = 0;
+
+    assert(options->driver == BLOCKDEV_DRIVER_GLUSTER);
+
+    glfs = qemu_gluster_glfs_init(opts->location, errp);
+    if (!glfs) {
+        ret = -errno;
+        goto out;
+    }
+
+    fd = glfs_creat(glfs, opts->location->path,
+                    O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR);
+    if (!fd) {
+        ret = -errno;
+        goto out;
+    }
+
+    ret = qemu_gluster_do_truncate(fd, opts->size, opts->preallocation, errp);
+
+out:
+    if (fd) {
+        if (glfs_close(fd) != 0 && ret == 0) {
+            ret = -errno;
+        }
+    }
+    glfs_clear_preopened(glfs);
+    return ret;
+}
+
+static int qemu_gluster_create(const char *filename,
+                               QemuOpts *opts, Error **errp)
+{
+    BlockdevCreateOptions *options;
+    BlockdevCreateOptionsGluster *gopts;
+    BlockdevOptionsGluster *gconf;
     char *tmp = NULL;
     Error *local_err = NULL;
+    int ret;
+
+    options = g_new0(BlockdevCreateOptions, 1);
+    options->driver = BLOCKDEV_DRIVER_GLUSTER;
+    gopts = &options->u.gluster;
 
     gconf = g_new0(BlockdevOptionsGluster, 1);
+    gopts->location = gconf;
+
+    gopts->size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
+                           BDRV_SECTOR_SIZE);
+
+    tmp = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
+    gopts->preallocation = qapi_enum_parse(&PreallocMode_lookup, tmp,
+                                           PREALLOC_MODE_OFF, &local_err);
+    g_free(tmp);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        ret = -EINVAL;
+        goto fail;
+    }
+
     gconf->debug = qemu_opt_get_number_del(opts, GLUSTER_OPT_DEBUG,
                                            GLUSTER_DEBUG_DEFAULT);
     if (gconf->debug < 0) {
@@ -1049,42 +1115,19 @@ static int qemu_gluster_create(const char *filename,
     }
     gconf->has_logfile = true;
 
-    glfs = qemu_gluster_init(gconf, filename, NULL, errp);
-    if (!glfs) {
-        ret = -errno;
-        goto out;
-    }
-
-    total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
-                          BDRV_SECTOR_SIZE);
-
-    tmp = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
-    prealloc = qapi_enum_parse(&PreallocMode_lookup, tmp, PREALLOC_MODE_OFF,
-                               &local_err);
-    g_free(tmp);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        ret = -EINVAL;
-        goto out;
+    ret = qemu_gluster_parse(gconf, filename, NULL, errp);
+    if (ret < 0) {
+        goto fail;
     }
 
-    fd = glfs_creat(glfs, gconf->path,
-                    O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR);
-    if (!fd) {
-        ret = -errno;
-        goto out;
+    ret = qemu_gluster_co_create(options, errp);
+    if (ret < 0) {
+        goto fail;
     }
 
-    ret = qemu_gluster_do_truncate(fd, total_size, prealloc, errp);
-
-out:
-    if (fd) {
-        if (glfs_close(fd) != 0 && ret == 0) {
-            ret = -errno;
-        }
-    }
-    qapi_free_BlockdevOptionsGluster(gconf);
-    glfs_clear_preopened(glfs);
+    ret = 0;
+fail:
+    qapi_free_BlockdevCreateOptions(options);
     return ret;
 }
 
@@ -1436,6 +1479,7 @@ static BlockDriver bdrv_gluster = {
     .bdrv_reopen_abort            = qemu_gluster_reopen_abort,
     .bdrv_close                   = qemu_gluster_close,
     .bdrv_create                  = qemu_gluster_create,
+    .bdrv_co_create               = qemu_gluster_co_create,
     .bdrv_getlength               = qemu_gluster_getlength,
     .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
     .bdrv_truncate                = qemu_gluster_truncate,
@@ -1464,6 +1508,7 @@ static BlockDriver bdrv_gluster_tcp = {
     .bdrv_reopen_abort            = qemu_gluster_reopen_abort,
     .bdrv_close                   = qemu_gluster_close,
     .bdrv_create                  = qemu_gluster_create,
+    .bdrv_co_create               = qemu_gluster_co_create,
     .bdrv_getlength               = qemu_gluster_getlength,
     .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
     .bdrv_truncate                = qemu_gluster_truncate,
@@ -1492,6 +1537,7 @@ static BlockDriver bdrv_gluster_unix = {
     .bdrv_reopen_abort            = qemu_gluster_reopen_abort,
     .bdrv_close                   = qemu_gluster_close,
     .bdrv_create                  = qemu_gluster_create,
+    .bdrv_co_create               = qemu_gluster_co_create,
     .bdrv_getlength               = qemu_gluster_getlength,
     .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
     .bdrv_truncate                = qemu_gluster_truncate,
@@ -1526,6 +1572,7 @@ static BlockDriver bdrv_gluster_rdma = {
     .bdrv_reopen_abort            = qemu_gluster_reopen_abort,
     .bdrv_close                   = qemu_gluster_close,
     .bdrv_create                  = qemu_gluster_create,
+    .bdrv_co_create               = qemu_gluster_co_create,
     .bdrv_getlength               = qemu_gluster_getlength,
     .bdrv_get_allocated_file_size = qemu_gluster_allocated_file_size,
     .bdrv_truncate                = qemu_gluster_truncate,
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 18/36] rbd: Fix use after free in qemu_rbd_set_keypairs() error path
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (16 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 17/36] gluster: " Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-22 23:02   ` Max Reitz
  2018-02-23 15:15   ` Eric Blake
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 19/36] rbd: Factor out qemu_rbd_connect() Kevin Wolf
                   ` (17 subsequent siblings)
  35 siblings, 2 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

If we want to include the invalid option name in the error message, we
can't free the string earlier than that.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/rbd.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/block/rbd.c b/block/rbd.c
index 8474b0ba11..27fa11b473 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -268,13 +268,14 @@ static int qemu_rbd_set_keypairs(rados_t cluster, const char *keypairs_json,
         key = qstring_get_str(name);
 
         ret = rados_conf_set(cluster, key, qstring_get_str(value));
-        QDECREF(name);
         QDECREF(value);
         if (ret < 0) {
             error_setg_errno(errp, -ret, "invalid conf option %s", key);
+            QDECREF(name);
             ret = -EINVAL;
             break;
         }
+        QDECREF(name);
     }
 
     QDECREF(keypairs);
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 19/36] rbd: Factor out qemu_rbd_connect()
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (17 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 18/36] rbd: Fix use after free in qemu_rbd_set_keypairs() error path Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-22 23:10   ` Max Reitz
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 20/36] rbd: Remove non-schema options from runtime_opts Kevin Wolf
                   ` (16 subsequent siblings)
  35 siblings, 1 reply; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

The code to establish an RBD connection is duplicated between open and
create. In order to be able to share the code, factor out the code from
qemu_rbd_open() as a first step.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/rbd.c | 100 ++++++++++++++++++++++++++++++++++++------------------------
 1 file changed, 60 insertions(+), 40 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index 27fa11b473..4bbcce4eca 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -544,32 +544,17 @@ out:
     return rados_str;
 }
 
-static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
-                         Error **errp)
+static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
+                            char **s_snap, char **s_image_name,
+                            QDict *options, bool cache, Error **errp)
 {
-    BDRVRBDState *s = bs->opaque;
-    const char *pool, *snap, *conf, *user, *image_name, *keypairs;
-    const char *secretid, *filename;
     QemuOpts *opts;
-    Error *local_err = NULL;
     char *mon_host = NULL;
+    const char *pool, *snap, *conf, *user, *image_name, *keypairs;
+    const char *secretid;
+    Error *local_err = NULL;
     int r;
 
-    /* If we are given a filename, parse the filename, with precedence given to
-     * filename encoded options */
-    filename = qdict_get_try_str(options, "filename");
-    if (filename) {
-        warn_report("'filename' option specified. "
-                    "This is an unsupported option, and may be deprecated "
-                    "in the future");
-        qemu_rbd_parse_filename(filename, options, &local_err);
-        if (local_err) {
-            r = -EINVAL;
-            error_propagate(errp, local_err);
-            goto exit;
-        }
-    }
-
     opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
     qemu_opts_absorb_qdict(opts, options, &local_err);
     if (local_err) {
@@ -600,35 +585,35 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
         goto failed_opts;
     }
 
-    r = rados_create(&s->cluster, user);
+    r = rados_create(cluster, user);
     if (r < 0) {
         error_setg_errno(errp, -r, "error initializing");
         goto failed_opts;
     }
 
-    s->snap = g_strdup(snap);
-    s->image_name = g_strdup(image_name);
+    *s_snap = g_strdup(snap);
+    *s_image_name = g_strdup(image_name);
 
     /* try default location when conf=NULL, but ignore failure */
-    r = rados_conf_read_file(s->cluster, conf);
+    r = rados_conf_read_file(*cluster, conf);
     if (conf && r < 0) {
         error_setg_errno(errp, -r, "error reading conf file %s", conf);
         goto failed_shutdown;
     }
 
-    r = qemu_rbd_set_keypairs(s->cluster, keypairs, errp);
+    r = qemu_rbd_set_keypairs(*cluster, keypairs, errp);
     if (r < 0) {
         goto failed_shutdown;
     }
 
     if (mon_host) {
-        r = rados_conf_set(s->cluster, "mon_host", mon_host);
+        r = rados_conf_set(*cluster, "mon_host", mon_host);
         if (r < 0) {
             goto failed_shutdown;
         }
     }
 
-    if (qemu_rbd_set_auth(s->cluster, secretid, errp) < 0) {
+    if (qemu_rbd_set_auth(*cluster, secretid, errp) < 0) {
         r = -EIO;
         goto failed_shutdown;
     }
@@ -640,24 +625,65 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
      * librbd defaults to no caching. If write through caching cannot
      * be set up, fall back to no caching.
      */
-    if (flags & BDRV_O_NOCACHE) {
-        rados_conf_set(s->cluster, "rbd_cache", "false");
+    if (cache) {
+        rados_conf_set(*cluster, "rbd_cache", "true");
     } else {
-        rados_conf_set(s->cluster, "rbd_cache", "true");
+        rados_conf_set(*cluster, "rbd_cache", "false");
     }
 
-    r = rados_connect(s->cluster);
+    r = rados_connect(*cluster);
     if (r < 0) {
         error_setg_errno(errp, -r, "error connecting");
         goto failed_shutdown;
     }
 
-    r = rados_ioctx_create(s->cluster, pool, &s->io_ctx);
+    r = rados_ioctx_create(*cluster, pool, io_ctx);
     if (r < 0) {
         error_setg_errno(errp, -r, "error opening pool %s", pool);
         goto failed_shutdown;
     }
 
+    qemu_opts_del(opts);
+    return 0;
+
+failed_shutdown:
+    rados_shutdown(*cluster);
+    g_free(*s_snap);
+    g_free(*s_image_name);
+failed_opts:
+    qemu_opts_del(opts);
+    g_free(mon_host);
+    return r;
+}
+
+static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
+                         Error **errp)
+{
+    BDRVRBDState *s = bs->opaque;
+    Error *local_err = NULL;
+    const char *filename;
+    int r;
+
+    /* If we are given a filename, parse the filename, with precedence given to
+     * filename encoded options */
+    filename = qdict_get_try_str(options, "filename");
+    if (filename) {
+        warn_report("'filename' option specified. "
+                    "This is an unsupported option, and may be deprecated "
+                    "in the future");
+        qemu_rbd_parse_filename(filename, options, &local_err);
+        if (local_err) {
+            error_propagate(errp, local_err);
+            return -EINVAL;
+        }
+    }
+
+    r = qemu_rbd_connect(&s->cluster, &s->io_ctx, &s->snap, &s->image_name,
+                         options, !(flags & BDRV_O_NOCACHE), errp);
+    if (r < 0) {
+        return r;
+    }
+
     /* rbd_open is always r/w */
     r = rbd_open(s->io_ctx, s->image_name, &s->image, s->snap);
     if (r < 0) {
@@ -682,19 +708,13 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
         }
     }
 
-    qemu_opts_del(opts);
     return 0;
 
 failed_open:
     rados_ioctx_destroy(s->io_ctx);
-failed_shutdown:
-    rados_shutdown(s->cluster);
     g_free(s->snap);
     g_free(s->image_name);
-failed_opts:
-    qemu_opts_del(opts);
-    g_free(mon_host);
-exit:
+    rados_shutdown(s->cluster);
     return r;
 }
 
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 20/36] rbd: Remove non-schema options from runtime_opts
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (18 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 19/36] rbd: Factor out qemu_rbd_connect() Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-22 23:13   ` Max Reitz
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 21/36] rbd: Pass BlockdevOptionsRbd to qemu_rbd_connect() Kevin Wolf
                   ` (15 subsequent siblings)
  35 siblings, 1 reply; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

Instead of the QemuOpts in qemu_rbd_connect(), we want to use QAPI
objects. As a preparation, fetch those options directly from the QDict
that .bdrv_open() supports in the rbd driver and that are not in the
schema.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/rbd.c | 55 ++++++++++++++++++++++++-------------------------------
 1 file changed, 24 insertions(+), 31 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index 4bbcce4eca..2e79c2d1fd 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -326,28 +326,6 @@ static QemuOptsList runtime_opts = {
         /*
          * server.* extracted manually, see qemu_rbd_mon_host()
          */
-        {
-            .name = "password-secret",
-            .type = QEMU_OPT_STRING,
-            .help = "ID of secret providing the password",
-        },
-
-        /*
-         * Keys for qemu_rbd_parse_filename(), not in the QAPI schema
-         */
-        {
-            /*
-             * HACK: name starts with '=' so that qemu_opts_parse()
-             * can't set it
-             */
-            .name = "=keyvalue-pairs",
-            .type = QEMU_OPT_STRING,
-            .help = "Legacy rados key/value option parameters",
-        },
-        {
-            .name = "filename",
-            .type = QEMU_OPT_STRING,
-        },
         { /* end of list */ }
     },
 };
@@ -546,12 +524,13 @@ out:
 
 static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
                             char **s_snap, char **s_image_name,
-                            QDict *options, bool cache, Error **errp)
+                            QDict *options, bool cache,
+                            const char *keypairs, const char *secretid,
+                            Error **errp)
 {
     QemuOpts *opts;
     char *mon_host = NULL;
-    const char *pool, *snap, *conf, *user, *image_name, *keypairs;
-    const char *secretid;
+    const char *pool, *snap, *conf, *user, *image_name;
     Error *local_err = NULL;
     int r;
 
@@ -570,14 +549,11 @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
         goto failed_opts;
     }
 
-    secretid = qemu_opt_get(opts, "password-secret");
-
     pool           = qemu_opt_get(opts, "pool");
     conf           = qemu_opt_get(opts, "conf");
     snap           = qemu_opt_get(opts, "snapshot");
     user           = qemu_opt_get(opts, "user");
     image_name     = qemu_opt_get(opts, "image");
-    keypairs       = qemu_opt_get(opts, "=keyvalue-pairs");
 
     if (!pool || !image_name) {
         error_setg(errp, "Parameters 'pool' and 'image' are required");
@@ -662,6 +638,7 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
     BDRVRBDState *s = bs->opaque;
     Error *local_err = NULL;
     const char *filename;
+    char *keypairs, *secretid;
     int r;
 
     /* If we are given a filename, parse the filename, with precedence given to
@@ -672,16 +649,28 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
                     "This is an unsupported option, and may be deprecated "
                     "in the future");
         qemu_rbd_parse_filename(filename, options, &local_err);
+        qdict_del(options, "filename");
         if (local_err) {
             error_propagate(errp, local_err);
             return -EINVAL;
         }
     }
 
+    keypairs = g_strdup(qdict_get_try_str(options, "=keyvalue-pairs"));
+    if (keypairs) {
+        qdict_del(options, "=keyvalue-pairs");
+    }
+
+    secretid = g_strdup(qdict_get_try_str(options, "password-secret"));
+    if (secretid) {
+        qdict_del(options, "password-secret");
+    }
+
     r = qemu_rbd_connect(&s->cluster, &s->io_ctx, &s->snap, &s->image_name,
-                         options, !(flags & BDRV_O_NOCACHE), errp);
+                         options, !(flags & BDRV_O_NOCACHE), keypairs, secretid,
+                         errp);
     if (r < 0) {
-        return r;
+        goto out;
     }
 
     /* rbd_open is always r/w */
@@ -708,13 +697,17 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
         }
     }
 
-    return 0;
+    r = 0;
+    goto out;
 
 failed_open:
     rados_ioctx_destroy(s->io_ctx);
     g_free(s->snap);
     g_free(s->image_name);
     rados_shutdown(s->cluster);
+out:
+    g_free(keypairs);
+    g_free(secretid);
     return r;
 }
 
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 21/36] rbd: Pass BlockdevOptionsRbd to qemu_rbd_connect()
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (19 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 20/36] rbd: Remove non-schema options from runtime_opts Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-22 23:25   ` Max Reitz
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 22/36] rbd: Support .bdrv_co_create Kevin Wolf
                   ` (14 subsequent siblings)
  35 siblings, 1 reply; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

With the conversion to a QAPI options object, the function is now
prepared to be used in a .bdrv_co_create implementation.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/rbd.c | 102 +++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 52 insertions(+), 50 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index 2e79c2d1fd..26641e53e0 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -24,6 +24,8 @@
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qjson.h"
 #include "qapi/qmp/qlist.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qapi-visit.h"
 
 /*
  * When specifying the image filename use:
@@ -482,24 +484,27 @@ static void qemu_rbd_complete_aio(RADOSCB *rcb)
     qemu_aio_unref(acb);
 }
 
-static char *qemu_rbd_mon_host(QDict *options, Error **errp)
+static char *qemu_rbd_mon_host(BlockdevOptionsRbd *opts, Error **errp)
 {
-    const char **vals = g_new(const char *, qdict_size(options) + 1);
-    char keybuf[32];
+    const char **vals;
     const char *host, *port;
     char *rados_str;
-    int i;
-
-    for (i = 0;; i++) {
-        sprintf(keybuf, "server.%d.host", i);
-        host = qdict_get_try_str(options, keybuf);
-        qdict_del(options, keybuf);
-        sprintf(keybuf, "server.%d.port", i);
-        port = qdict_get_try_str(options, keybuf);
-        qdict_del(options, keybuf);
-        if (!host && !port) {
-            break;
-        }
+    InetSocketAddressBaseList *p;
+    int i, cnt;
+
+    if (!opts->has_server) {
+        return NULL;
+    }
+
+    for (cnt = 0, p = opts->server; p; p = p->next) {
+        cnt++;
+    }
+
+    vals = g_new(const char *, cnt + 1);
+
+    for (i = 0, p = opts->server; p; p = p->next, i++) {
+        host = p->value->host;
+        port = p->value->port;
         if (!host) {
             error_setg(errp, "Parameter server.%d.host is missing", i);
             rados_str = NULL;
@@ -524,56 +529,34 @@ out:
 
 static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
                             char **s_snap, char **s_image_name,
-                            QDict *options, bool cache,
+                            BlockdevOptionsRbd *opts, bool cache,
                             const char *keypairs, const char *secretid,
                             Error **errp)
 {
-    QemuOpts *opts;
     char *mon_host = NULL;
-    const char *pool, *snap, *conf, *user, *image_name;
     Error *local_err = NULL;
     int r;
 
-    opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
-    qemu_opts_absorb_qdict(opts, options, &local_err);
+    mon_host = qemu_rbd_mon_host(opts, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         r = -EINVAL;
         goto failed_opts;
     }
 
-    mon_host = qemu_rbd_mon_host(options, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        r = -EINVAL;
-        goto failed_opts;
-    }
-
-    pool           = qemu_opt_get(opts, "pool");
-    conf           = qemu_opt_get(opts, "conf");
-    snap           = qemu_opt_get(opts, "snapshot");
-    user           = qemu_opt_get(opts, "user");
-    image_name     = qemu_opt_get(opts, "image");
-
-    if (!pool || !image_name) {
-        error_setg(errp, "Parameters 'pool' and 'image' are required");
-        r = -EINVAL;
-        goto failed_opts;
-    }
-
-    r = rados_create(cluster, user);
+    r = rados_create(cluster, opts->user);
     if (r < 0) {
         error_setg_errno(errp, -r, "error initializing");
         goto failed_opts;
     }
 
-    *s_snap = g_strdup(snap);
-    *s_image_name = g_strdup(image_name);
+    *s_snap = g_strdup(opts->snapshot);
+    *s_image_name = g_strdup(opts->image);
 
     /* try default location when conf=NULL, but ignore failure */
-    r = rados_conf_read_file(*cluster, conf);
-    if (conf && r < 0) {
-        error_setg_errno(errp, -r, "error reading conf file %s", conf);
+    r = rados_conf_read_file(*cluster, opts->conf);
+    if (opts->has_conf && r < 0) {
+        error_setg_errno(errp, -r, "error reading conf file %s", opts->conf);
         goto failed_shutdown;
     }
 
@@ -613,13 +596,12 @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
         goto failed_shutdown;
     }
 
-    r = rados_ioctx_create(*cluster, pool, io_ctx);
+    r = rados_ioctx_create(*cluster, opts->pool, io_ctx);
     if (r < 0) {
-        error_setg_errno(errp, -r, "error opening pool %s", pool);
+        error_setg_errno(errp, -r, "error opening pool %s", opts->pool);
         goto failed_shutdown;
     }
 
-    qemu_opts_del(opts);
     return 0;
 
 failed_shutdown:
@@ -627,7 +609,6 @@ failed_shutdown:
     g_free(*s_snap);
     g_free(*s_image_name);
 failed_opts:
-    qemu_opts_del(opts);
     g_free(mon_host);
     return r;
 }
@@ -636,6 +617,9 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
                          Error **errp)
 {
     BDRVRBDState *s = bs->opaque;
+    BlockdevOptionsRbd *opts = NULL;
+    Visitor *v;
+    QObject *crumpled = NULL;
     Error *local_err = NULL;
     const char *filename;
     char *keypairs, *secretid;
@@ -666,8 +650,25 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
         qdict_del(options, "password-secret");
     }
 
+    /* Convert the remaining options into a QAPI object */
+    crumpled = qdict_crumple(options, errp);
+    if (crumpled == NULL) {
+        return -EINVAL;
+    }
+
+    v = qobject_input_visitor_new_keyval(crumpled);
+    visit_type_BlockdevOptionsRbd(v, NULL, &opts, &local_err);
+    visit_free(v);
+    qobject_decref(crumpled);
+
+    if (local_err) {
+        error_propagate(errp, local_err);
+        r = -EINVAL;
+        goto out;
+    }
+
     r = qemu_rbd_connect(&s->cluster, &s->io_ctx, &s->snap, &s->image_name,
-                         options, !(flags & BDRV_O_NOCACHE), keypairs, secretid,
+                         opts, !(flags & BDRV_O_NOCACHE), keypairs, secretid,
                          errp);
     if (r < 0) {
         goto out;
@@ -706,6 +707,7 @@ failed_open:
     g_free(s->image_name);
     rados_shutdown(s->cluster);
 out:
+    qapi_free_BlockdevOptionsRbd(opts);
     g_free(keypairs);
     g_free(secretid);
     return r;
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 22/36] rbd: Support .bdrv_co_create
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (20 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 21/36] rbd: Pass BlockdevOptionsRbd to qemu_rbd_connect() Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-22 23:30   ` Max Reitz
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 23/36] rbd: Assing s->snap/image_name in qemu_rbd_open() Kevin Wolf
                   ` (13 subsequent siblings)
  35 siblings, 1 reply; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

This adds the .bdrv_co_create driver callback to rbd, which enables
image creation over QMP.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 qapi/block-core.json |  19 ++++++-
 block/rbd.c          | 146 ++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 116 insertions(+), 49 deletions(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 74021c51d7..6c0c16ebe3 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3436,6 +3436,23 @@
             '*refcount-bits':   'int' } }
 
 ##
+# @BlockdevCreateOptionsRbd:
+#
+# Driver specific image creation options for rbd/Ceph.
+#
+# @location         Where to store the new image file. This location cannot
+#                   point to a snapshot.
+# @size             Size of the virtual disk in bytes
+# @cluster-size     RBD object size
+#
+# Since: 2.12
+##
+{ 'struct': 'BlockdevCreateOptionsRbd',
+  'data': { 'location':         'BlockdevOptionsRbd',
+            'size':             'size',
+            '*cluster-size' :   'size' } }
+
+##
 # @BlockdevCreateNotSupported:
 #
 # This is used for all drivers that don't support creating images.
@@ -3484,7 +3501,7 @@
       'qed':            'BlockdevCreateNotSupported',
       'quorum':         'BlockdevCreateNotSupported',
       'raw':            'BlockdevCreateNotSupported',
-      'rbd':            'BlockdevCreateNotSupported',
+      'rbd':            'BlockdevCreateOptionsRbd',
       'replication':    'BlockdevCreateNotSupported',
       'sheepdog':       'BlockdevCreateNotSupported',
       'ssh':            'BlockdevCreateNotSupported',
diff --git a/block/rbd.c b/block/rbd.c
index 26641e53e0..82f03505a9 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -332,69 +332,55 @@ static QemuOptsList runtime_opts = {
     },
 };
 
-static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
+/* FIXME Deprecate and remove keypairs or make it available in QMP.
+ * password_secret should eventually be configurable in opts->location. Support
+ * for it in .bdrv_open will make it work here as well. */
+static int qemu_rbd_do_create(BlockdevCreateOptions *options,
+                              const char *keypairs, const char *password_secret,
+                              Error **errp)
 {
-    Error *local_err = NULL;
-    int64_t bytes = 0;
-    int64_t objsize;
-    int obj_order = 0;
-    const char *pool, *image_name, *conf, *user, *keypairs;
-    const char *secretid;
+    BlockdevCreateOptionsRbd *opts = &options->u.rbd;
     rados_t cluster;
     rados_ioctx_t io_ctx;
-    QDict *options = NULL;
-    int ret = 0;
+    int obj_order = 0;
+    int ret;
 
-    secretid = qemu_opt_get(opts, "password-secret");
+    assert(options->driver == BLOCKDEV_DRIVER_RBD);
+    if (opts->location->has_snapshot) {
+        error_setg(errp, "Can't use snapshot name for image creation");
+        return -EINVAL;
+    }
 
-    /* Read out options */
-    bytes = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
-                     BDRV_SECTOR_SIZE);
-    objsize = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE, 0);
-    if (objsize) {
+    /* TODO Remove the limitation */
+    if (opts->location->has_server) {
+        error_setg(errp, "Can't specify server for image creation");
+        return -EINVAL;
+    }
+
+    if (opts->has_cluster_size) {
+        int64_t objsize = opts->cluster_size;
         if ((objsize - 1) & objsize) {    /* not a power of 2? */
             error_setg(errp, "obj size needs to be power of 2");
-            ret = -EINVAL;
-            goto exit;
+            return -EINVAL;
         }
         if (objsize < 4096) {
             error_setg(errp, "obj size too small");
-            ret = -EINVAL;
-            goto exit;
+            return -EINVAL;
         }
         obj_order = ctz32(objsize);
     }
 
-    options = qdict_new();
-    qemu_rbd_parse_filename(filename, options, &local_err);
-    if (local_err) {
-        ret = -EINVAL;
-        error_propagate(errp, local_err);
-        goto exit;
-    }
-
-    /*
-     * Caution: while qdict_get_try_str() is fine, getting non-string
-     * types would require more care.  When @options come from -blockdev
-     * or blockdev_add, its members are typed according to the QAPI
-     * schema, but when they come from -drive, they're all QString.
-     */
-    pool       = qdict_get_try_str(options, "pool");
-    conf       = qdict_get_try_str(options, "conf");
-    user       = qdict_get_try_str(options, "user");
-    image_name = qdict_get_try_str(options, "image");
-    keypairs   = qdict_get_try_str(options, "=keyvalue-pairs");
-
-    ret = rados_create(&cluster, user);
+    ret = rados_create(&cluster, opts->location->user);
     if (ret < 0) {
         error_setg_errno(errp, -ret, "error initializing");
-        goto exit;
+        return ret;
     }
 
     /* try default location when conf=NULL, but ignore failure */
-    ret = rados_conf_read_file(cluster, conf);
-    if (conf && ret < 0) {
-        error_setg_errno(errp, -ret, "error reading conf file %s", conf);
+    ret = rados_conf_read_file(cluster, opts->location->conf);
+    if (opts->location->conf && ret < 0) {
+        error_setg_errno(errp, -ret, "error reading conf file %s",
+                         opts->location->conf);
         ret = -EIO;
         goto shutdown;
     }
@@ -405,7 +391,7 @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
         goto shutdown;
     }
 
-    if (qemu_rbd_set_auth(cluster, secretid, errp) < 0) {
+    if (qemu_rbd_set_auth(cluster, password_secret, errp) < 0) {
         ret = -EIO;
         goto shutdown;
     }
@@ -416,24 +402,87 @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
         goto shutdown;
     }
 
-    ret = rados_ioctx_create(cluster, pool, &io_ctx);
+    ret = rados_ioctx_create(cluster, opts->location->pool, &io_ctx);
     if (ret < 0) {
-        error_setg_errno(errp, -ret, "error opening pool %s", pool);
+        error_setg_errno(errp, -ret, "error opening pool %s",
+                         opts->location->pool);
         goto shutdown;
     }
 
-    ret = rbd_create(io_ctx, image_name, bytes, &obj_order);
+    ret = rbd_create(io_ctx, opts->location->image, opts->size, &obj_order);
     if (ret < 0) {
         error_setg_errno(errp, -ret, "error rbd create");
     }
 
     rados_ioctx_destroy(io_ctx);
 
+    ret = 0;
 shutdown:
     rados_shutdown(cluster);
+    return ret;
+}
+
+static int qemu_rbd_co_create(BlockdevCreateOptions *options, Error **errp)
+{
+    return qemu_rbd_do_create(options, NULL, NULL, errp);
+}
+
+static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
+{
+    BlockdevCreateOptions *create_options;
+    BlockdevCreateOptionsRbd *rbd_opts;
+    BlockdevOptionsRbd *loc;
+    Error *local_err = NULL;
+    const char *keypairs, *password_secret;
+    QDict *options = NULL;
+    int ret = 0;
+
+    create_options = g_new0(BlockdevCreateOptions, 1);
+    create_options->driver = BLOCKDEV_DRIVER_RBD;
+    rbd_opts = &create_options->u.rbd;
+
+    rbd_opts->location = g_new0(BlockdevOptionsRbd, 1);
+
+    password_secret = qemu_opt_get(opts, "password-secret");
+
+    /* Read out options */
+    rbd_opts->size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
+                              BDRV_SECTOR_SIZE);
+    rbd_opts->cluster_size = qemu_opt_get_size_del(opts,
+                                                   BLOCK_OPT_CLUSTER_SIZE, 0);
+    rbd_opts->has_cluster_size = (rbd_opts->cluster_size != 0);
+
+    options = qdict_new();
+    qemu_rbd_parse_filename(filename, options, &local_err);
+    if (local_err) {
+        ret = -EINVAL;
+        error_propagate(errp, local_err);
+        goto exit;
+    }
+
+    /*
+     * Caution: while qdict_get_try_str() is fine, getting non-string
+     * types would require more care.  When @options come from -blockdev
+     * or blockdev_add, its members are typed according to the QAPI
+     * schema, but when they come from -drive, they're all QString.
+     */
+    loc = rbd_opts->location;
+    loc->pool     = g_strdup(qdict_get_try_str(options, "pool"));
+    loc->conf     = g_strdup(qdict_get_try_str(options, "conf"));
+    loc->has_conf = !!loc->conf;
+    loc->user     = g_strdup(qdict_get_try_str(options, "user"));
+    loc->has_user = !!loc->user;
+    loc->image    = g_strdup(qdict_get_try_str(options, "image"));
+    keypairs      = qdict_get_try_str(options, "=keyvalue-pairs");
+
+    ret = qemu_rbd_do_create(create_options, keypairs, password_secret, errp);
+    if (ret < 0) {
+        goto exit;
+    }
 
 exit:
     QDECREF(options);
+    qapi_free_BlockdevCreateOptions(create_options);
     return ret;
 }
 
@@ -1149,6 +1198,7 @@ static BlockDriver bdrv_rbd = {
     .bdrv_close             = qemu_rbd_close,
     .bdrv_reopen_prepare    = qemu_rbd_reopen_prepare,
     .bdrv_create            = qemu_rbd_create,
+    .bdrv_co_create         = qemu_rbd_co_create,
     .bdrv_has_zero_init     = bdrv_has_zero_init_1,
     .bdrv_get_info          = qemu_rbd_getinfo,
     .create_opts            = &qemu_rbd_create_opts,
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 23/36] rbd: Assing s->snap/image_name in qemu_rbd_open()
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (21 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 22/36] rbd: Support .bdrv_co_create Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-22 23:34   ` [Qemu-devel] [PATCH v2 23/36] rbd: ***ing " Max Reitz
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 24/36] rbd: Use qemu_rbd_connect() in qemu_rbd_do_create() Kevin Wolf
                   ` (12 subsequent siblings)
  35 siblings, 1 reply; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

Now that the options are already available in qemu_rbd_open() and not
only parsed in qemu_rbd_connect(), we can assign s->snap and
s->image_name there instead of passing the fields by reference to
qemu_rbd_connect().

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/rbd.c | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index 82f03505a9..a34bf0be46 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -577,7 +577,6 @@ out:
 }
 
 static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
-                            char **s_snap, char **s_image_name,
                             BlockdevOptionsRbd *opts, bool cache,
                             const char *keypairs, const char *secretid,
                             Error **errp)
@@ -599,9 +598,6 @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
         goto failed_opts;
     }
 
-    *s_snap = g_strdup(opts->snapshot);
-    *s_image_name = g_strdup(opts->image);
-
     /* try default location when conf=NULL, but ignore failure */
     r = rados_conf_read_file(*cluster, opts->conf);
     if (opts->has_conf && r < 0) {
@@ -655,8 +651,6 @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
 
 failed_shutdown:
     rados_shutdown(*cluster);
-    g_free(*s_snap);
-    g_free(*s_image_name);
 failed_opts:
     g_free(mon_host);
     return r;
@@ -716,13 +710,15 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
         goto out;
     }
 
-    r = qemu_rbd_connect(&s->cluster, &s->io_ctx, &s->snap, &s->image_name,
-                         opts, !(flags & BDRV_O_NOCACHE), keypairs, secretid,
-                         errp);
+    r = qemu_rbd_connect(&s->cluster, &s->io_ctx, opts,
+                         !(flags & BDRV_O_NOCACHE), keypairs, secretid, errp);
     if (r < 0) {
         goto out;
     }
 
+    s->snap = g_strdup(opts->snapshot);
+    s->image_name = g_strdup(opts->image);
+
     /* rbd_open is always r/w */
     r = rbd_open(s->io_ctx, s->image_name, &s->image, s->snap);
     if (r < 0) {
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 24/36] rbd: Use qemu_rbd_connect() in qemu_rbd_do_create()
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (22 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 23/36] rbd: Assing s->snap/image_name in qemu_rbd_open() Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-22 23:37   ` Max Reitz
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 25/36] nfs: Use QAPI options in nfs_client_open() Kevin Wolf
                   ` (11 subsequent siblings)
  35 siblings, 1 reply; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

This is almost exactly the same code. The differences are that
qemu_rbd_connect() supports BlockdevOptionsRbd.server and that the cache
mode is set explicitly.

Supporting 'server' is a welcome new feature for image creation.
Caching is disabled by default, so leave it that way.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/rbd.c | 54 ++++++++++--------------------------------------------
 1 file changed, 10 insertions(+), 44 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index a34bf0be46..af8e186106 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -103,6 +103,11 @@ typedef struct BDRVRBDState {
     char *snap;
 } BDRVRBDState;
 
+static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
+                            BlockdevOptionsRbd *opts, bool cache,
+                            const char *keypairs, const char *secretid,
+                            Error **errp);
+
 static char *qemu_rbd_next_tok(char *src, char delim, char **p)
 {
     char *end;
@@ -351,12 +356,6 @@ static int qemu_rbd_do_create(BlockdevCreateOptions *options,
         return -EINVAL;
     }
 
-    /* TODO Remove the limitation */
-    if (opts->location->has_server) {
-        error_setg(errp, "Can't specify server for image creation");
-        return -EINVAL;
-    }
-
     if (opts->has_cluster_size) {
         int64_t objsize = opts->cluster_size;
         if ((objsize - 1) & objsize) {    /* not a power of 2? */
@@ -370,54 +369,21 @@ static int qemu_rbd_do_create(BlockdevCreateOptions *options,
         obj_order = ctz32(objsize);
     }
 
-    ret = rados_create(&cluster, opts->location->user);
+    ret = qemu_rbd_connect(&cluster, &io_ctx, opts->location, false, keypairs,
+                           NULL, errp);
     if (ret < 0) {
-        error_setg_errno(errp, -ret, "error initializing");
         return ret;
     }
 
-    /* try default location when conf=NULL, but ignore failure */
-    ret = rados_conf_read_file(cluster, opts->location->conf);
-    if (opts->location->conf && ret < 0) {
-        error_setg_errno(errp, -ret, "error reading conf file %s",
-                         opts->location->conf);
-        ret = -EIO;
-        goto shutdown;
-    }
-
-    ret = qemu_rbd_set_keypairs(cluster, keypairs, errp);
-    if (ret < 0) {
-        ret = -EIO;
-        goto shutdown;
-    }
-
-    if (qemu_rbd_set_auth(cluster, password_secret, errp) < 0) {
-        ret = -EIO;
-        goto shutdown;
-    }
-
-    ret = rados_connect(cluster);
-    if (ret < 0) {
-        error_setg_errno(errp, -ret, "error connecting");
-        goto shutdown;
-    }
-
-    ret = rados_ioctx_create(cluster, opts->location->pool, &io_ctx);
-    if (ret < 0) {
-        error_setg_errno(errp, -ret, "error opening pool %s",
-                         opts->location->pool);
-        goto shutdown;
-    }
-
     ret = rbd_create(io_ctx, opts->location->image, opts->size, &obj_order);
     if (ret < 0) {
         error_setg_errno(errp, -ret, "error rbd create");
+        goto out;
     }
 
-    rados_ioctx_destroy(io_ctx);
-
     ret = 0;
-shutdown:
+out:
+    rados_ioctx_destroy(io_ctx);
     rados_shutdown(cluster);
     return ret;
 }
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 25/36] nfs: Use QAPI options in nfs_client_open()
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (23 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 24/36] rbd: Use qemu_rbd_connect() in qemu_rbd_do_create() Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 26/36] nfs: Support .bdrv_co_create Kevin Wolf
                   ` (10 subsequent siblings)
  35 siblings, 0 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

Using the QAPI visitor to turn all options into QAPI BlockdevOptionsNfs
simplifies the code a lot. It will also be useful for implementing the
QAPI based .bdrv_co_create callback.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 block/nfs.c | 176 ++++++++++++++++++------------------------------------------
 1 file changed, 53 insertions(+), 123 deletions(-)

diff --git a/block/nfs.c b/block/nfs.c
index 6576a73d6e..9283bfbaae 100644
--- a/block/nfs.c
+++ b/block/nfs.c
@@ -367,49 +367,6 @@ static int coroutine_fn nfs_co_flush(BlockDriverState *bs)
     return task.ret;
 }
 
-static QemuOptsList runtime_opts = {
-    .name = "nfs",
-    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
-    .desc = {
-        {
-            .name = "path",
-            .type = QEMU_OPT_STRING,
-            .help = "Path of the image on the host",
-        },
-        {
-            .name = "user",
-            .type = QEMU_OPT_NUMBER,
-            .help = "UID value to use when talking to the server",
-        },
-        {
-            .name = "group",
-            .type = QEMU_OPT_NUMBER,
-            .help = "GID value to use when talking to the server",
-        },
-        {
-            .name = "tcp-syn-count",
-            .type = QEMU_OPT_NUMBER,
-            .help = "Number of SYNs to send during the session establish",
-        },
-        {
-            .name = "readahead-size",
-            .type = QEMU_OPT_NUMBER,
-            .help = "Set the readahead size in bytes",
-        },
-        {
-            .name = "page-cache-size",
-            .type = QEMU_OPT_NUMBER,
-            .help = "Set the pagecache size in bytes",
-        },
-        {
-            .name = "debug",
-            .type = QEMU_OPT_NUMBER,
-            .help = "Set the NFS debug level (max 2)",
-        },
-        { /* end of list */ }
-    },
-};
-
 static void nfs_detach_aio_context(BlockDriverState *bs)
 {
     NFSClient *client = bs->opaque;
@@ -452,71 +409,16 @@ static void nfs_file_close(BlockDriverState *bs)
     nfs_client_close(client);
 }
 
-static NFSServer *nfs_config(QDict *options, Error **errp)
-{
-    NFSServer *server = NULL;
-    QDict *addr = NULL;
-    QObject *crumpled_addr = NULL;
-    Visitor *iv = NULL;
-    Error *local_error = NULL;
-
-    qdict_extract_subqdict(options, &addr, "server.");
-    if (!qdict_size(addr)) {
-        error_setg(errp, "NFS server address missing");
-        goto out;
-    }
-
-    crumpled_addr = qdict_crumple(addr, errp);
-    if (!crumpled_addr) {
-        goto out;
-    }
-
-    /*
-     * Caution: this works only because all scalar members of
-     * NFSServer are QString in @crumpled_addr.  The visitor expects
-     * @crumpled_addr to be typed according to the QAPI schema.  It
-     * is when @options come from -blockdev or blockdev_add.  But when
-     * they come from -drive, they're all QString.
-     */
-    iv = qobject_input_visitor_new(crumpled_addr);
-    visit_type_NFSServer(iv, NULL, &server, &local_error);
-    if (local_error) {
-        error_propagate(errp, local_error);
-        goto out;
-    }
-
-out:
-    QDECREF(addr);
-    qobject_decref(crumpled_addr);
-    visit_free(iv);
-    return server;
-}
-
-
-static int64_t nfs_client_open(NFSClient *client, QDict *options,
+static int64_t nfs_client_open(NFSClient *client, BlockdevOptionsNfs *opts,
                                int flags, int open_flags, Error **errp)
 {
     int64_t ret = -EINVAL;
-    QemuOpts *opts = NULL;
-    Error *local_err = NULL;
     struct stat st;
     char *file = NULL, *strp = NULL;
 
     qemu_mutex_init(&client->mutex);
-    opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
-    qemu_opts_absorb_qdict(opts, options, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        ret = -EINVAL;
-        goto fail;
-    }
 
-    client->path = g_strdup(qemu_opt_get(opts, "path"));
-    if (!client->path) {
-        ret = -EINVAL;
-        error_setg(errp, "No path was specified");
-        goto fail;
-    }
+    client->path = g_strdup(opts->path);
 
     strp = strrchr(client->path, '/');
     if (strp == NULL) {
@@ -526,12 +428,10 @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
     file = g_strdup(strp);
     *strp = 0;
 
-    /* Pop the config into our state object, Exit if invalid */
-    client->server = nfs_config(options, errp);
-    if (!client->server) {
-        ret = -EINVAL;
-        goto fail;
-    }
+    /* Steal the NFSServer object from opts; set the original pointer to NULL
+     * to avoid use after free and double free. */
+    client->server = opts->server;
+    opts->server = NULL;
 
     client->context = nfs_init_context();
     if (client->context == NULL) {
@@ -539,29 +439,29 @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
         goto fail;
     }
 
-    if (qemu_opt_get(opts, "user")) {
-        client->uid = qemu_opt_get_number(opts, "user", 0);
+    if (opts->has_user) {
+        client->uid = opts->user;
         nfs_set_uid(client->context, client->uid);
     }
 
-    if (qemu_opt_get(opts, "group")) {
-        client->gid = qemu_opt_get_number(opts, "group", 0);
+    if (opts->has_group) {
+        client->gid = opts->group;
         nfs_set_gid(client->context, client->gid);
     }
 
-    if (qemu_opt_get(opts, "tcp-syn-count")) {
-        client->tcp_syncnt = qemu_opt_get_number(opts, "tcp-syn-count", 0);
+    if (opts->has_tcp_syn_count) {
+        client->tcp_syncnt = opts->tcp_syn_count;
         nfs_set_tcp_syncnt(client->context, client->tcp_syncnt);
     }
 
 #ifdef LIBNFS_FEATURE_READAHEAD
-    if (qemu_opt_get(opts, "readahead-size")) {
+    if (opts->has_readahead_size) {
         if (open_flags & BDRV_O_NOCACHE) {
             error_setg(errp, "Cannot enable NFS readahead "
                              "if cache.direct = on");
             goto fail;
         }
-        client->readahead = qemu_opt_get_number(opts, "readahead-size", 0);
+        client->readahead = opts->readahead_size;
         if (client->readahead > QEMU_NFS_MAX_READAHEAD_SIZE) {
             warn_report("Truncating NFS readahead size to %d",
                         QEMU_NFS_MAX_READAHEAD_SIZE);
@@ -576,13 +476,13 @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
 #endif
 
 #ifdef LIBNFS_FEATURE_PAGECACHE
-    if (qemu_opt_get(opts, "page-cache-size")) {
+    if (opts->has_page_cache_size) {
         if (open_flags & BDRV_O_NOCACHE) {
             error_setg(errp, "Cannot enable NFS pagecache "
                              "if cache.direct = on");
             goto fail;
         }
-        client->pagecache = qemu_opt_get_number(opts, "page-cache-size", 0);
+        client->pagecache = opts->page_cache_size;
         if (client->pagecache > QEMU_NFS_MAX_PAGECACHE_SIZE) {
             warn_report("Truncating NFS pagecache size to %d pages",
                         QEMU_NFS_MAX_PAGECACHE_SIZE);
@@ -595,8 +495,8 @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
 #endif
 
 #ifdef LIBNFS_FEATURE_DEBUG
-    if (qemu_opt_get(opts, "debug")) {
-        client->debug = qemu_opt_get_number(opts, "debug", 0);
+    if (opts->has_debug) {
+        client->debug = opts->debug;
         /* limit the maximum debug level to avoid potential flooding
          * of our log files. */
         if (client->debug > QEMU_NFS_MAX_DEBUG_LEVEL) {
@@ -647,11 +547,41 @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
 fail:
     nfs_client_close(client);
 out:
-    qemu_opts_del(opts);
     g_free(file);
     return ret;
 }
 
+static int64_t nfs_client_open_qdict(NFSClient *client, QDict *options,
+                                     int flags, int open_flags, Error **errp)
+{
+    BlockdevOptionsNfs *opts = NULL;
+    QObject *crumpled = NULL;
+    Visitor *v;
+    Error *local_err = NULL;
+    int ret;
+
+    crumpled = qdict_crumple(options, errp);
+    if (crumpled == NULL) {
+        return -EINVAL;
+    }
+
+    v = qobject_input_visitor_new_keyval(crumpled);
+    visit_type_BlockdevOptionsNfs(v, NULL, &opts, &local_err);
+    visit_free(v);
+
+    if (local_err) {
+        error_propagate(errp, local_err);
+        ret = -EINVAL;
+        goto fail;
+    }
+
+    ret = nfs_client_open(client, opts, flags, open_flags, errp);
+fail:
+    qobject_decref(crumpled);
+    qapi_free_BlockdevOptionsNfs(opts);
+    return ret;
+}
+
 static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
                          Error **errp) {
     NFSClient *client = bs->opaque;
@@ -659,9 +589,9 @@ static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
 
     client->aio_context = bdrv_get_aio_context(bs);
 
-    ret = nfs_client_open(client, options,
-                          (flags & BDRV_O_RDWR) ? O_RDWR : O_RDONLY,
-                          bs->open_flags, errp);
+    ret = nfs_client_open_qdict(client, options,
+                                (flags & BDRV_O_RDWR) ? O_RDWR : O_RDONLY,
+                                bs->open_flags, errp);
     if (ret < 0) {
         return ret;
     }
@@ -702,7 +632,7 @@ static int nfs_file_create(const char *url, QemuOpts *opts, Error **errp)
         goto out;
     }
 
-    ret = nfs_client_open(client, options, O_CREAT, 0, errp);
+    ret = nfs_client_open_qdict(client, options, O_CREAT, 0, errp);
     if (ret < 0) {
         goto out;
     }
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 26/36] nfs: Support .bdrv_co_create
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (24 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 25/36] nfs: Use QAPI options in nfs_client_open() Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 27/36] sheepdog: QAPIfy "redundacy" create option Kevin Wolf
                   ` (9 subsequent siblings)
  35 siblings, 0 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

This adds the .bdrv_co_create driver callback to nfs, which enables
image creation over QMP.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 qapi/block-core.json | 16 +++++++++++-
 block/nfs.c          | 74 +++++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 74 insertions(+), 16 deletions(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 6c0c16ebe3..085b791303 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3393,6 +3393,20 @@
             '*preallocation':   'PreallocMode' } }
 
 ##
+# @BlockdevCreateOptionsNfs:
+#
+# Driver specific image creation options for NFS.
+#
+# @location         Where to store the new image file
+# @size             Size of the virtual disk in bytes
+#
+# Since: 2.12
+##
+{ 'struct': 'BlockdevCreateOptionsNfs',
+  'data': { 'location':         'BlockdevOptionsNfs',
+            'size':             'size' } }
+
+##
 # @BlockdevQcow2Version:
 #
 # @v2:  The original QCOW2 format as introduced in qemu 0.10 (version 2)
@@ -3491,7 +3505,7 @@
       'iscsi':          'BlockdevCreateNotSupported',
       'luks':           'BlockdevCreateNotSupported',
       'nbd':            'BlockdevCreateNotSupported',
-      'nfs':            'BlockdevCreateNotSupported',
+      'nfs':            'BlockdevCreateOptionsNfs',
       'null-aio':       'BlockdevCreateNotSupported',
       'null-co':        'BlockdevCreateNotSupported',
       'nvme':           'BlockdevCreateNotSupported',
diff --git a/block/nfs.c b/block/nfs.c
index 9283bfbaae..c0c153cadb 100644
--- a/block/nfs.c
+++ b/block/nfs.c
@@ -551,33 +551,45 @@ out:
     return ret;
 }
 
-static int64_t nfs_client_open_qdict(NFSClient *client, QDict *options,
-                                     int flags, int open_flags, Error **errp)
+static BlockdevOptionsNfs *nfs_options_qdict_to_qapi(QDict *options,
+                                                     Error **errp)
 {
     BlockdevOptionsNfs *opts = NULL;
     QObject *crumpled = NULL;
     Visitor *v;
     Error *local_err = NULL;
-    int ret;
 
     crumpled = qdict_crumple(options, errp);
     if (crumpled == NULL) {
-        return -EINVAL;
+        return NULL;
     }
 
     v = qobject_input_visitor_new_keyval(crumpled);
     visit_type_BlockdevOptionsNfs(v, NULL, &opts, &local_err);
     visit_free(v);
+    qobject_decref(crumpled);
 
     if (local_err) {
-        error_propagate(errp, local_err);
+        return NULL;
+    }
+
+    return opts;
+}
+
+static int64_t nfs_client_open_qdict(NFSClient *client, QDict *options,
+                                     int flags, int open_flags, Error **errp)
+{
+    BlockdevOptionsNfs *opts;
+    int ret;
+
+    opts = nfs_options_qdict_to_qapi(options, errp);
+    if (opts == NULL) {
         ret = -EINVAL;
         goto fail;
     }
 
     ret = nfs_client_open(client, opts, flags, open_flags, errp);
 fail:
-    qobject_decref(crumpled);
     qapi_free_BlockdevOptionsNfs(opts);
     return ret;
 }
@@ -614,17 +626,42 @@ static QemuOptsList nfs_create_opts = {
     }
 };
 
-static int nfs_file_create(const char *url, QemuOpts *opts, Error **errp)
+static int nfs_file_co_create(BlockdevCreateOptions *options, Error **errp)
 {
-    int64_t ret, total_size;
+    BlockdevCreateOptionsNfs *opts = &options->u.nfs;
     NFSClient *client = g_new0(NFSClient, 1);
-    QDict *options = NULL;
+    int ret;
+
+    assert(options->driver == BLOCKDEV_DRIVER_NFS);
 
     client->aio_context = qemu_get_aio_context();
 
+    ret = nfs_client_open(client, opts->location, O_CREAT, 0, errp);
+    if (ret < 0) {
+        goto out;
+    }
+    ret = nfs_ftruncate(client->context, client->fh, opts->size);
+    nfs_client_close(client);
+
+out:
+    g_free(client);
+    return ret;
+}
+
+static int nfs_file_create(const char *url, QemuOpts *opts, Error **errp)
+{
+    BlockdevCreateOptions *create_options;
+    BlockdevCreateOptionsNfs *nfs_opts;
+    QDict *options;
+    int ret;
+
+    create_options = g_new0(BlockdevCreateOptions, 1);
+    create_options->driver = BLOCKDEV_DRIVER_NFS;
+    nfs_opts = &create_options->u.nfs;
+
     /* Read out options */
-    total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
-                          BDRV_SECTOR_SIZE);
+    nfs_opts->size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
+                              BDRV_SECTOR_SIZE);
 
     options = qdict_new();
     ret = nfs_parse_uri(url, options, errp);
@@ -632,15 +669,21 @@ static int nfs_file_create(const char *url, QemuOpts *opts, Error **errp)
         goto out;
     }
 
-    ret = nfs_client_open_qdict(client, options, O_CREAT, 0, errp);
+    nfs_opts->location = nfs_options_qdict_to_qapi(options, errp);
+    if (nfs_opts->location == NULL) {
+        ret = -EINVAL;
+        goto out;
+    }
+
+    ret = nfs_file_co_create(create_options, errp);
     if (ret < 0) {
         goto out;
     }
-    ret = nfs_ftruncate(client->context, client->fh, total_size);
-    nfs_client_close(client);
+
+    ret = 0;
 out:
     QDECREF(options);
-    g_free(client);
+    qapi_free_BlockdevCreateOptions(create_options);
     return ret;
 }
 
@@ -828,6 +871,7 @@ static BlockDriver bdrv_nfs = {
     .bdrv_file_open                 = nfs_file_open,
     .bdrv_close                     = nfs_file_close,
     .bdrv_create                    = nfs_file_create,
+    .bdrv_co_create                 = nfs_file_co_create,
     .bdrv_reopen_prepare            = nfs_reopen_prepare,
 
     .bdrv_co_preadv                 = nfs_co_preadv,
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 27/36] sheepdog: QAPIfy "redundacy" create option
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (25 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 26/36] nfs: Support .bdrv_co_create Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-22 23:43   ` Max Reitz
  2018-02-23 15:25   ` Kevin Wolf
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 28/36] sheepdog: Support .bdrv_co_create Kevin Wolf
                   ` (8 subsequent siblings)
  35 siblings, 2 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

The "redundacy" option for Sheepdog image creation is currently a string
that can encode one or two integers depending on its format, which at
the same time implicitly selects a mode.

This patch turns it into a QAPI union and converts the string into such
a QAPI object before interpreting the values.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 qapi/block-core.json | 45 +++++++++++++++++++++++++
 block/sheepdog.c     | 94 +++++++++++++++++++++++++++++++++++++---------------
 2 files changed, 112 insertions(+), 27 deletions(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 085b791303..2b249c9e3d 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3467,6 +3467,51 @@
             '*cluster-size' :   'size' } }
 
 ##
+# @SheepdogRedundancyType:
+#
+# @full             Create a fully replicated vdi with x copies
+# @erasure-coded    Create an erasure coded vdi with x data strips and
+#                   y parity strips
+#
+# Since: 2.12
+##
+{ 'enum': 'SheepdogRedundancyType',
+  'data': [ 'full', 'erasure-coded' ] }
+
+##
+# @SheepdogRedundancyFull:
+#
+# @copies           Number of copies to use (between 1 and 31)
+#
+# Since: 2.12
+##
+{ 'struct': 'SheepdogRedundancyFull',
+  'data': { 'copies': 'int' }}
+
+##
+# @SheepdogRedundancyErasureCoded:
+#
+# @data-strips      Number of data strips to use (one of {2,4,8,16})
+# @parity-strips    Number of parity strips to use (between 1 and 15)
+#
+# Since: 2.12
+##
+{ 'struct': 'SheepdogRedundancyErasureCoded',
+  'data': { 'data-strips': 'int',
+            'parity-strips': 'int' }}
+
+##
+# @SheepdogRedundancy:
+#
+# Since: 2.12
+##
+{ 'union': 'SheepdogRedundancy',
+  'base': { 'type': 'SheepdogRedundancyType' },
+  'discriminator': 'type',
+  'data': { 'full': 'SheepdogRedundancyFull',
+            'erasure-coded': 'SheepdogRedundancyErasureCoded' } }
+
+##
 # @BlockdevCreateNotSupported:
 #
 # This is used for all drivers that don't support creating images.
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 3c3becf94d..22df2ba9d0 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -1882,6 +1882,48 @@ out_with_err_set:
     return ret;
 }
 
+static int parse_redundancy(BDRVSheepdogState *s, SheepdogRedundancy *opt)
+{
+    struct SheepdogInode *inode = &s->inode;
+
+    switch (opt->type) {
+    case SHEEPDOG_REDUNDANCY_TYPE_FULL:
+        if (opt->u.full.copies > SD_MAX_COPIES || opt->u.full.copies < 1) {
+            return -EINVAL;
+        }
+        inode->copy_policy = 0;
+        inode->nr_copies = opt->u.full.copies;
+        return 0;
+
+    case SHEEPDOG_REDUNDANCY_TYPE_ERASURE_CODED:
+    {
+        int64_t copy = opt->u.erasure_coded.data_strips;
+        int64_t parity = opt->u.erasure_coded.parity_strips;
+
+        if (copy != 2 && copy != 4 && copy != 8 && copy != 16) {
+            return -EINVAL;
+        }
+
+        if (parity >= SD_EC_MAX_STRIP || parity < 1) {
+            return -EINVAL;
+        }
+
+        /*
+         * 4 bits for parity and 4 bits for data.
+         * We have to compress upper data bits because it can't represent 16
+         */
+        inode->copy_policy = ((copy / 2) << 4) + parity;
+        inode->nr_copies = copy + parity;
+        return 0;
+    }
+
+    default:
+        g_assert_not_reached();
+    }
+
+    return -EINVAL;
+}
+
 /*
  * Sheepdog support two kinds of redundancy, full replication and erasure
  * coding.
@@ -1892,12 +1934,13 @@ out_with_err_set:
  * # create a erasure coded vdi with x data strips and y parity strips
  * -o redundancy=x:y (x must be one of {2,4,8,16} and 1 <= y < SD_EC_MAX_STRIP)
  */
-static int parse_redundancy(BDRVSheepdogState *s, const char *opt)
+static int parse_redundancy_str(BDRVSheepdogState *s, const char *opt)
 {
-    struct SheepdogInode *inode = &s->inode;
+    struct SheepdogRedundancy redundancy;
     const char *n1, *n2;
     long copy, parity;
     char p[10];
+    int ret;
 
     pstrcpy(p, sizeof(p), opt);
     n1 = strtok(p, ":");
@@ -1907,35 +1950,32 @@ static int parse_redundancy(BDRVSheepdogState *s, const char *opt)
         return -EINVAL;
     }
 
-    copy = strtol(n1, NULL, 10);
-    /* FIXME fix error checking by switching to qemu_strtol() */
-    if (copy > SD_MAX_COPIES || copy < 1) {
-        return -EINVAL;
-    }
-    if (!n2) {
-        inode->copy_policy = 0;
-        inode->nr_copies = copy;
-        return 0;
+    ret = qemu_strtol(n1, NULL, 10, &copy);
+    if (ret < 0) {
+        return ret;
     }
 
-    if (copy != 2 && copy != 4 && copy != 8 && copy != 16) {
-        return -EINVAL;
-    }
+    if (!n2) {
+        redundancy = (SheepdogRedundancy) {
+            .type               = SHEEPDOG_REDUNDANCY_TYPE_FULL,
+            .u.full.copies      = copy,
+        };
+    } else {
+        ret = qemu_strtol(n2, NULL, 10, &parity);
+        if (ret < 0) {
+            return ret;
+        }
 
-    parity = strtol(n2, NULL, 10);
-    /* FIXME fix error checking by switching to qemu_strtol() */
-    if (parity >= SD_EC_MAX_STRIP || parity < 1) {
-        return -EINVAL;
+        redundancy = (SheepdogRedundancy) {
+            .type               = SHEEPDOG_REDUNDANCY_TYPE_ERASURE_CODED,
+            .u.erasure_coded    = {
+                .data_strips    = copy,
+                .parity_strips  = parity,
+            },
+        };
     }
 
-    /*
-     * 4 bits for parity and 4 bits for data.
-     * We have to compress upper data bits because it can't represent 16
-     */
-    inode->copy_policy = ((copy / 2) << 4) + parity;
-    inode->nr_copies = copy + parity;
-
-    return 0;
+    return parse_redundancy(s, &redundancy);
 }
 
 static int parse_block_size_shift(BDRVSheepdogState *s, QemuOpts *opt)
@@ -2007,7 +2047,7 @@ static int sd_create(const char *filename, QemuOpts *opts,
     g_free(buf);
     buf = qemu_opt_get_del(opts, BLOCK_OPT_REDUNDANCY);
     if (buf) {
-        ret = parse_redundancy(s, buf);
+        ret = parse_redundancy_str(s, buf);
         if (ret < 0) {
             error_setg(errp, "Invalid redundancy mode: '%s'", buf);
             goto out;
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 28/36] sheepdog: Support .bdrv_co_create
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (26 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 27/36] sheepdog: QAPIfy "redundacy" create option Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-22 23:51   ` Max Reitz
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 29/36] ssh: Use QAPI BlockdevOptionsSsh object Kevin Wolf
                   ` (7 subsequent siblings)
  35 siblings, 1 reply; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

This adds the .bdrv_co_create driver callback to sheepdog, which enables
image creation over QMP.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 qapi/block-core.json |  24 +++++-
 block/sheepdog.c     | 240 +++++++++++++++++++++++++++++++++++----------------
 2 files changed, 189 insertions(+), 75 deletions(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 2b249c9e3d..f7679fce53 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3512,6 +3512,28 @@
             'erasure-coded': 'SheepdogRedundancyErasureCoded' } }
 
 ##
+# @BlockdevCreateOptionsSheepdog:
+#
+# Driver specific image creation options for Sheepdog.
+#
+# @location         Where to store the new image file
+# @size             Size of the virtual disk in bytes
+# @backing-file     File name of a base image
+# @preallocation    Preallocation mode (allowed values: off, full)
+# @redundancy       Redundancy of the image
+# @object-size      Object size of the image
+#
+# Since: 2.12
+##
+{ 'struct': 'BlockdevCreateOptionsSheepdog',
+  'data': { 'location':         'BlockdevOptionsSheepdog',
+            'size':             'size',
+            '*backing-file':    'str',
+            '*preallocation':   'PreallocMode',
+            '*redundancy':      'SheepdogRedundancy',
+            '*object-size':     'size' } }
+
+##
 # @BlockdevCreateNotSupported:
 #
 # This is used for all drivers that don't support creating images.
@@ -3562,7 +3584,7 @@
       'raw':            'BlockdevCreateNotSupported',
       'rbd':            'BlockdevCreateOptionsRbd',
       'replication':    'BlockdevCreateNotSupported',
-      'sheepdog':       'BlockdevCreateNotSupported',
+      'sheepdog':       'BlockdevCreateOptionsSheepdog',
       'ssh':            'BlockdevCreateNotSupported',
       'throttle':       'BlockdevCreateNotSupported',
       'vdi':            'BlockdevCreateNotSupported',
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 22df2ba9d0..d45cf68ff2 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -17,6 +17,7 @@
 #include "qapi/error.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qobject-input-visitor.h"
+#include "qapi/qobject-output-visitor.h"
 #include "qemu/uri.h"
 #include "qemu/error-report.h"
 #include "qemu/option.h"
@@ -533,23 +534,6 @@ static void sd_aio_setup(SheepdogAIOCB *acb, BDRVSheepdogState *s,
     qemu_co_mutex_unlock(&s->queue_lock);
 }
 
-static SocketAddress *sd_socket_address(const char *path,
-                                        const char *host, const char *port)
-{
-    SocketAddress *addr = g_new0(SocketAddress, 1);
-
-    if (path) {
-        addr->type = SOCKET_ADDRESS_TYPE_UNIX;
-        addr->u.q_unix.path = g_strdup(path);
-    } else {
-        addr->type = SOCKET_ADDRESS_TYPE_INET;
-        addr->u.inet.host = g_strdup(host ?: SD_DEFAULT_ADDR);
-        addr->u.inet.port = g_strdup(port ?: stringify(SD_DEFAULT_PORT));
-    }
-
-    return addr;
-}
-
 static SocketAddress *sd_server_config(QDict *options, Error **errp)
 {
     QDict *server = NULL;
@@ -1882,6 +1866,42 @@ out_with_err_set:
     return ret;
 }
 
+static int sd_create_prealloc(BlockdevOptionsSheepdog *location, int64_t size,
+                              Error **errp)
+{
+    BlockDriverState *bs;
+    Visitor *v;
+    QObject *obj = NULL;
+    QDict *qdict;
+    Error *local_err = NULL;
+    int ret;
+
+    v = qobject_output_visitor_new(&obj);
+    visit_type_BlockdevOptionsSheepdog(v, NULL, &location, &local_err);
+    visit_free(v);
+
+    if (local_err) {
+        error_propagate(errp, local_err);
+        qobject_decref(obj);
+        return -EINVAL;
+    }
+
+    qdict = qobject_to_qdict(obj);
+    qdict_flatten(qdict);
+
+    bs = bdrv_open(NULL, NULL, qdict, BDRV_O_PROTOCOL | BDRV_O_RDWR, errp);
+    if (bs == NULL) {
+        ret = -EIO;
+        goto fail;
+    }
+
+    ret = sd_prealloc(bs, 0, size, errp);
+fail:
+    bdrv_unref(bs);
+    QDECREF(qdict);
+    return ret;
+}
+
 static int parse_redundancy(BDRVSheepdogState *s, SheepdogRedundancy *opt)
 {
     struct SheepdogInode *inode = &s->inode;
@@ -1934,9 +1954,9 @@ static int parse_redundancy(BDRVSheepdogState *s, SheepdogRedundancy *opt)
  * # create a erasure coded vdi with x data strips and y parity strips
  * -o redundancy=x:y (x must be one of {2,4,8,16} and 1 <= y < SD_EC_MAX_STRIP)
  */
-static int parse_redundancy_str(BDRVSheepdogState *s, const char *opt)
+static SheepdogRedundancy *parse_redundancy_str(const char *opt)
 {
-    struct SheepdogRedundancy redundancy;
+    SheepdogRedundancy *redundancy;
     const char *n1, *n2;
     long copy, parity;
     char p[10];
@@ -1947,26 +1967,27 @@ static int parse_redundancy_str(BDRVSheepdogState *s, const char *opt)
     n2 = strtok(NULL, ":");
 
     if (!n1) {
-        return -EINVAL;
+        return NULL;
     }
 
     ret = qemu_strtol(n1, NULL, 10, &copy);
     if (ret < 0) {
-        return ret;
+        return NULL;
     }
 
+    redundancy = g_new0(SheepdogRedundancy, 1);
     if (!n2) {
-        redundancy = (SheepdogRedundancy) {
+        *redundancy = (SheepdogRedundancy) {
             .type               = SHEEPDOG_REDUNDANCY_TYPE_FULL,
             .u.full.copies      = copy,
         };
     } else {
         ret = qemu_strtol(n2, NULL, 10, &parity);
         if (ret < 0) {
-            return ret;
+            return NULL;
         }
 
-        redundancy = (SheepdogRedundancy) {
+        *redundancy = (SheepdogRedundancy) {
             .type               = SHEEPDOG_REDUNDANCY_TYPE_ERASURE_CODED,
             .u.erasure_coded    = {
                 .data_strips    = copy,
@@ -1975,17 +1996,19 @@ static int parse_redundancy_str(BDRVSheepdogState *s, const char *opt)
         };
     }
 
-    return parse_redundancy(s, &redundancy);
+    return redundancy;
 }
 
-static int parse_block_size_shift(BDRVSheepdogState *s, QemuOpts *opt)
+static int parse_block_size_shift(BDRVSheepdogState *s,
+                                  BlockdevCreateOptionsSheepdog *opts)
 {
     struct SheepdogInode *inode = &s->inode;
     uint64_t object_size;
     int obj_order;
 
-    object_size = qemu_opt_get_size_del(opt, BLOCK_OPT_OBJECT_SIZE, 0);
-    if (object_size) {
+    if (opts->has_object_size) {
+        object_size = opts->object_size;
+
         if ((object_size - 1) & object_size) {    /* not a power of 2? */
             return -EINVAL;
         }
@@ -1999,57 +2022,55 @@ static int parse_block_size_shift(BDRVSheepdogState *s, QemuOpts *opt)
     return 0;
 }
 
-static int sd_create(const char *filename, QemuOpts *opts,
-                     Error **errp)
+static int sd_co_create(BlockdevCreateOptions *options, Error **errp)
 {
-    Error *err = NULL;
+    BlockdevCreateOptionsSheepdog *opts = &options->u.sheepdog;
     int ret = 0;
     uint32_t vid = 0;
     char *backing_file = NULL;
     char *buf = NULL;
     BDRVSheepdogState *s;
-    SheepdogConfig cfg;
     uint64_t max_vdi_size;
     bool prealloc = false;
 
+    assert(options->driver == BLOCKDEV_DRIVER_SHEEPDOG);
+
     s = g_new0(BDRVSheepdogState, 1);
 
-    if (strstr(filename, "://")) {
-        sd_parse_uri(&cfg, filename, &err);
-    } else {
-        parse_vdiname(&cfg, filename, &err);
-    }
-    if (err) {
-        error_propagate(errp, err);
+    /* Steal SocketAddress from QAPI, set NULL to prevent double free */
+    s->addr = opts->location->server;
+    opts->location->server = NULL;
+
+    if (strlen(opts->location->vdi) >= sizeof(s->name)) {
+        error_setg(errp, "'vdi' string too long");
+        ret = -EINVAL;
         goto out;
     }
+    pstrcpy(s->name, sizeof(s->name), opts->location->vdi);
 
-    buf = cfg.port ? g_strdup_printf("%d", cfg.port) : NULL;
-    s->addr = sd_socket_address(cfg.path, cfg.host, buf);
-    g_free(buf);
-    strcpy(s->name, cfg.vdi);
-    sd_config_done(&cfg);
+    s->inode.vdi_size = opts->size;
+    backing_file = opts->backing_file;
 
-    s->inode.vdi_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
-                                 BDRV_SECTOR_SIZE);
-    backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
-    buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
-    if (!buf || !strcmp(buf, "off")) {
+    if (!opts->has_preallocation) {
+        opts->preallocation = PREALLOC_MODE_OFF;
+    }
+    switch (opts->preallocation) {
+    case PREALLOC_MODE_OFF:
         prealloc = false;
-    } else if (!strcmp(buf, "full")) {
+        break;
+    case PREALLOC_MODE_FULL:
         prealloc = true;
-    } else {
-        error_setg(errp, "Invalid preallocation mode: '%s'", buf);
+        break;
+    default:
+        error_setg(errp, "Preallocation mode not supported for Sheepdog");
         ret = -EINVAL;
         goto out;
     }
 
-    g_free(buf);
-    buf = qemu_opt_get_del(opts, BLOCK_OPT_REDUNDANCY);
-    if (buf) {
-        ret = parse_redundancy_str(s, buf);
+    if (opts->has_redundancy) {
+        ret = parse_redundancy(s, opts->redundancy);
         if (ret < 0) {
-            error_setg(errp, "Invalid redundancy mode: '%s'", buf);
+            error_setg(errp, "Invalid redundancy mode");
             goto out;
         }
     }
@@ -2061,20 +2082,20 @@ static int sd_create(const char *filename, QemuOpts *opts,
         goto out;
     }
 
-    if (backing_file) {
+    if (opts->has_backing_file) {
         BlockBackend *blk;
         BDRVSheepdogState *base;
         BlockDriver *drv;
 
         /* Currently, only Sheepdog backing image is supported. */
-        drv = bdrv_find_protocol(backing_file, true, NULL);
+        drv = bdrv_find_protocol(opts->backing_file, true, NULL);
         if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) {
             error_setg(errp, "backing_file must be a sheepdog image");
             ret = -EINVAL;
             goto out;
         }
 
-        blk = blk_new_open(backing_file, NULL, NULL,
+        blk = blk_new_open(opts->backing_file, NULL, NULL,
                            BDRV_O_PROTOCOL, errp);
         if (blk == NULL) {
             ret = -EIO;
@@ -2142,28 +2163,96 @@ static int sd_create(const char *filename, QemuOpts *opts,
     }
 
     if (prealloc) {
-        BlockDriverState *bs;
-        QDict *opts;
-
-        opts = qdict_new();
-        qdict_put_str(opts, "driver", "sheepdog");
-        bs = bdrv_open(filename, NULL, opts, BDRV_O_PROTOCOL | BDRV_O_RDWR,
-                       errp);
-        if (!bs) {
-            goto out;
-        }
-
-        ret = sd_prealloc(bs, 0, s->inode.vdi_size, errp);
-
-        bdrv_unref(bs);
+        ret = sd_create_prealloc(opts->location, opts->size, errp);
     }
 out:
     g_free(backing_file);
     g_free(buf);
+    g_free(s->addr);
     g_free(s);
     return ret;
 }
 
+static int sd_create(const char *filename, QemuOpts *opts,
+                     Error **errp)
+{
+    BlockdevCreateOptions *create_options = NULL;
+    QDict *qdict, *location_qdict;
+    QObject *crumpled;
+    Visitor *v;
+    const char *redundancy;
+    Error *local_err = NULL;
+    int ret;
+
+    redundancy = qemu_opt_get_del(opts, BLOCK_OPT_REDUNDANCY);
+
+    qdict = qemu_opts_to_qdict(opts, NULL);
+    qdict_put_str(qdict, "driver", "sheepdog");
+
+    location_qdict = qdict_new();
+    qdict_put(qdict, "location", location_qdict);
+
+    sd_parse_filename(filename, location_qdict, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        ret = -EINVAL;
+        goto fail;
+    }
+
+    qdict_flatten(qdict);
+
+    /* Change legacy command line options into QMP ones */
+    static const QDictRenames opt_renames[] = {
+        { BLOCK_OPT_BACKING_FILE,       "backing-file" },
+        { BLOCK_OPT_OBJECT_SIZE,        "object-size" },
+        { NULL, NULL },
+    };
+
+    if (!qdict_rename_keys(qdict, opt_renames, errp)) {
+        ret = -EINVAL;
+        goto fail;
+    }
+
+    /* Get the QAPI object */
+    crumpled = qdict_crumple(qdict, errp);
+    if (crumpled == NULL) {
+        ret = -EINVAL;
+        goto fail;
+    }
+
+    v = qobject_input_visitor_new_keyval(crumpled);
+    visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
+    visit_free(v);
+    qobject_decref(crumpled);
+
+    if (local_err) {
+        error_propagate(errp, local_err);
+        ret = -EINVAL;
+        goto fail;
+    }
+
+    assert(create_options->driver == BLOCKDEV_DRIVER_SHEEPDOG);
+    create_options->u.sheepdog.size =
+        ROUND_UP(create_options->u.sheepdog.size, BDRV_SECTOR_SIZE);
+
+    if (redundancy) {
+        create_options->u.sheepdog.has_redundancy = true;
+        create_options->u.sheepdog.redundancy =
+            parse_redundancy_str(redundancy);
+        if (create_options->u.sheepdog.redundancy == NULL) {
+            error_setg(errp, "Invalid redundancy mode");
+            ret = -EINVAL;
+            goto fail;
+        }
+    }
+
+    ret = sd_co_create(create_options, errp);
+fail:
+    qapi_free_BlockdevCreateOptions(create_options);
+    QDECREF(qdict);
+    return ret;
+}
+
 static void sd_close(BlockDriverState *bs)
 {
     Error *local_err = NULL;
@@ -3144,6 +3233,7 @@ static BlockDriver bdrv_sheepdog = {
     .bdrv_reopen_abort            = sd_reopen_abort,
     .bdrv_close                   = sd_close,
     .bdrv_create                  = sd_create,
+    .bdrv_co_create               = sd_co_create,
     .bdrv_has_zero_init           = bdrv_has_zero_init_1,
     .bdrv_getlength               = sd_getlength,
     .bdrv_get_allocated_file_size = sd_get_allocated_file_size,
@@ -3180,6 +3270,7 @@ static BlockDriver bdrv_sheepdog_tcp = {
     .bdrv_reopen_abort            = sd_reopen_abort,
     .bdrv_close                   = sd_close,
     .bdrv_create                  = sd_create,
+    .bdrv_co_create               = sd_co_create,
     .bdrv_has_zero_init           = bdrv_has_zero_init_1,
     .bdrv_getlength               = sd_getlength,
     .bdrv_get_allocated_file_size = sd_get_allocated_file_size,
@@ -3216,6 +3307,7 @@ static BlockDriver bdrv_sheepdog_unix = {
     .bdrv_reopen_abort            = sd_reopen_abort,
     .bdrv_close                   = sd_close,
     .bdrv_create                  = sd_create,
+    .bdrv_co_create               = sd_co_create,
     .bdrv_has_zero_init           = bdrv_has_zero_init_1,
     .bdrv_getlength               = sd_getlength,
     .bdrv_get_allocated_file_size = sd_get_allocated_file_size,
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 29/36] ssh: Use QAPI BlockdevOptionsSsh object
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (27 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 28/36] sheepdog: Support .bdrv_co_create Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 30/36] ssh: QAPIfy host-key-check option Kevin Wolf
                   ` (6 subsequent siblings)
  35 siblings, 0 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

Create a BlockdevOptionsSsh object in connect_to_ssh() and take the
options from there. 'host_key_check' is still processed separately
because it's not in the schema yet.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 block/ssh.c | 136 +++++++++++++++++++++++++++---------------------------------
 1 file changed, 61 insertions(+), 75 deletions(-)

diff --git a/block/ssh.c b/block/ssh.c
index b63addcf94..9a89b7f350 100644
--- a/block/ssh.c
+++ b/block/ssh.c
@@ -543,21 +543,6 @@ static QemuOptsList ssh_runtime_opts = {
             .type = QEMU_OPT_NUMBER,
             .help = "Port to connect to",
         },
-        {
-            .name = "path",
-            .type = QEMU_OPT_STRING,
-            .help = "Path of the image on the host",
-        },
-        {
-            .name = "user",
-            .type = QEMU_OPT_STRING,
-            .help = "User as which to connect",
-        },
-        {
-            .name = "host_key_check",
-            .type = QEMU_OPT_STRING,
-            .help = "Defines how and what to check the host key against",
-        },
         { /* end of list */ }
     },
 };
@@ -582,23 +567,31 @@ static bool ssh_process_legacy_socket_options(QDict *output_opts,
     return true;
 }
 
-static InetSocketAddress *ssh_config(QDict *options, Error **errp)
+static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp)
 {
-    InetSocketAddress *inet = NULL;
-    QDict *addr = NULL;
-    QObject *crumpled_addr = NULL;
-    Visitor *iv = NULL;
-    Error *local_error = NULL;
-
-    qdict_extract_subqdict(options, &addr, "server.");
-    if (!qdict_size(addr)) {
-        error_setg(errp, "SSH server address missing");
-        goto out;
+    BlockdevOptionsSsh *result = NULL;
+    QemuOpts *opts = NULL;
+    Error *local_err = NULL;
+    QObject *crumpled;
+    const QDictEntry *e;
+    Visitor *v;
+
+    /* Translate legacy options */
+    opts = qemu_opts_create(&ssh_runtime_opts, NULL, 0, &error_abort);
+    qemu_opts_absorb_qdict(opts, options, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        goto fail;
     }
 
-    crumpled_addr = qdict_crumple(addr, errp);
-    if (!crumpled_addr) {
-        goto out;
+    if (!ssh_process_legacy_socket_options(options, opts, errp)) {
+        goto fail;
+    }
+
+    /* Create the QAPI object */
+    crumpled = qdict_crumple(options, errp);
+    if (crumpled == NULL) {
+        goto fail;
     }
 
     /*
@@ -609,51 +602,50 @@ static InetSocketAddress *ssh_config(QDict *options, Error **errp)
      * but when they come from -drive, they're all QString.  The
      * visitor expects the former.
      */
-    iv = qobject_input_visitor_new(crumpled_addr);
-    visit_type_InetSocketAddress(iv, NULL, &inet, &local_error);
-    if (local_error) {
-        error_propagate(errp, local_error);
-        goto out;
+    v = qobject_input_visitor_new(crumpled);
+    visit_type_BlockdevOptionsSsh(v, NULL, &result, &local_err);
+    visit_free(v);
+    qobject_decref(crumpled);
+
+    if (local_err) {
+        error_propagate(errp, local_err);
+        goto fail;
     }
 
-out:
-    QDECREF(addr);
-    qobject_decref(crumpled_addr);
-    visit_free(iv);
-    return inet;
+    /* Remove the processed options from the QDict (the visitor processes
+     * _all_ options in the QDict) */
+    while ((e = qdict_first(options))) {
+        qdict_del(options, e->key);
+    }
+
+fail:
+    qemu_opts_del(opts);
+    return result;
 }
 
 static int connect_to_ssh(BDRVSSHState *s, QDict *options,
                           int ssh_flags, int creat_mode, Error **errp)
 {
+    BlockdevOptionsSsh *opts;
     int r, ret;
-    QemuOpts *opts = NULL;
-    Error *local_err = NULL;
-    const char *user, *path, *host_key_check;
+    const char *user, *host_key_check;
     long port = 0;
 
-    opts = qemu_opts_create(&ssh_runtime_opts, NULL, 0, &error_abort);
-    qemu_opts_absorb_qdict(opts, options, &local_err);
-    if (local_err) {
-        ret = -EINVAL;
-        error_propagate(errp, local_err);
-        goto err;
-    }
-
-    if (!ssh_process_legacy_socket_options(options, opts, errp)) {
-        ret = -EINVAL;
-        goto err;
+    host_key_check = qdict_get_try_str(options, "host_key_check");
+    if (!host_key_check) {
+        host_key_check = "yes";
+    } else {
+        qdict_del(options, "host_key_check");
     }
 
-    path = qemu_opt_get(opts, "path");
-    if (!path) {
-        ret = -EINVAL;
-        error_setg(errp, "No path was specified");
-        goto err;
+    opts = ssh_parse_options(options, errp);
+    if (opts == NULL) {
+        return -EINVAL;
     }
 
-    user = qemu_opt_get(opts, "user");
-    if (!user) {
+    if (opts->has_user) {
+        user = opts->user;
+    } else {
         user = g_get_user_name();
         if (!user) {
             error_setg_errno(errp, errno, "Can't get user name");
@@ -662,17 +654,9 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
         }
     }
 
-    host_key_check = qemu_opt_get(opts, "host_key_check");
-    if (!host_key_check) {
-        host_key_check = "yes";
-    }
-
     /* Pop the config into our state object, Exit if invalid */
-    s->inet = ssh_config(options, errp);
-    if (!s->inet) {
-        ret = -EINVAL;
-        goto err;
-    }
+    s->inet = opts->server;
+    opts->server = NULL;
 
     if (qemu_strtol(s->inet->port, NULL, 10, &port) < 0) {
         error_setg(errp, "Use only numeric port value");
@@ -729,15 +713,17 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
 
     /* Open the remote file. */
     DPRINTF("opening file %s flags=0x%x creat_mode=0%o",
-            path, ssh_flags, creat_mode);
-    s->sftp_handle = libssh2_sftp_open(s->sftp, path, ssh_flags, creat_mode);
+            opts->path, ssh_flags, creat_mode);
+    s->sftp_handle = libssh2_sftp_open(s->sftp, opts->path, ssh_flags,
+                                       creat_mode);
     if (!s->sftp_handle) {
-        session_error_setg(errp, s, "failed to open remote file '%s'", path);
+        session_error_setg(errp, s, "failed to open remote file '%s'",
+                           opts->path);
         ret = -EINVAL;
         goto err;
     }
 
-    qemu_opts_del(opts);
+    qapi_free_BlockdevOptionsSsh(opts);
 
     r = libssh2_sftp_fstat(s->sftp_handle, &s->attrs);
     if (r < 0) {
@@ -764,7 +750,7 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
     }
     s->session = NULL;
 
-    qemu_opts_del(opts);
+    qapi_free_BlockdevOptionsSsh(opts);
 
     return ret;
 }
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 30/36] ssh: QAPIfy host-key-check option
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (28 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 29/36] ssh: Use QAPI BlockdevOptionsSsh object Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 31/36] ssh: Pass BlockdevOptionsSsh to connect_to_ssh() Kevin Wolf
                   ` (5 subsequent siblings)
  35 siblings, 0 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

This makes the host-key-check option available in blockdev-add.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 qapi/block-core.json | 63 +++++++++++++++++++++++++++++++++++--
 block/ssh.c          | 88 +++++++++++++++++++++++++++++++++-------------------
 2 files changed, 117 insertions(+), 34 deletions(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index f7679fce53..431d4a4fb2 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -2553,6 +2553,63 @@
             '*encrypt': 'BlockdevQcow2Encryption' } }
 
 ##
+# @SshHostKeyCheckMode:
+#
+# @none             Don't check the host key at all
+# @hash             Compare the host key with a given hash
+# @known_hosts      Check the host key against the known_hosts file
+#
+# Since: 2.12
+##
+{ 'enum': 'SshHostKeyCheckMode',
+  'data': [ 'none', 'hash', 'known_hosts' ] }
+
+##
+# @SshHostKeyCheckHashType:
+#
+# @md5              The given hash is an md5 hash
+# @sha1             The given hash is an sha1 hash
+#
+# Since: 2.12
+##
+{ 'enum': 'SshHostKeyCheckHashType',
+  'data': [ 'md5', 'sha1' ] }
+
+##
+# @SshHostKeyHash:
+#
+# @type             The hash algorithm used for the hash
+# @hash             The expected hash value
+#
+# Since: 2.12
+##
+{ 'struct': 'SshHostKeyHash',
+  'data': { 'type': 'SshHostKeyCheckHashType',
+            'hash': 'str' }}
+
+##
+# @SshHostKeyDummy:
+#
+# For those union branches that don't need additional fields.
+#
+# Since: 2.12
+##
+{ 'struct': 'SshHostKeyDummy',
+  'data': {} }
+
+##
+# @SshHostKeyCheck:
+#
+# Since: 2.12
+##
+{ 'union': 'SshHostKeyCheck',
+  'base': { 'mode': 'SshHostKeyCheckMode' },
+  'discriminator': 'mode',
+  'data': { 'none': 'SshHostKeyDummy',
+            'hash': 'SshHostKeyHash',
+            'known_hosts': 'SshHostKeyDummy' } }
+
+##
 # @BlockdevOptionsSsh:
 #
 # @server:              host address
@@ -2562,14 +2619,16 @@
 # @user:                user as which to connect, defaults to current
 #                       local user name
 #
-# TODO: Expose the host_key_check option in QMP
+# @host-key-check:      Defines how and what to check the host key against
+#                       (default: known_hosts)
 #
 # Since: 2.9
 ##
 { 'struct': 'BlockdevOptionsSsh',
   'data': { 'server': 'InetSocketAddress',
             'path': 'str',
-            '*user': 'str' } }
+            '*user': 'str',
+            '*host-key-check': 'SshHostKeyCheck' } }
 
 
 ##
diff --git a/block/ssh.c b/block/ssh.c
index 9a89b7f350..dcf766c213 100644
--- a/block/ssh.c
+++ b/block/ssh.c
@@ -430,31 +430,35 @@ check_host_key_hash(BDRVSSHState *s, const char *hash,
 }
 
 static int check_host_key(BDRVSSHState *s, const char *host, int port,
-                          const char *host_key_check, Error **errp)
+                          SshHostKeyCheck *hkc, Error **errp)
 {
-    /* host_key_check=no */
-    if (strcmp(host_key_check, "no") == 0) {
-        return 0;
-    }
+    SshHostKeyCheckMode mode;
 
-    /* host_key_check=md5:xx:yy:zz:... */
-    if (strncmp(host_key_check, "md5:", 4) == 0) {
-        return check_host_key_hash(s, &host_key_check[4],
-                                   LIBSSH2_HOSTKEY_HASH_MD5, 16, errp);
-    }
-
-    /* host_key_check=sha1:xx:yy:zz:... */
-    if (strncmp(host_key_check, "sha1:", 5) == 0) {
-        return check_host_key_hash(s, &host_key_check[5],
-                                   LIBSSH2_HOSTKEY_HASH_SHA1, 20, errp);
+    if (hkc) {
+        mode = hkc->mode;
+    } else {
+        mode = SSH_HOST_KEY_CHECK_MODE_KNOWN_HOSTS;
     }
 
-    /* host_key_check=yes */
-    if (strcmp(host_key_check, "yes") == 0) {
+    switch (mode) {
+    case SSH_HOST_KEY_CHECK_MODE_NONE:
+        return 0;
+    case SSH_HOST_KEY_CHECK_MODE_HASH:
+        if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_MD5) {
+            return check_host_key_hash(s, hkc->u.hash.hash,
+                                       LIBSSH2_HOSTKEY_HASH_MD5, 16, errp);
+        } else if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_SHA1) {
+            return check_host_key_hash(s, hkc->u.hash.hash,
+                                       LIBSSH2_HOSTKEY_HASH_SHA1, 20, errp);
+        }
+        g_assert_not_reached();
+        break;
+    case SSH_HOST_KEY_CHECK_MODE_KNOWN_HOSTS:
         return check_host_key_knownhosts(s, host, port, errp);
+    default:
+        g_assert_not_reached();
     }
 
-    error_setg(errp, "unknown host_key_check setting (%s)", host_key_check);
     return -EINVAL;
 }
 
@@ -543,16 +547,22 @@ static QemuOptsList ssh_runtime_opts = {
             .type = QEMU_OPT_NUMBER,
             .help = "Port to connect to",
         },
+        {
+            .name = "host_key_check",
+            .type = QEMU_OPT_STRING,
+            .help = "Defines how and what to check the host key against",
+        },
         { /* end of list */ }
     },
 };
 
-static bool ssh_process_legacy_socket_options(QDict *output_opts,
-                                              QemuOpts *legacy_opts,
-                                              Error **errp)
+static bool ssh_process_legacy_options(QDict *output_opts,
+                                       QemuOpts *legacy_opts,
+                                       Error **errp)
 {
     const char *host = qemu_opt_get(legacy_opts, "host");
     const char *port = qemu_opt_get(legacy_opts, "port");
+    const char *host_key_check = qemu_opt_get(legacy_opts, "host_key_check");
 
     if (!host && port) {
         error_setg(errp, "port may not be used without host");
@@ -564,6 +574,28 @@ static bool ssh_process_legacy_socket_options(QDict *output_opts,
         qdict_put_str(output_opts, "server.port", port ?: stringify(22));
     }
 
+    if (host_key_check) {
+        if (strcmp(host_key_check, "no") == 0) {
+            qdict_put_str(output_opts, "host-key-check.mode", "none");
+        } else if (strncmp(host_key_check, "md5:", 4) == 0) {
+            qdict_put_str(output_opts, "host-key-check.mode", "hash");
+            qdict_put_str(output_opts, "host-key-check.type", "md5");
+            qdict_put_str(output_opts, "host-key-check.hash",
+                          &host_key_check[4]);
+        } else if (strncmp(host_key_check, "sha1:", 5) == 0) {
+            qdict_put_str(output_opts, "host-key-check.mode", "hash");
+            qdict_put_str(output_opts, "host-key-check.type", "sha1");
+            qdict_put_str(output_opts, "host-key-check.hash",
+                          &host_key_check[5]);
+        } else if (strcmp(host_key_check, "yes") == 0) {
+            qdict_put_str(output_opts, "host-key-check.mode", "known_hosts");
+        } else {
+            error_setg(errp, "unknown host_key_check setting (%s)",
+                       host_key_check);
+            return false;
+        }
+    }
+
     return true;
 }
 
@@ -584,7 +616,7 @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp)
         goto fail;
     }
 
-    if (!ssh_process_legacy_socket_options(options, opts, errp)) {
+    if (!ssh_process_legacy_options(options, opts, errp)) {
         goto fail;
     }
 
@@ -628,16 +660,9 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
 {
     BlockdevOptionsSsh *opts;
     int r, ret;
-    const char *user, *host_key_check;
+    const char *user;
     long port = 0;
 
-    host_key_check = qdict_get_try_str(options, "host_key_check");
-    if (!host_key_check) {
-        host_key_check = "yes";
-    } else {
-        qdict_del(options, "host_key_check");
-    }
-
     opts = ssh_parse_options(options, errp);
     if (opts == NULL) {
         return -EINVAL;
@@ -691,8 +716,7 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
     }
 
     /* Check the remote host's key against known_hosts. */
-    ret = check_host_key(s, s->inet->host, port, host_key_check,
-                         errp);
+    ret = check_host_key(s, s->inet->host, port, opts->host_key_check, errp);
     if (ret < 0) {
         goto err;
     }
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 31/36] ssh: Pass BlockdevOptionsSsh to connect_to_ssh()
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (29 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 30/36] ssh: QAPIfy host-key-check option Kevin Wolf
@ 2018-02-21 13:53 ` Kevin Wolf
  2018-02-21 13:54 ` [Qemu-devel] [PATCH v2 32/36] ssh: Support .bdrv_co_create Kevin Wolf
                   ` (4 subsequent siblings)
  35 siblings, 0 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:53 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

Move the parsing of the QDict options up to the callers, in preparation
for the .bdrv_co_create implementation that directly gets a QAPI type.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 block/ssh.c | 34 +++++++++++++++++++++-------------
 1 file changed, 21 insertions(+), 13 deletions(-)

diff --git a/block/ssh.c b/block/ssh.c
index dcf766c213..77bc20041f 100644
--- a/block/ssh.c
+++ b/block/ssh.c
@@ -655,19 +655,13 @@ fail:
     return result;
 }
 
-static int connect_to_ssh(BDRVSSHState *s, QDict *options,
+static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts,
                           int ssh_flags, int creat_mode, Error **errp)
 {
-    BlockdevOptionsSsh *opts;
     int r, ret;
     const char *user;
     long port = 0;
 
-    opts = ssh_parse_options(options, errp);
-    if (opts == NULL) {
-        return -EINVAL;
-    }
-
     if (opts->has_user) {
         user = opts->user;
     } else {
@@ -747,8 +741,6 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
         goto err;
     }
 
-    qapi_free_BlockdevOptionsSsh(opts);
-
     r = libssh2_sftp_fstat(s->sftp_handle, &s->attrs);
     if (r < 0) {
         sftp_error_setg(errp, s, "failed to read file attributes");
@@ -774,8 +766,6 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
     }
     s->session = NULL;
 
-    qapi_free_BlockdevOptionsSsh(opts);
-
     return ret;
 }
 
@@ -783,6 +773,7 @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
                          Error **errp)
 {
     BDRVSSHState *s = bs->opaque;
+    BlockdevOptionsSsh *opts;
     int ret;
     int ssh_flags;
 
@@ -793,8 +784,13 @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
         ssh_flags |= LIBSSH2_FXF_WRITE;
     }
 
+    opts = ssh_parse_options(options, errp);
+    if (opts == NULL) {
+        return -EINVAL;
+    }
+
     /* Start up SSH. */
-    ret = connect_to_ssh(s, options, ssh_flags, 0, errp);
+    ret = connect_to_ssh(s, opts, ssh_flags, 0, errp);
     if (ret < 0) {
         goto err;
     }
@@ -802,6 +798,8 @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
     /* Go non-blocking. */
     libssh2_session_set_blocking(s->session, 0);
 
+    qapi_free_BlockdevOptionsSsh(opts);
+
     return 0;
 
  err:
@@ -810,6 +808,8 @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags,
     }
     s->sock = -1;
 
+    qapi_free_BlockdevOptionsSsh(opts);
+
     return ret;
 }
 
@@ -831,6 +831,7 @@ static int ssh_create(const char *filename, QemuOpts *opts, Error **errp)
     int r, ret;
     int64_t total_size = 0;
     QDict *uri_options = NULL;
+    BlockdevOptionsSsh *ssh_opts = NULL;
     BDRVSSHState s;
     ssize_t r2;
     char c[1] = { '\0' };
@@ -849,7 +850,13 @@ static int ssh_create(const char *filename, QemuOpts *opts, Error **errp)
         goto out;
     }
 
-    r = connect_to_ssh(&s, uri_options,
+    ssh_opts = ssh_parse_options(uri_options, errp);
+    if (ssh_opts == NULL) {
+        ret = -EINVAL;
+        goto out;
+    }
+
+    r = connect_to_ssh(&s, ssh_opts,
                        LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE|
                        LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
                        0644, errp);
@@ -876,6 +883,7 @@ static int ssh_create(const char *filename, QemuOpts *opts, Error **errp)
     if (uri_options != NULL) {
         QDECREF(uri_options);
     }
+    qapi_free_BlockdevOptionsSsh(ssh_opts);
     return ret;
 }
 
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 32/36] ssh: Support .bdrv_co_create
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (30 preceding siblings ...)
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 31/36] ssh: Pass BlockdevOptionsSsh to connect_to_ssh() Kevin Wolf
@ 2018-02-21 13:54 ` Kevin Wolf
  2018-02-26 12:40   ` Max Reitz
  2018-02-21 13:54 ` [Qemu-devel] [PATCH v2 33/36] file-posix: Fix no-op bdrv_truncate() with falloc preallocation Kevin Wolf
                   ` (3 subsequent siblings)
  35 siblings, 1 reply; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:54 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

This adds the .bdrv_co_create driver callback to ssh, which enables
image creation over QMP.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 qapi/block-core.json | 16 ++++++++-
 block/ssh.c          | 92 +++++++++++++++++++++++++++++-----------------------
 2 files changed, 67 insertions(+), 41 deletions(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 431d4a4fb2..2f7fab46eb 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3593,6 +3593,20 @@
             '*object-size':     'size' } }
 
 ##
+# @BlockdevCreateOptionsSsh:
+#
+# Driver specific image creation options for SSH.
+#
+# @location         Where to store the new image file
+# @size             Size of the virtual disk in bytes
+#
+# Since: 2.12
+##
+{ 'struct': 'BlockdevCreateOptionsSsh',
+  'data': { 'location':         'BlockdevOptionsSsh',
+            'size':             'size' } }
+
+##
 # @BlockdevCreateNotSupported:
 #
 # This is used for all drivers that don't support creating images.
@@ -3644,7 +3658,7 @@
       'rbd':            'BlockdevCreateOptionsRbd',
       'replication':    'BlockdevCreateNotSupported',
       'sheepdog':       'BlockdevCreateOptionsSheepdog',
-      'ssh':            'BlockdevCreateNotSupported',
+      'ssh':            'BlockdevCreateOptionsSsh',
       'throttle':       'BlockdevCreateNotSupported',
       'vdi':            'BlockdevCreateNotSupported',
       'vhdx':           'BlockdevCreateNotSupported',
diff --git a/block/ssh.c b/block/ssh.c
index 77bc20041f..bd3044e5f6 100644
--- a/block/ssh.c
+++ b/block/ssh.c
@@ -826,64 +826,75 @@ static QemuOptsList ssh_create_opts = {
     }
 };
 
-static int ssh_create(const char *filename, QemuOpts *opts, Error **errp)
+static int ssh_co_create(BlockdevCreateOptions *options, Error **errp)
 {
-    int r, ret;
-    int64_t total_size = 0;
-    QDict *uri_options = NULL;
-    BlockdevOptionsSsh *ssh_opts = NULL;
+    BlockdevCreateOptionsSsh *opts = &options->u.ssh;
     BDRVSSHState s;
-    ssize_t r2;
     char c[1] = { '\0' };
+    int ret;
+
+    assert(options->driver == BLOCKDEV_DRIVER_SSH);
 
     ssh_state_init(&s);
 
+    ret = connect_to_ssh(&s, opts->location,
+                         LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE|
+                         LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
+                         0644, errp);
+    if (ret < 0) {
+        goto fail;
+    }
+
+    if (opts->size > 0) {
+        libssh2_sftp_seek64(s.sftp_handle, opts->size - 1);
+        ret = libssh2_sftp_write(s.sftp_handle, c, 1);
+        if (ret < 0) {
+            sftp_error_setg(errp, &s, "truncate failed");
+            ret = -EINVAL;
+            goto fail;
+        }
+        s.attrs.filesize = opts->size;
+    }
+
+    ret = 0;
+fail:
+    ssh_state_free(&s);
+    return ret;
+}
+
+static int ssh_create(const char *filename, QemuOpts *opts, Error **errp)
+{
+    BlockdevCreateOptions *create_options;
+    BlockdevCreateOptionsSsh *ssh_opts;
+    int ret;
+    QDict *uri_options = NULL;
+
+    create_options = g_new0(BlockdevCreateOptions, 1);
+    create_options->driver = BLOCKDEV_DRIVER_SSH;
+    ssh_opts = &create_options->u.ssh;
+
     /* Get desired file size. */
-    total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
-                          BDRV_SECTOR_SIZE);
-    DPRINTF("total_size=%" PRIi64, total_size);
+    ssh_opts->size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
+                              BDRV_SECTOR_SIZE);
+    DPRINTF("total_size=%" PRIi64, ssh_opts->size);
 
     uri_options = qdict_new();
-    r = parse_uri(filename, uri_options, errp);
-    if (r < 0) {
-        ret = r;
+    ret = parse_uri(filename, uri_options, errp);
+    if (ret < 0) {
         goto out;
     }
 
-    ssh_opts = ssh_parse_options(uri_options, errp);
-    if (ssh_opts == NULL) {
+    ssh_opts->location = ssh_parse_options(uri_options, errp);
+    if (ssh_opts->location == NULL) {
         ret = -EINVAL;
         goto out;
     }
 
-    r = connect_to_ssh(&s, ssh_opts,
-                       LIBSSH2_FXF_READ|LIBSSH2_FXF_WRITE|
-                       LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
-                       0644, errp);
-    if (r < 0) {
-        ret = r;
-        goto out;
-    }
-
-    if (total_size > 0) {
-        libssh2_sftp_seek64(s.sftp_handle, total_size-1);
-        r2 = libssh2_sftp_write(s.sftp_handle, c, 1);
-        if (r2 < 0) {
-            sftp_error_setg(errp, &s, "truncate failed");
-            ret = -EINVAL;
-            goto out;
-        }
-        s.attrs.filesize = total_size;
-    }
-
-    ret = 0;
+    ret = ssh_co_create(create_options, errp);
 
  out:
-    ssh_state_free(&s);
-    if (uri_options != NULL) {
-        QDECREF(uri_options);
-    }
-    qapi_free_BlockdevOptionsSsh(ssh_opts);
+    QDECREF(uri_options);
+    qapi_free_BlockdevCreateOptions(create_options);
     return ret;
 }
 
@@ -1223,6 +1234,7 @@ static BlockDriver bdrv_ssh = {
     .bdrv_parse_filename          = ssh_parse_filename,
     .bdrv_file_open               = ssh_file_open,
     .bdrv_create                  = ssh_create,
+    .bdrv_co_create               = ssh_co_create,
     .bdrv_close                   = ssh_close,
     .bdrv_has_zero_init           = ssh_has_zero_init,
     .bdrv_co_readv                = ssh_co_readv,
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 33/36] file-posix: Fix no-op bdrv_truncate() with falloc preallocation
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (31 preceding siblings ...)
  2018-02-21 13:54 ` [Qemu-devel] [PATCH v2 32/36] ssh: Support .bdrv_co_create Kevin Wolf
@ 2018-02-21 13:54 ` Kevin Wolf
  2018-02-23 15:21   ` Eric Blake
  2018-02-21 13:54 ` [Qemu-devel] [PATCH v2 34/36] block: Fail bdrv_truncate() with negative size Kevin Wolf
                   ` (2 subsequent siblings)
  35 siblings, 1 reply; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:54 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

If bdrv_truncate() is called, but the requested size is the same as
before, don't call posix_fallocate(), which returns -EINVAL for length
zero and would therefore make bdrv_truncate() fail.

The problem can be triggered by creating a zero-sized raw image with
'falloc' preallocation mode.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 block/file-posix.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/block/file-posix.c b/block/file-posix.c
index ba14ed9459..6aed5bca0b 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -1686,11 +1686,15 @@ static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc,
          * file systems that do not support fallocate(), trying to check if a
          * block is allocated before allocating it, so don't do that here.
          */
-        result = -posix_fallocate(fd, current_length, offset - current_length);
-        if (result != 0) {
-            /* posix_fallocate() doesn't set errno. */
-            error_setg_errno(errp, -result,
-                             "Could not preallocate new data");
+        if (offset != current_length) {
+            result = -posix_fallocate(fd, current_length, offset - current_length);
+            if (result != 0) {
+                /* posix_fallocate() doesn't set errno. */
+                error_setg_errno(errp, -result,
+                                 "Could not preallocate new data");
+            }
+        } else {
+            result = 0;
         }
         goto out;
 #endif
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 34/36] block: Fail bdrv_truncate() with negative size
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (32 preceding siblings ...)
  2018-02-21 13:54 ` [Qemu-devel] [PATCH v2 33/36] file-posix: Fix no-op bdrv_truncate() with falloc preallocation Kevin Wolf
@ 2018-02-21 13:54 ` Kevin Wolf
  2018-02-22 23:35   ` Eric Blake
  2018-02-21 13:54 ` [Qemu-devel] [PATCH v2 35/36] qemu-iotests: Test qcow2 over file image creation with QMP Kevin Wolf
  2018-02-21 13:54 ` [Qemu-devel] [PATCH v2 36/36] qemu-iotests: Test ssh image creation over QMP Kevin Wolf
  35 siblings, 1 reply; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:54 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

Most callers have their own checks, but something like this should also
be checked centrally. As it happens, x-blockdev-create can pass negative
image sizes to format drivers (because there is no QAPI type that would
reject negative numbers) and triggers the check added by this patch.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 block.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/block.c b/block.c
index 4a7e448226..5c874aefa1 100644
--- a/block.c
+++ b/block.c
@@ -3684,6 +3684,11 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
         error_setg(errp, "No medium inserted");
         return -ENOMEDIUM;
     }
+    if (offset < 0) {
+        error_setg(errp, "Image size cannot be negative");
+        return -EINVAL;
+    }
+
     if (!drv->bdrv_truncate) {
         if (bs->file && drv->is_filter) {
             return bdrv_truncate(bs->file, offset, prealloc, errp);
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 35/36] qemu-iotests: Test qcow2 over file image creation with QMP
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (33 preceding siblings ...)
  2018-02-21 13:54 ` [Qemu-devel] [PATCH v2 34/36] block: Fail bdrv_truncate() with negative size Kevin Wolf
@ 2018-02-21 13:54 ` Kevin Wolf
  2018-02-21 13:54 ` [Qemu-devel] [PATCH v2 36/36] qemu-iotests: Test ssh image creation over QMP Kevin Wolf
  35 siblings, 0 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:54 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/206     | 436 +++++++++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/206.out | 209 ++++++++++++++++++++++
 tests/qemu-iotests/group   |   1 +
 3 files changed, 646 insertions(+)
 create mode 100755 tests/qemu-iotests/206
 create mode 100644 tests/qemu-iotests/206.out

diff --git a/tests/qemu-iotests/206 b/tests/qemu-iotests/206
new file mode 100755
index 0000000000..0a18b2b19a
--- /dev/null
+++ b/tests/qemu-iotests/206
@@ -0,0 +1,436 @@
+#!/bin/bash
+#
+# Test qcow2 and file image creation
+#
+# Copyright (C) 2018 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/>.
+#
+
+# creator
+owner=kwolf@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+status=1	# failure is the default!
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+function do_run_qemu()
+{
+    echo Testing: "$@"
+    $QEMU -nographic -qmp stdio -serial none "$@"
+    echo
+}
+
+function run_qemu()
+{
+    do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
+                          | _filter_qemu | _filter_imgfmt \
+                          | _filter_actual_image_size
+}
+
+echo
+echo "=== Successful image creation (defaults) ==="
+echo
+
+size=$((128 * 1024 * 1024))
+
+run_qemu <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "file",
+      "filename": "$TEST_IMG",
+      "size": 0
+  }
+}
+{ "execute": "blockdev-add",
+  "arguments": {
+      "driver": "file",
+      "node-name": "imgfile",
+      "filename": "$TEST_IMG"
+  }
+}
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": "imgfile",
+      "size": $size
+  }
+}
+{ "execute": "quit" }
+EOF
+
+_img_info --format-specific
+
+echo
+echo "=== Successful image creation (inline blockdev-add, explicit defaults) ==="
+echo
+
+# Choose a different size to show that we got a new image
+size=$((64 * 1024 * 1024))
+
+run_qemu <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "file",
+      "filename": "$TEST_IMG",
+      "size": 0,
+      "preallocation": "off",
+      "nocow": false
+  }
+}
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": {
+          "driver": "file",
+          "filename": "$TEST_IMG"
+      },
+      "size": $size,
+      "version": "v3",
+      "cluster-size": 65536,
+      "preallocation": "off",
+      "lazy-refcounts": false,
+      "refcount-bits": 16
+  }
+}
+{ "execute": "quit" }
+EOF
+
+_img_info --format-specific
+
+echo
+echo "=== Successful image creation (v3 non-default options) ==="
+echo
+
+# Choose a different size to show that we got a new image
+size=$((32 * 1024 * 1024))
+
+run_qemu <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "file",
+      "filename": "$TEST_IMG",
+      "size": 0,
+      "preallocation": "falloc",
+      "nocow": true
+  }
+}
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": {
+          "driver": "file",
+          "filename": "$TEST_IMG"
+      },
+      "size": $size,
+      "version": "v3",
+      "cluster-size": 2097152,
+      "preallocation": "metadata",
+      "lazy-refcounts": true,
+      "refcount-bits": 1
+  }
+}
+{ "execute": "quit" }
+EOF
+
+_img_info --format-specific
+
+echo
+echo "=== Successful image creation (v2 non-default options) ==="
+echo
+
+mv $TEST_IMG $TEST_IMG.base
+
+run_qemu <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "file",
+      "filename": "$TEST_IMG",
+      "size": 0
+  }
+}
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": {
+          "driver": "file",
+          "filename": "$TEST_IMG"
+      },
+      "size": $size,
+      "backing-file": "$TEST_IMG.base",
+      "backing-fmt": "qcow2",
+      "version": "v2",
+      "cluster-size": 512
+  }
+}
+{ "execute": "quit" }
+EOF
+
+_img_info --format-specific
+
+echo
+echo "=== Successful image creation (encrypted) ==="
+echo
+
+run_qemu -object secret,id=keysec0,data="foo" <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": {
+          "driver": "file",
+          "filename": "$TEST_IMG"
+      },
+      "size": $size,
+      "encrypt": {
+          "format": "luks",
+          "key-secret": "keysec0",
+          "cipher-alg": "twofish-128",
+          "cipher-mode": "ctr",
+          "ivgen-alg": "plain64",
+          "ivgen-hash-alg": "md5",
+          "hash-alg": "sha1",
+          "iter-time": 10
+      }
+  }
+}
+{ "execute": "quit" }
+EOF
+
+_img_info --format-specific | _filter_img_info --format-specific
+
+echo
+echo "=== Invalid BlockdevRef ==="
+echo
+
+run_qemu <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": "this doesn't exist",
+      "size": $size
+  }
+}
+{ "execute": "quit" }
+EOF
+
+
+echo
+echo "=== Invalid sizes ==="
+echo
+
+# TODO Negative image sizes aren't handled correctly, but this is a problem
+# with QAPI's implementation of the 'size' type and affects other commands as
+# well. Once this is fixed, we may want to add a test case here.
+
+# 1. Misaligned image size
+# 2. 2^64 - 512
+# 3. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
+# 4. 2^63 - 512 (generally valid, but qcow2 can't handle images this size)
+
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": "node0",
+      "size": 1234
+  }
+}
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": "node0",
+      "size": 18446744073709551104
+  }
+}
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": "node0",
+      "size": 9223372036854775808
+  }
+}
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": "node0",
+      "size": 9223372036854775296
+  }
+}
+{ "execute": "quit" }
+EOF
+
+echo
+echo "=== Invalid version ==="
+echo
+
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": "node0",
+      "size": 67108864,
+      "version": "v1"
+  }
+}
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": "node0",
+      "size": 67108864,
+      "version": "v2",
+      "lazy-refcounts": true
+  }
+}
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": "node0",
+      "size": 67108864,
+      "version": "v2",
+      "refcount-bits": 8
+  }
+}
+{ "execute": "quit" }
+EOF
+
+echo
+echo "=== Invalid backing file options ==="
+echo
+
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": "node0",
+      "size": 67108864,
+      "backing-file": "/dev/null",
+      "preallocation": "full"
+  }
+}
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": "node0",
+      "size": 67108864,
+      "backing-fmt": "$IMGFMT"
+  }
+}
+{ "execute": "quit" }
+EOF
+
+echo
+echo "=== Invalid cluster size ==="
+echo
+
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": "node0",
+      "size": 67108864,
+      "cluster-size": 1234
+  }
+}
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": "node0",
+      "size": 67108864,
+      "cluster-size": 128
+  }
+}
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": "node0",
+      "size": 67108864,
+      "cluster-size": 4194304
+  }
+}
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": "node0",
+      "size": 67108864,
+      "cluster-size": 0
+  }
+}
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": "node0",
+      "size": 281474976710656,
+      "cluster-size": 512
+  }
+}
+{ "execute": "quit" }
+EOF
+
+echo
+echo "=== Invalid refcount width ==="
+echo
+
+run_qemu -blockdev driver=file,filename="$TEST_IMG",node-name=node0 <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": "node0",
+      "size": 67108864,
+      "refcount-bits": 128
+  }
+}
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": "node0",
+      "size": 67108864,
+      "refcount-bits": 0
+  }
+}
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "$IMGFMT",
+      "file": "node0",
+      "size": 67108864,
+      "refcount-bits": 7
+  }
+}
+{ "execute": "quit" }
+EOF
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out
new file mode 100644
index 0000000000..042342ae9d
--- /dev/null
+++ b/tests/qemu-iotests/206.out
@@ -0,0 +1,209 @@
+QA output created by 206
+
+=== Successful image creation (defaults) ===
+
+Testing:
+QMP_VERSION
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
+virtual size: 128M (134217728 bytes)
+cluster_size: 65536
+Format specific information:
+    compat: 1.1
+    lazy refcounts: false
+    refcount bits: 16
+    corrupt: false
+
+=== Successful image creation (inline blockdev-add, explicit defaults) ===
+
+Testing:
+QMP_VERSION
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
+virtual size: 64M (67108864 bytes)
+cluster_size: 65536
+Format specific information:
+    compat: 1.1
+    lazy refcounts: false
+    refcount bits: 16
+    corrupt: false
+
+=== Successful image creation (v3 non-default options) ===
+
+Testing:
+QMP_VERSION
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
+virtual size: 32M (33554432 bytes)
+cluster_size: 2097152
+Format specific information:
+    compat: 1.1
+    lazy refcounts: true
+    refcount bits: 1
+    corrupt: false
+
+=== Successful image creation (v2 non-default options) ===
+
+Testing:
+QMP_VERSION
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
+virtual size: 32M (33554432 bytes)
+cluster_size: 512
+backing file: TEST_DIR/t.IMGFMT.base
+backing file format: IMGFMT
+Format specific information:
+    compat: 0.10
+    refcount bits: 16
+
+=== Successful image creation (encrypted) ===
+
+Testing: -object secret,id=keysec0,data=foo
+QMP_VERSION
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
+virtual size: 32M (33554432 bytes)
+Format specific information:
+    compat: 1.1
+    lazy refcounts: false
+    refcount bits: 16
+    encrypt:
+        ivgen alg: plain64
+        hash alg: sha1
+        cipher alg: twofish-128
+        uuid: 00000000-0000-0000-0000-000000000000
+        format: luks
+        cipher mode: ctr
+        slots:
+            [0]:
+                active: true
+                iters: 1024
+                key offset: 4096
+                stripes: 4000
+            [1]:
+                active: false
+                key offset: 69632
+            [2]:
+                active: false
+                key offset: 135168
+            [3]:
+                active: false
+                key offset: 200704
+            [4]:
+                active: false
+                key offset: 266240
+            [5]:
+                active: false
+                key offset: 331776
+            [6]:
+                active: false
+                key offset: 397312
+            [7]:
+                active: false
+                key offset: 462848
+        payload offset: 528384
+        master key iters: 1024
+    corrupt: false
+
+=== Invalid BlockdevRef ===
+
+Testing:
+QMP_VERSION
+{"return": {}}
+{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+
+
+=== Invalid sizes ===
+
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
+QMP_VERSION
+{"return": {}}
+{"error": {"class": "GenericError", "desc": "Image size must be a multiple of 512 bytes"}}
+{"error": {"class": "GenericError", "desc": "Could not resize image: Image size cannot be negative"}}
+{"error": {"class": "GenericError", "desc": "Could not resize image: Image size cannot be negative"}}
+{"error": {"class": "GenericError", "desc": "Could not resize image: Failed to grow the L1 table: File too large"}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+
+
+=== Invalid version ===
+
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
+QMP_VERSION
+{"return": {}}
+{"error": {"class": "GenericError", "desc": "Invalid parameter 'v1'"}}
+{"error": {"class": "GenericError", "desc": "Lazy refcounts only supported with compatibility level 1.1 and above (use version=v3 or greater)"}}
+{"error": {"class": "GenericError", "desc": "Different refcount widths than 16 bits require compatibility level 1.1 or above (use version=v3 or greater)"}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+
+
+=== Invalid backing file options ===
+
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
+QMP_VERSION
+{"return": {}}
+{"error": {"class": "GenericError", "desc": "Backing file and preallocation cannot be used at the same time"}}
+{"error": {"class": "GenericError", "desc": "Backing format cannot be used without backing file"}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+
+
+=== Invalid cluster size ===
+
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
+QMP_VERSION
+{"return": {}}
+{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
+{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
+{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
+{"error": {"class": "GenericError", "desc": "Cluster size must be a power of two between 512 and 2048k"}}
+{"error": {"class": "GenericError", "desc": "Could not resize image: Failed to grow the L1 table: File too large"}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+
+
+=== Invalid refcount width ===
+
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0
+QMP_VERSION
+{"return": {}}
+{"error": {"class": "GenericError", "desc": "Refcount width must be a power of two and may not exceed 64 bits"}}
+{"error": {"class": "GenericError", "desc": "Refcount width must be a power of two and may not exceed 64 bits"}}
+{"error": {"class": "GenericError", "desc": "Refcount width must be a power of two and may not exceed 64 bits"}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index a2dfe79d86..69b6504f67 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -202,3 +202,4 @@
 203 rw auto
 204 rw auto quick
 205 rw auto quick
+206 rw auto
-- 
2.13.6

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

* [Qemu-devel] [PATCH v2 36/36] qemu-iotests: Test ssh image creation over QMP
  2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
                   ` (34 preceding siblings ...)
  2018-02-21 13:54 ` [Qemu-devel] [PATCH v2 35/36] qemu-iotests: Test qcow2 over file image creation with QMP Kevin Wolf
@ 2018-02-21 13:54 ` Kevin Wolf
  2018-02-26 12:53   ` Max Reitz
  35 siblings, 1 reply; 77+ messages in thread
From: Kevin Wolf @ 2018-02-21 13:54 UTC (permalink / raw)
  To: qemu-block
  Cc: kwolf, mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/207     | 261 +++++++++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/207.out |  75 +++++++++++++
 tests/qemu-iotests/group   |   1 +
 3 files changed, 337 insertions(+)
 create mode 100755 tests/qemu-iotests/207
 create mode 100644 tests/qemu-iotests/207.out

diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207
new file mode 100755
index 0000000000..f5c77852d1
--- /dev/null
+++ b/tests/qemu-iotests/207
@@ -0,0 +1,261 @@
+#!/bin/bash
+#
+# Test ssh image creation
+#
+# Copyright (C) 2018 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/>.
+#
+
+# creator
+owner=kwolf@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+status=1	# failure is the default!
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt raw
+_supported_proto ssh
+_supported_os Linux
+
+function do_run_qemu()
+{
+    echo Testing: "$@"
+    $QEMU -nographic -qmp stdio -serial none "$@"
+    echo
+}
+
+function run_qemu()
+{
+    do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
+                          | _filter_qemu | _filter_imgfmt \
+                          | _filter_actual_image_size
+}
+
+echo
+echo "=== Successful image creation (defaults) ==="
+echo
+
+run_qemu <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "ssh",
+      "location": {
+          "path": "$TEST_IMG_FILE",
+          "server": {
+              "host": "127.0.0.1",
+              "port": "22"
+          }
+      },
+      "size": 4194304
+  }
+}
+{ "execute": "quit" }
+EOF
+
+_img_info | _filter_img_info
+echo
+TEST_IMG=$TEST_IMG_FILE _img_info | _filter_img_info
+
+echo
+echo "=== Test host-key-check options ==="
+echo
+
+run_qemu <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "ssh",
+      "location": {
+          "path": "$TEST_IMG_FILE",
+          "server": {
+              "host": "127.0.0.1",
+              "port": "22"
+          },
+          "host-key-check": {
+              "mode": "none"
+          }
+      },
+      "size": 8388608
+  }
+}
+{ "execute": "quit" }
+EOF
+
+_img_info | _filter_img_info
+
+run_qemu <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "ssh",
+      "location": {
+          "path": "$TEST_IMG_FILE",
+          "server": {
+              "host": "127.0.0.1",
+              "port": "22"
+          },
+          "host-key-check": {
+              "mode": "known_hosts"
+          }
+      },
+      "size": 4194304
+  }
+}
+{ "execute": "quit" }
+EOF
+
+_img_info | _filter_img_info
+
+
+key=$(ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" |
+      cut -d" " -f3 | base64 -d | md5sum -b | cut -d" " -f1)
+
+run_qemu <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "ssh",
+      "location": {
+          "path": "$TEST_IMG_FILE",
+          "server": {
+              "host": "127.0.0.1",
+              "port": "22"
+          },
+          "host-key-check": {
+              "mode": "hash",
+              "type": "md5",
+              "hash": "wrong"
+          }
+      },
+      "size": 8388608
+  }
+}
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "ssh",
+      "location": {
+          "path": "$TEST_IMG_FILE",
+          "server": {
+              "host": "127.0.0.1",
+              "port": "22"
+          },
+          "host-key-check": {
+              "mode": "hash",
+              "type": "md5",
+              "hash": "$key"
+          }
+      },
+      "size": 8388608
+  }
+}
+{ "execute": "quit" }
+EOF
+
+_img_info | _filter_img_info
+
+
+key=$(ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" |
+      cut -d" " -f3 | base64 -d | sha1sum -b | cut -d" " -f1)
+
+run_qemu <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "ssh",
+      "location": {
+          "path": "$TEST_IMG_FILE",
+          "server": {
+              "host": "127.0.0.1",
+              "port": "22"
+          },
+          "host-key-check": {
+              "mode": "hash",
+              "type": "sha1",
+              "hash": "wrong"
+          }
+      },
+      "size": 4194304
+  }
+}
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "ssh",
+      "location": {
+          "path": "$TEST_IMG_FILE",
+          "server": {
+              "host": "127.0.0.1",
+              "port": "22"
+          },
+          "host-key-check": {
+              "mode": "hash",
+              "type": "sha1",
+              "hash": "$key"
+          }
+      },
+      "size": 4194304
+  }
+}
+{ "execute": "quit" }
+EOF
+
+_img_info | _filter_img_info
+
+echo
+echo "=== Invalid path and user ==="
+echo
+
+run_qemu <<EOF
+{ "execute": "qmp_capabilities" }
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "ssh",
+      "location": {
+          "path": "/this/is/not/an/existing/path",
+          "server": {
+              "host": "127.0.0.1",
+              "port": "22"
+          }
+      },
+      "size": 4194304
+  }
+}
+{ "execute": "x-blockdev-create",
+  "arguments": {
+      "driver": "ssh",
+      "location": {
+          "path": "$TEST_IMG_FILE",
+          "user": "invalid user",
+          "server": {
+              "host": "127.0.0.1",
+              "port": "22"
+          }
+      },
+      "size": 4194304
+  }
+}
+{ "execute": "quit" }
+EOF
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out
new file mode 100644
index 0000000000..417deee970
--- /dev/null
+++ b/tests/qemu-iotests/207.out
@@ -0,0 +1,75 @@
+QA output created by 207
+
+=== Successful image creation (defaults) ===
+
+Testing:
+QMP_VERSION
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
+file format: IMGFMT
+virtual size: 4.0M (4194304 bytes)
+
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
+virtual size: 4.0M (4194304 bytes)
+
+=== Test host-key-check options ===
+
+Testing:
+QMP_VERSION
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
+file format: IMGFMT
+virtual size: 8.0M (8388608 bytes)
+Testing:
+QMP_VERSION
+{"return": {}}
+{"return": {}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
+file format: IMGFMT
+virtual size: 4.0M (4194304 bytes)
+Testing:
+QMP_VERSION
+{"return": {}}
+{"error": {"class": "GenericError", "desc": "remote host key does not match host_key_check 'wrong'"}}
+{"return": {}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
+file format: IMGFMT
+virtual size: 8.0M (8388608 bytes)
+Testing:
+QMP_VERSION
+{"return": {}}
+{"error": {"class": "GenericError", "desc": "remote host key does not match host_key_check 'wrong'"}}
+{"return": {}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+
+image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_DIR/t.IMGFMT"}}
+file format: IMGFMT
+virtual size: 4.0M (4194304 bytes)
+
+=== Invalid path and user ===
+
+Testing:
+QMP_VERSION
+{"return": {}}
+{"error": {"class": "GenericError", "desc": "failed to open remote file '/this/is/not/an/existing/path': Failed opening remote file (libssh2 error code: -31)"}}
+{"error": {"class": "GenericError", "desc": "failed to authenticate using publickey authentication and the identities held by your ssh-agent"}}
+{"return": {}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+
+*** done
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 69b6504f67..c401791fcd 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -203,3 +203,4 @@
 204 rw auto quick
 205 rw auto quick
 206 rw auto
+207 rw auto
-- 
2.13.6

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

* Re: [Qemu-devel] [PATCH v2 08/36] util: Add qemu_opts_to_qdict_filtered()
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 08/36] util: Add qemu_opts_to_qdict_filtered() Kevin Wolf
@ 2018-02-21 20:38   ` Eric Blake
  2018-02-22 22:03   ` Max Reitz
  1 sibling, 0 replies; 77+ messages in thread
From: Eric Blake @ 2018-02-21 20:38 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: mreitz, pkrempa, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

On 02/21/2018 07:53 AM, Kevin Wolf wrote:
> This allows, given a QemuOpts for a QemuOptsList that was merged from
> multiple QemuOptsList, to only consider those options that exist in one
> specific list. Block drivers need this to separate format-layer create
> options from protocol-level options.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   include/qemu/option.h |  2 ++
>   util/qemu-option.c    | 42 +++++++++++++++++++++++++++++++++++++-----
>   2 files changed, 39 insertions(+), 5 deletions(-)
> 

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

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

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

* Re: [Qemu-devel] [PATCH v2 09/36] test-qemu-opts: Test qemu_opts_append()
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 09/36] test-qemu-opts: Test qemu_opts_append() Kevin Wolf
@ 2018-02-21 20:53   ` Eric Blake
  2018-02-22 22:19   ` Max Reitz
  1 sibling, 0 replies; 77+ messages in thread
From: Eric Blake @ 2018-02-21 20:53 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: mreitz, pkrempa, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

On 02/21/2018 07:53 AM, Kevin Wolf wrote:
> Basic test for merging two QemuOptsLists.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   tests/test-qemu-opts.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 128 insertions(+)
> 

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

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

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

* Re: [Qemu-devel] [PATCH v2 10/36] test-qemu-opts: Test qemu_opts_to_qdict_filtered()
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 10/36] test-qemu-opts: Test qemu_opts_to_qdict_filtered() Kevin Wolf
@ 2018-02-21 20:57   ` Eric Blake
  2018-02-22  9:50     ` Kevin Wolf
  2018-02-22 22:26   ` Max Reitz
  1 sibling, 1 reply; 77+ messages in thread
From: Eric Blake @ 2018-02-21 20:57 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: mreitz, pkrempa, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

On 02/21/2018 07:53 AM, Kevin Wolf wrote:
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   tests/test-qemu-opts.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 125 insertions(+)
> 
> diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c
> index 6c3183390b..2c422abcd4 100644
> --- a/tests/test-qemu-opts.c
> +++ b/tests/test-qemu-opts.c
> @@ -10,6 +10,7 @@
>   #include "qemu/osdep.h"
>   #include "qemu/cutils.h"
>   #include "qemu/option.h"
> +#include "qemu/option_int.h"
>   #include "qapi/error.h"
>   #include "qapi/qmp/qdict.h"
>   #include "qapi/qmp/qstring.h"
> @@ -868,6 +869,127 @@ static void test_opts_append(void)
>       qemu_opts_free(merged);
>   }
>   
> +static void test_opts_to_qdict_basic(void)
> +{
> +    QemuOpts *opts;
> +    QDict *dict;
> +
> +    opts = qemu_opts_parse(&opts_list_01, "str1=foo,str2=,str3=bar,number1=42",
> +                           false, &error_abort);

Worth any additional craziness in regards to our QemuOpts parsing, like 
str1=foo,,bar,str2... for an option containing commas, or 
str2=,str1=foo, for supplying options in a different order than the 
list?  But what you have is a good addition even if you don't tweak it.

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

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

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

* Re: [Qemu-devel] [PATCH v2 10/36] test-qemu-opts: Test qemu_opts_to_qdict_filtered()
  2018-02-21 20:57   ` Eric Blake
@ 2018-02-22  9:50     ` Kevin Wolf
  2018-02-22 14:24       ` Eric Blake
  0 siblings, 1 reply; 77+ messages in thread
From: Kevin Wolf @ 2018-02-22  9:50 UTC (permalink / raw)
  To: Eric Blake
  Cc: qemu-block, mreitz, pkrempa, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

Am 21.02.2018 um 21:57 hat Eric Blake geschrieben:
> On 02/21/2018 07:53 AM, Kevin Wolf wrote:
> > Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> > ---
> >   tests/test-qemu-opts.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++
> >   1 file changed, 125 insertions(+)
> > 
> > diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c
> > index 6c3183390b..2c422abcd4 100644
> > --- a/tests/test-qemu-opts.c
> > +++ b/tests/test-qemu-opts.c
> > @@ -10,6 +10,7 @@
> >   #include "qemu/osdep.h"
> >   #include "qemu/cutils.h"
> >   #include "qemu/option.h"
> > +#include "qemu/option_int.h"
> >   #include "qapi/error.h"
> >   #include "qapi/qmp/qdict.h"
> >   #include "qapi/qmp/qstring.h"
> > @@ -868,6 +869,127 @@ static void test_opts_append(void)
> >       qemu_opts_free(merged);
> >   }
> > +static void test_opts_to_qdict_basic(void)
> > +{
> > +    QemuOpts *opts;
> > +    QDict *dict;
> > +
> > +    opts = qemu_opts_parse(&opts_list_01, "str1=foo,str2=,str3=bar,number1=42",
> > +                           false, &error_abort);
> 
> Worth any additional craziness in regards to our QemuOpts parsing, like
> str1=foo,,bar,str2... for an option containing commas, or str2=,str1=foo,
> for supplying options in a different order than the list?  But what you have
> is a good addition even if you don't tweak it.

This is not a test for parsing options string, but for converting an
already existing QemuOpts to a QDict. Parsing is already extensively
tested in /qemu-opts/opts_parse/*. I'm only using qemu_opts_parse() here
because it's the most convenient way to create a QemuOpts with multiple
options.

So the only things we need to consider in this test case are different
QemuOpts that result from the parsing. Escaped commas don't exist in
this representation any more and the associated QemuOptsList isn't
involved in the conversion to QDicts, so these wouldn't actually be new
cases for the thing we're testing here.

Kevin

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

* Re: [Qemu-devel] [PATCH v2 10/36] test-qemu-opts: Test qemu_opts_to_qdict_filtered()
  2018-02-22  9:50     ` Kevin Wolf
@ 2018-02-22 14:24       ` Eric Blake
  0 siblings, 0 replies; 77+ messages in thread
From: Eric Blake @ 2018-02-22 14:24 UTC (permalink / raw)
  To: Kevin Wolf
  Cc: qemu-block, mreitz, pkrempa, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

On 02/22/2018 03:50 AM, Kevin Wolf wrote:

>>> +    opts = qemu_opts_parse(&opts_list_01, "str1=foo,str2=,str3=bar,number1=42",
>>> +                           false, &error_abort);
>>
>> Worth any additional craziness in regards to our QemuOpts parsing, like
>> str1=foo,,bar,str2... for an option containing commas, or str2=,str1=foo,
>> for supplying options in a different order than the list?  But what you have
>> is a good addition even if you don't tweak it.
> 
> This is not a test for parsing options string, but for converting an
> already existing QemuOpts to a QDict. Parsing is already extensively
> tested in /qemu-opts/opts_parse/*. I'm only using qemu_opts_parse() here
> because it's the most convenient way to create a QemuOpts with multiple
> options.
> 
> So the only things we need to consider in this test case are different
> QemuOpts that result from the parsing. Escaped commas don't exist in
> this representation any more and the associated QemuOptsList isn't
> involved in the conversion to QDicts, so these wouldn't actually be new
> cases for the thing we're testing here.

Alright, you've convinced me that this isn't the test to be hammering on 
QemuOpts.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

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

* Re: [Qemu-devel] [PATCH v2 08/36] util: Add qemu_opts_to_qdict_filtered()
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 08/36] util: Add qemu_opts_to_qdict_filtered() Kevin Wolf
  2018-02-21 20:38   ` Eric Blake
@ 2018-02-22 22:03   ` Max Reitz
  1 sibling, 0 replies; 77+ messages in thread
From: Max Reitz @ 2018-02-22 22:03 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

On 2018-02-21 14:53, Kevin Wolf wrote:
> This allows, given a QemuOpts for a QemuOptsList that was merged from
> multiple QemuOptsList, to only consider those options that exist in one
> specific list. Block drivers need this to separate format-layer create
> options from protocol-level options.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  include/qemu/option.h |  2 ++
>  util/qemu-option.c    | 42 +++++++++++++++++++++++++++++++++++++-----
>  2 files changed, 39 insertions(+), 5 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


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

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

* Re: [Qemu-devel] [PATCH v2 09/36] test-qemu-opts: Test qemu_opts_append()
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 09/36] test-qemu-opts: Test qemu_opts_append() Kevin Wolf
  2018-02-21 20:53   ` Eric Blake
@ 2018-02-22 22:19   ` Max Reitz
  1 sibling, 0 replies; 77+ messages in thread
From: Max Reitz @ 2018-02-22 22:19 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

On 2018-02-21 14:53, Kevin Wolf wrote:
> Basic test for merging two QemuOptsLists.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  tests/test-qemu-opts.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 128 insertions(+)

Reviewed-by: Max Reitz <mreitz@redhat.com>


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

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

* Re: [Qemu-devel] [PATCH v2 10/36] test-qemu-opts: Test qemu_opts_to_qdict_filtered()
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 10/36] test-qemu-opts: Test qemu_opts_to_qdict_filtered() Kevin Wolf
  2018-02-21 20:57   ` Eric Blake
@ 2018-02-22 22:26   ` Max Reitz
  1 sibling, 0 replies; 77+ messages in thread
From: Max Reitz @ 2018-02-22 22:26 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

On 2018-02-21 14:53, Kevin Wolf wrote:
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  tests/test-qemu-opts.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 125 insertions(+)

Reviewed-by: Max Reitz <mreitz@redhat.com>


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

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

* Re: [Qemu-devel] [PATCH v2 11/36] qdict: Introduce qdict_rename_keys()
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 11/36] qdict: Introduce qdict_rename_keys() Kevin Wolf
@ 2018-02-22 22:40   ` Max Reitz
  2018-02-22 23:13   ` Eric Blake
  1 sibling, 0 replies; 77+ messages in thread
From: Max Reitz @ 2018-02-22 22:40 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

On 2018-02-21 14:53, Kevin Wolf wrote:
> A few block drivers will need to rename .bdrv_create options for their
> QAPIfication, so let's have a helper function for that.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  include/qapi/qmp/qdict.h |   6 +++
>  qobject/qdict.c          |  34 ++++++++++++++
>  tests/check-qdict.c      | 113 +++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 153 insertions(+)

[...]

> diff --git a/tests/check-qdict.c b/tests/check-qdict.c
> index ec628f3453..5f8f3be9ff 100644
> --- a/tests/check-qdict.c
> +++ b/tests/check-qdict.c
> @@ -665,6 +665,117 @@ static void qdict_crumple_test_empty(void)

[...]

> +    /* Renames are processed top to bottom */
> +    renames = (QDictRenames[]) {
> +        { "abc",        "tmp" },
> +        { "abcdef",     "abc" },
> +        { "number",     "abcdef" },
> +        { "flag",       "number" },
> +        { "nothing",    "flag" },
> +        { "tmp",        "nothing" },
> +        { NULL , NULL }
> +    };

A bit confusing to follow, but I guess nobody will have to follow it
after me and Eric.

> +    copy = qdict_clone_shallow(dict);
> +    qdict_rename_keys(copy, renames, &error_abort);
> +
> +    g_assert_cmpstr(qdict_get_str(copy, "nothing"), ==, "foo");
> +    g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "bar");
> +    g_assert_cmpint(qdict_get_int(copy, "abcdef"), ==, 42);
> +    g_assert_cmpint(qdict_get_bool(copy, "number"), ==, true);
> +    g_assert(qobject_type(qdict_get(copy, "flag")) == QTYPE_QNULL);
> +    g_assert(!qdict_haskey(copy, "tmp"));
> +
> +    QDECREF(copy);
> +
> +    /* Conflicting renam */

*rename

With that fixed:

Reviewed-by: Max Reitz <mreitz@redhat.com>


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

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

* Re: [Qemu-devel] [PATCH v2 13/36] block: Make bdrv_is_whitelisted() public
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 13/36] block: Make bdrv_is_whitelisted() public Kevin Wolf
@ 2018-02-22 22:45   ` Max Reitz
  2018-02-22 23:17   ` Eric Blake
  1 sibling, 0 replies; 77+ messages in thread
From: Max Reitz @ 2018-02-22 22:45 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

On 2018-02-21 14:53, Kevin Wolf wrote:
> We'll use a separate source file for image creation, and we need to
> check there whether the requested driver is whitelisted.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  include/block/block.h | 1 +
>  block.c               | 2 +-
>  2 files changed, 2 insertions(+), 1 deletion(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


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

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

* Re: [Qemu-devel] [PATCH v2 14/36] block: x-blockdev-create QMP command
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 14/36] block: x-blockdev-create QMP command Kevin Wolf
@ 2018-02-22 22:50   ` Max Reitz
  2018-02-22 23:19   ` Eric Blake
  1 sibling, 0 replies; 77+ messages in thread
From: Max Reitz @ 2018-02-22 22:50 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

On 2018-02-21 14:53, Kevin Wolf wrote:
> This adds a synchronous x-blockdev-create QMP command that can create
> qcow2 images on a given node name.
> 
> We don't want to block while creating an image, so this is not the final
> interface in all aspects, but BlockdevCreateOptionsQcow2 and
> .bdrv_co_create() are what they actually might look like in the end. In
> any case, this should be good enough to test whether we interpret
> BlockdevCreateOptions as we should.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  qapi/block-core.json      | 12 ++++++++
>  include/block/block_int.h |  2 ++
>  block/create.c            | 76 +++++++++++++++++++++++++++++++++++++++++++++++
>  block/qcow2.c             |  3 +-
>  block/Makefile.objs       |  2 +-
>  5 files changed, 93 insertions(+), 2 deletions(-)
>  create mode 100644 block/create.c

Reviewed-by: Max Reitz <mreitz@redhat.com>


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

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

* Re: [Qemu-devel] [PATCH v2 17/36] gluster: Support .bdrv_co_create
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 17/36] gluster: " Kevin Wolf
@ 2018-02-22 23:01   ` Max Reitz
  2018-02-23 15:10   ` Eric Blake
  1 sibling, 0 replies; 77+ messages in thread
From: Max Reitz @ 2018-02-22 23:01 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

On 2018-02-21 14:53, Kevin Wolf wrote:
> This adds the .bdrv_co_create driver callback to gluster, which enables
> image creation over QMP.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  qapi/block-core.json |  18 ++++++-
>  block/gluster.c      | 135 ++++++++++++++++++++++++++++++++++-----------------
>  2 files changed, 108 insertions(+), 45 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


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

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

* Re: [Qemu-devel] [PATCH v2 18/36] rbd: Fix use after free in qemu_rbd_set_keypairs() error path
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 18/36] rbd: Fix use after free in qemu_rbd_set_keypairs() error path Kevin Wolf
@ 2018-02-22 23:02   ` Max Reitz
  2018-02-23 15:15   ` Eric Blake
  1 sibling, 0 replies; 77+ messages in thread
From: Max Reitz @ 2018-02-22 23:02 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

On 2018-02-21 14:53, Kevin Wolf wrote:
> If we want to include the invalid option name in the error message, we
> can't free the string earlier than that.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block/rbd.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


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

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

* Re: [Qemu-devel] [PATCH v2 19/36] rbd: Factor out qemu_rbd_connect()
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 19/36] rbd: Factor out qemu_rbd_connect() Kevin Wolf
@ 2018-02-22 23:10   ` Max Reitz
  2018-02-23 15:19     ` Kevin Wolf
  0 siblings, 1 reply; 77+ messages in thread
From: Max Reitz @ 2018-02-22 23:10 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

On 2018-02-21 14:53, Kevin Wolf wrote:
> The code to establish an RBD connection is duplicated between open and
> create. In order to be able to share the code, factor out the code from
> qemu_rbd_open() as a first step.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block/rbd.c | 100 ++++++++++++++++++++++++++++++++++++------------------------
>  1 file changed, 60 insertions(+), 40 deletions(-)
> 
> diff --git a/block/rbd.c b/block/rbd.c
> index 27fa11b473..4bbcce4eca 100644
> --- a/block/rbd.c
> +++ b/block/rbd.c
> @@ -544,32 +544,17 @@ out:
>      return rados_str;
>  }
>  
> -static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
> -                         Error **errp)
> +static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
> +                            char **s_snap, char **s_image_name,
> +                            QDict *options, bool cache, Error **errp)

Bikeshedding ahead:  Maybe this should be called qemu_rados_connect()?
I don't know anything about this, but there seems to be a distinction
between rados_* functions and rbd_* functions -- the former work on the
pool, the latter on the single block device.

Since this function only connects to the pool and not to a single device
within, I think it should be called qemu_rados_connect() instead of
qemu_rbd_connect().

(Also because qemu_rbd_connect() seems so similar to qemu_rbd_open().)

Up to you:

Reviewed-by: Max Reitz <mreitz@redhat.com>


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

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

* Re: [Qemu-devel] [PATCH v2 20/36] rbd: Remove non-schema options from runtime_opts
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 20/36] rbd: Remove non-schema options from runtime_opts Kevin Wolf
@ 2018-02-22 23:13   ` Max Reitz
  2018-02-22 23:16     ` Max Reitz
  0 siblings, 1 reply; 77+ messages in thread
From: Max Reitz @ 2018-02-22 23:13 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

On 2018-02-21 14:53, Kevin Wolf wrote:
> Instead of the QemuOpts in qemu_rbd_connect(), we want to use QAPI
> objects. As a preparation, fetch those options directly from the QDict
> that .bdrv_open() supports in the rbd driver and that are not in the
> schema.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block/rbd.c | 55 ++++++++++++++++++++++++-------------------------------
>  1 file changed, 24 insertions(+), 31 deletions(-)
> 
> diff --git a/block/rbd.c b/block/rbd.c
> index 4bbcce4eca..2e79c2d1fd 100644
> --- a/block/rbd.c
> +++ b/block/rbd.c
> @@ -326,28 +326,6 @@ static QemuOptsList runtime_opts = {
>          /*
>           * server.* extracted manually, see qemu_rbd_mon_host()
>           */
> -        {
> -            .name = "password-secret",
> -            .type = QEMU_OPT_STRING,
> -            .help = "ID of secret providing the password",
> -        },

Err, did we just forget this in the QAPI schema or is it really not
supposed to be there?

Max


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

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

* Re: [Qemu-devel] [PATCH v2 11/36] qdict: Introduce qdict_rename_keys()
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 11/36] qdict: Introduce qdict_rename_keys() Kevin Wolf
  2018-02-22 22:40   ` Max Reitz
@ 2018-02-22 23:13   ` Eric Blake
  1 sibling, 0 replies; 77+ messages in thread
From: Eric Blake @ 2018-02-22 23:13 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: mreitz, pkrempa, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

On 02/21/2018 07:53 AM, Kevin Wolf wrote:
> A few block drivers will need to rename .bdrv_create options for their
> QAPIfication, so let's have a helper function for that.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   include/qapi/qmp/qdict.h |   6 +++
>   qobject/qdict.c          |  34 ++++++++++++++
>   tests/check-qdict.c      | 113 +++++++++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 153 insertions(+)
> 

> +/**
> + * qdict_rename_keys(): Rename keys in qdict according to the replacements
> + * specified in the array renames. The array must be terminated by an entry
> + * with from = NULL.
> + *
> + * The renames are performed individually in the order of the array, so entries
> + * may be renamed multiple times and may or may not conflict depending on the
> + * order of the renames array.

Oh interesting - so I could rename a->tmp, b->a, tmp->b in the classic 
strategy to intentionally avoid conflicts.  But I hope none of our 
actual clients ever abuse the interface that directly.

> + *
> + * Returns true for success, false in error cases.

I won't make you change it, but is 0/-1 any easier to understand 
intuitively?  With bool, it's often a case of "I'd better check the docs 
for whether true meant the sense I wanted"

> + */
> +bool qdict_rename_keys(QDict *qdict, const QDictRenames *renames, Error **errp)
> +{

> +++ b/tests/check-qdict.c

> +    copy = qdict_clone_shallow(dict);
> +    qdict_rename_keys(copy, renames, &error_abort);
> +
> +    g_assert_cmpstr(qdict_get_str(copy, "abc"), ==, "foo");
> +    g_assert_cmpstr(qdict_get_str(copy, "abcdef"), ==, "bar");
> +    g_assert_cmpint(qdict_get_int(copy, "number"), ==, 42);
> +    g_assert_cmpint(qdict_get_bool(copy, "flag"), ==, true);
> +    g_assert(qobject_type(qdict_get(copy, "nothing")) == QTYPE_QNULL);

Also worth an assert that there are exactly 5 keys, so that rename 
didn't botch something to leave a different straggler key behind?

> +
> +    QDECREF(copy);
> +
> +    /* Simple rename of all entries */
> +    renames = (QDictRenames[]) {
> +        { "abc",        "str1" },
> +        { "abcdef",     "str2" },
> +        { "number",     "int" },
> +        { "flag",       "bool" },
> +        { "nothing",    "null" },
> +        { NULL , NULL }
> +    };
> +    copy = qdict_clone_shallow(dict);
> +    qdict_rename_keys(copy, renames, &error_abort);
> +
> +    g_assert(!qdict_haskey(copy, "abc"));
> +    g_assert(!qdict_haskey(copy, "abcdef"));
> +    g_assert(!qdict_haskey(copy, "number"));
> +    g_assert(!qdict_haskey(copy, "flag"));
> +    g_assert(!qdict_haskey(copy, "nothing"));

Direct check for the obvious keys that should have been renamed,

> +
> +    g_assert_cmpstr(qdict_get_str(copy, "str1"), ==, "foo");
> +    g_assert_cmpstr(qdict_get_str(copy, "str2"), ==, "bar");
> +    g_assert_cmpint(qdict_get_int(copy, "int"), ==, 42);
> +    g_assert_cmpint(qdict_get_bool(copy, "bool"), ==, true);
> +    g_assert(qobject_type(qdict_get(copy, "null")) == QTYPE_QNULL);

but again, an assert that there are 5 keys rules out all other mistakes, 
too.

Up to you whether to further tweak the tests; and with the spelling fix 
Max already found,

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

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

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

* Re: [Qemu-devel] [PATCH v2 20/36] rbd: Remove non-schema options from runtime_opts
  2018-02-22 23:13   ` Max Reitz
@ 2018-02-22 23:16     ` Max Reitz
  0 siblings, 0 replies; 77+ messages in thread
From: Max Reitz @ 2018-02-22 23:16 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

On 2018-02-23 00:13, Max Reitz wrote:
> On 2018-02-21 14:53, Kevin Wolf wrote:
>> Instead of the QemuOpts in qemu_rbd_connect(), we want to use QAPI
>> objects. As a preparation, fetch those options directly from the QDict
>> that .bdrv_open() supports in the rbd driver and that are not in the
>> schema.
>>
>> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
>> ---
>>  block/rbd.c | 55 ++++++++++++++++++++++++-------------------------------
>>  1 file changed, 24 insertions(+), 31 deletions(-)
>>
>> diff --git a/block/rbd.c b/block/rbd.c
>> index 4bbcce4eca..2e79c2d1fd 100644
>> --- a/block/rbd.c
>> +++ b/block/rbd.c
>> @@ -326,28 +326,6 @@ static QemuOptsList runtime_opts = {
>>          /*
>>           * server.* extracted manually, see qemu_rbd_mon_host()
>>           */
>> -        {
>> -            .name = "password-secret",
>> -            .type = QEMU_OPT_STRING,
>> -            .help = "ID of secret providing the password",
>> -        },
> 
> Err, did we just forget this in the QAPI schema or is it really not
> supposed to be there?

Ah, we intentionally removed it after it was added.  OK, then.

Reviewed-by: Max Reitz <mreitz@redhat.com>


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

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

* Re: [Qemu-devel] [PATCH v2 13/36] block: Make bdrv_is_whitelisted() public
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 13/36] block: Make bdrv_is_whitelisted() public Kevin Wolf
  2018-02-22 22:45   ` Max Reitz
@ 2018-02-22 23:17   ` Eric Blake
  1 sibling, 0 replies; 77+ messages in thread
From: Eric Blake @ 2018-02-22 23:17 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: mreitz, pkrempa, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

On 02/21/2018 07:53 AM, Kevin Wolf wrote:
> We'll use a separate source file for image creation, and we need to
> check there whether the requested driver is whitelisted.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   include/block/block.h | 1 +
>   block.c               | 2 +-
>   2 files changed, 2 insertions(+), 1 deletion(-)
> 

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

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

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

* Re: [Qemu-devel] [PATCH v2 14/36] block: x-blockdev-create QMP command
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 14/36] block: x-blockdev-create QMP command Kevin Wolf
  2018-02-22 22:50   ` Max Reitz
@ 2018-02-22 23:19   ` Eric Blake
  1 sibling, 0 replies; 77+ messages in thread
From: Eric Blake @ 2018-02-22 23:19 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: mreitz, pkrempa, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

On 02/21/2018 07:53 AM, Kevin Wolf wrote:
> This adds a synchronous x-blockdev-create QMP command that can create
> qcow2 images on a given node name.
> 
> We don't want to block while creating an image, so this is not the final
> interface in all aspects, but BlockdevCreateOptionsQcow2 and
> .bdrv_co_create() are what they actually might look like in the end. In
> any case, this should be good enough to test whether we interpret
> BlockdevCreateOptions as we should.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   qapi/block-core.json      | 12 ++++++++
>   include/block/block_int.h |  2 ++
>   block/create.c            | 76 +++++++++++++++++++++++++++++++++++++++++++++++
>   block/qcow2.c             |  3 +-
>   block/Makefile.objs       |  2 +-
>   5 files changed, 93 insertions(+), 2 deletions(-)
>   create mode 100644 block/create.c
> 

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

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

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

* Re: [Qemu-devel] [PATCH v2 21/36] rbd: Pass BlockdevOptionsRbd to qemu_rbd_connect()
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 21/36] rbd: Pass BlockdevOptionsRbd to qemu_rbd_connect() Kevin Wolf
@ 2018-02-22 23:25   ` Max Reitz
  2018-02-23 16:19     ` Kevin Wolf
  0 siblings, 1 reply; 77+ messages in thread
From: Max Reitz @ 2018-02-22 23:25 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

On 2018-02-21 14:53, Kevin Wolf wrote:
> With the conversion to a QAPI options object, the function is now
> prepared to be used in a .bdrv_co_create implementation.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block/rbd.c | 102 +++++++++++++++++++++++++++++++-----------------------------
>  1 file changed, 52 insertions(+), 50 deletions(-)
> 
> diff --git a/block/rbd.c b/block/rbd.c
> index 2e79c2d1fd..26641e53e0 100644
> --- a/block/rbd.c
> +++ b/block/rbd.c

[...]

> @@ -482,24 +484,27 @@ static void qemu_rbd_complete_aio(RADOSCB *rcb)
>      qemu_aio_unref(acb);
>  }
>  
> -static char *qemu_rbd_mon_host(QDict *options, Error **errp)
> +static char *qemu_rbd_mon_host(BlockdevOptionsRbd *opts, Error **errp)
>  {
> -    const char **vals = g_new(const char *, qdict_size(options) + 1);
> -    char keybuf[32];
> +    const char **vals;
>      const char *host, *port;
>      char *rados_str;
> -    int i;
> -
> -    for (i = 0;; i++) {
> -        sprintf(keybuf, "server.%d.host", i);
> -        host = qdict_get_try_str(options, keybuf);
> -        qdict_del(options, keybuf);
> -        sprintf(keybuf, "server.%d.port", i);
> -        port = qdict_get_try_str(options, keybuf);
> -        qdict_del(options, keybuf);
> -        if (!host && !port) {
> -            break;
> -        }
> +    InetSocketAddressBaseList *p;
> +    int i, cnt;
> +
> +    if (!opts->has_server) {
> +        return NULL;
> +    }
> +
> +    for (cnt = 0, p = opts->server; p; p = p->next) {
> +        cnt++;
> +    }
> +
> +    vals = g_new(const char *, cnt + 1);
> +
> +    for (i = 0, p = opts->server; p; p = p->next, i++) {
> +        host = p->value->host;
> +        port = p->value->port;
>          if (!host) {
>              error_setg(errp, "Parameter server.%d.host is missing", i);
>              rados_str = NULL;

host and port are mandatory in the schema, so we can omit this now.

> @@ -524,56 +529,34 @@ out:
>  
>  static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
>                              char **s_snap, char **s_image_name,
> -                            QDict *options, bool cache,
> +                            BlockdevOptionsRbd *opts, bool cache,
>                              const char *keypairs, const char *secretid,
>                              Error **errp)
>  {
> -    QemuOpts *opts;
>      char *mon_host = NULL;
> -    const char *pool, *snap, *conf, *user, *image_name;
>      Error *local_err = NULL;
>      int r;
>  
> -    opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
> -    qemu_opts_absorb_qdict(opts, options, &local_err);
> +    mon_host = qemu_rbd_mon_host(opts, &local_err);
>      if (local_err) {
>          error_propagate(errp, local_err);
>          r = -EINVAL;
>          goto failed_opts;
>      }
>  
> -    mon_host = qemu_rbd_mon_host(options, &local_err);
> -    if (local_err) {
> -        error_propagate(errp, local_err);
> -        r = -EINVAL;
> -        goto failed_opts;
> -    }
> -
> -    pool           = qemu_opt_get(opts, "pool");
> -    conf           = qemu_opt_get(opts, "conf");
> -    snap           = qemu_opt_get(opts, "snapshot");
> -    user           = qemu_opt_get(opts, "user");
> -    image_name     = qemu_opt_get(opts, "image");
> -
> -    if (!pool || !image_name) {
> -        error_setg(errp, "Parameters 'pool' and 'image' are required");
> -        r = -EINVAL;
> -        goto failed_opts;
> -    }
> -
> -    r = rados_create(cluster, user);
> +    r = rados_create(cluster, opts->user);
>      if (r < 0) {
>          error_setg_errno(errp, -r, "error initializing");
>          goto failed_opts;
>      }
>  
> -    *s_snap = g_strdup(snap);
> -    *s_image_name = g_strdup(image_name);
> +    *s_snap = g_strdup(opts->snapshot);
> +    *s_image_name = g_strdup(opts->image);
>  
>      /* try default location when conf=NULL, but ignore failure */
> -    r = rados_conf_read_file(*cluster, conf);
> -    if (conf && r < 0) {
> -        error_setg_errno(errp, -r, "error reading conf file %s", conf);
> +    r = rados_conf_read_file(*cluster, opts->conf);
> +    if (opts->has_conf && r < 0) {

Reading opts->conf without knowing whether opts->has_conf is true is a
bit weird.  Would you mind "s->has_conf ? opts->conf : NULL" for the
rados_conf_read() call?

On that thought, opts->snapshot and opts->user are optional, too.  Are
they guaranteed to be NULL if they haven't been specified?  Should we
guard those accesses with opts->has_* queries, too?

> +        error_setg_errno(errp, -r, "error reading conf file %s", opts->conf);
>          goto failed_shutdown;
>      }
>  

[..]

> @@ -666,8 +650,25 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
>          qdict_del(options, "password-secret");
>      }
>  
> +    /* Convert the remaining options into a QAPI object */
> +    crumpled = qdict_crumple(options, errp);
> +    if (crumpled == NULL) {
> +        return -EINVAL;

"goto out", or this will leak @keypairs and @secretid.

Max

> +    }
> +
> +    v = qobject_input_visitor_new_keyval(crumpled);
> +    visit_type_BlockdevOptionsRbd(v, NULL, &opts, &local_err);
> +    visit_free(v);
> +    qobject_decref(crumpled);
> +
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        r = -EINVAL;
> +        goto out;
> +    }
> +
>      r = qemu_rbd_connect(&s->cluster, &s->io_ctx, &s->snap, &s->image_name,
> -                         options, !(flags & BDRV_O_NOCACHE), keypairs, secretid,
> +                         opts, !(flags & BDRV_O_NOCACHE), keypairs, secretid,
>                           errp);
>      if (r < 0) {
>          goto out;
> @@ -706,6 +707,7 @@ failed_open:
>      g_free(s->image_name);
>      rados_shutdown(s->cluster);
>  out:
> +    qapi_free_BlockdevOptionsRbd(opts);
>      g_free(keypairs);
>      g_free(secretid);
>      return r;
> 



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

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

* Re: [Qemu-devel] [PATCH v2 22/36] rbd: Support .bdrv_co_create
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 22/36] rbd: Support .bdrv_co_create Kevin Wolf
@ 2018-02-22 23:30   ` Max Reitz
  0 siblings, 0 replies; 77+ messages in thread
From: Max Reitz @ 2018-02-22 23:30 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

On 2018-02-21 14:53, Kevin Wolf wrote:
> This adds the .bdrv_co_create driver callback to rbd, which enables
> image creation over QMP.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  qapi/block-core.json |  19 ++++++-
>  block/rbd.c          | 146 ++++++++++++++++++++++++++++++++++-----------------
>  2 files changed, 116 insertions(+), 49 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>


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

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

* Re: [Qemu-devel] [PATCH v2 15/36] file-posix: Support .bdrv_co_create
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 15/36] file-posix: Support .bdrv_co_create Kevin Wolf
@ 2018-02-22 23:34   ` Eric Blake
  0 siblings, 0 replies; 77+ messages in thread
From: Eric Blake @ 2018-02-22 23:34 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: mreitz, pkrempa, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

On 02/21/2018 07:53 AM, Kevin Wolf wrote:
> This adds the .bdrv_co_create driver callback to file, which enables
> image creation over QMP.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> Reviewed-by: Max Reitz <mreitz@redhat.com>
> ---
>   qapi/block-core.json | 20 +++++++++++++-
>   block/file-posix.c   | 77 +++++++++++++++++++++++++++++++++++++---------------
>   2 files changed, 74 insertions(+), 23 deletions(-)
> 
> diff --git a/qapi/block-core.json b/qapi/block-core.json
> index 359195a1a3..0040795603 100644
> --- a/qapi/block-core.json
> +++ b/qapi/block-core.json
> @@ -3359,6 +3359,24 @@
>   { 'command': 'blockdev-del', 'data': { 'node-name': 'str' } }
>   
>   ##
> +# @BlockdevCreateOptionsFile:
> +#
> +# Driver specific image creation options for file.
> +#
> +# @filename         Filename for the new image file

Does this allow /dev/fdset magic filenames, for when libvirt has to 
pre-create a file and assign correct SELinux permissions, then hand the 
fd over the monitor, but where qemu then takes over the rest of the 
creation task?  What tasks remain in file-posix creation, you ask?...

> +# @size             Size of the virtual disk in bytes
> +# @preallocation    Preallocation mode for the new image (default: off)

...why, of course, a non-default preallocation.  It would be nice to 
hand a 0-byte fd to qemu, then let qemu uniformly truncate it to its 
desired size, using whatever preallocation strategy is supported, rather 
than having to have libvirt worry about preallocation in addition to 
SELinux labeling.  Especially once we get an async command variant 
working, where we can track progress, given that some forms of 
preallocation take a while.  And we may someday still reach the policy 
decision where we can block qemu from directly calling open().

> +# @nocow            Turn off copy-on-write (valid only on btrfs; default: off)
> +#
> +# Since: 2.12
> +##
> +{ 'struct': 'BlockdevCreateOptionsFile',
> +  'data': { 'filename':         'str',
> +            'size':             'size',
> +            '*preallocation':   'PreallocMode',
> +            '*nocow':           'bool' } }
> +

I think I asked earlier why size is mandatory at this layer, but I'm 
still okay with that.

Hmm, since "creating" a file can be a destructive operation (if size 
requires a downwards truncation, or even if we intentionally wipe the 
first sector so that any prior bits that resemble a different format are 
no longer visible, or if preallocation explicitly wipes the entire 
image...), do we want to have any safeguards in place so that creation 
is attempted only on a newly-opened BDS, or with a force flag if size 
does not match the current size, or so on?  That's more a question for 
the x-blockdev-create command though, so it doesn't stop review of this 
patch.


>   
> -    fd = qemu_open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
> +    /* Create file */
> +    fd = qemu_open(file_opts->filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
>                      0644);

At any rate, qemu_open() means that we be supporting /dev/fdset magic on 
a passed-in fd.

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

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

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

* Re: [Qemu-devel] [PATCH v2 23/36] rbd: ***ing s->snap/image_name in qemu_rbd_open()
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 23/36] rbd: Assing s->snap/image_name in qemu_rbd_open() Kevin Wolf
@ 2018-02-22 23:34   ` Max Reitz
  0 siblings, 0 replies; 77+ messages in thread
From: Max Reitz @ 2018-02-22 23:34 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

I suppose the first word after the colon in your subject is supposed to
be "assign" and not what it currently is (which is something I am not
going to repeat!). :-)

On 2018-02-21 14:53, Kevin Wolf wrote:
> Now that the options are already available in qemu_rbd_open() and not
> only parsed in qemu_rbd_connect(), we can assign s->snap and
> s->image_name there instead of passing the fields by reference to
> qemu_rbd_connect().
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block/rbd.c | 14 +++++---------
>  1 file changed, 5 insertions(+), 9 deletions(-)
> 
> diff --git a/block/rbd.c b/block/rbd.c
> index 82f03505a9..a34bf0be46 100644
> --- a/block/rbd.c
> +++ b/block/rbd.c

[...]

> @@ -716,13 +710,15 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
>          goto out;
>      }
>  
> -    r = qemu_rbd_connect(&s->cluster, &s->io_ctx, &s->snap, &s->image_name,
> -                         opts, !(flags & BDRV_O_NOCACHE), keypairs, secretid,
> -                         errp);
> +    r = qemu_rbd_connect(&s->cluster, &s->io_ctx, opts,
> +                         !(flags & BDRV_O_NOCACHE), keypairs, secretid, errp);
>      if (r < 0) {
>          goto out;
>      }
>  
> +    s->snap = g_strdup(opts->snapshot);
> +    s->image_name = g_strdup(opts->image);
> +

Same question as in patch 21: Should we guard these by checking
opts->has_* first?

Max

>      /* rbd_open is always r/w */
>      r = rbd_open(s->io_ctx, s->image_name, &s->image, s->snap);
>      if (r < 0) {
> 



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

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

* Re: [Qemu-devel] [PATCH v2 34/36] block: Fail bdrv_truncate() with negative size
  2018-02-21 13:54 ` [Qemu-devel] [PATCH v2 34/36] block: Fail bdrv_truncate() with negative size Kevin Wolf
@ 2018-02-22 23:35   ` Eric Blake
  0 siblings, 0 replies; 77+ messages in thread
From: Eric Blake @ 2018-02-22 23:35 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: mreitz, pkrempa, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

On 02/21/2018 07:54 AM, Kevin Wolf wrote:
> Most callers have their own checks, but something like this should also
> be checked centrally. As it happens, x-blockdev-create can pass negative
> image sizes to format drivers (because there is no QAPI type that would
> reject negative numbers) and triggers the check added by this patch.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> Reviewed-by: Max Reitz <mreitz@redhat.com>
> ---
>   block.c | 5 +++++
>   1 file changed, 5 insertions(+)

Are there any callers that can be simplified (such as now assert()ing 
rather than checking and returning an error) due to better guarantees 
about a non-negative argument?

> 
> diff --git a/block.c b/block.c
> index 4a7e448226..5c874aefa1 100644
> --- a/block.c
> +++ b/block.c
> @@ -3684,6 +3684,11 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
>           error_setg(errp, "No medium inserted");
>           return -ENOMEDIUM;
>       }
> +    if (offset < 0) {
> +        error_setg(errp, "Image size cannot be negative");
> +        return -EINVAL;
> +    }
> +
>       if (!drv->bdrv_truncate) {
>           if (bs->file && drv->is_filter) {
>               return bdrv_truncate(bs->file, offset, prealloc, errp);
> 

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

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

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

* Re: [Qemu-devel] [PATCH v2 24/36] rbd: Use qemu_rbd_connect() in qemu_rbd_do_create()
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 24/36] rbd: Use qemu_rbd_connect() in qemu_rbd_do_create() Kevin Wolf
@ 2018-02-22 23:37   ` Max Reitz
  0 siblings, 0 replies; 77+ messages in thread
From: Max Reitz @ 2018-02-22 23:37 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

On 2018-02-21 14:53, Kevin Wolf wrote:
> This is almost exactly the same code. The differences are that
> qemu_rbd_connect() supports BlockdevOptionsRbd.server and that the cache
> mode is set explicitly.
> 
> Supporting 'server' is a welcome new feature for image creation.
> Caching is disabled by default, so leave it that way.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block/rbd.c | 54 ++++++++++--------------------------------------------
>  1 file changed, 10 insertions(+), 44 deletions(-)
> 
> diff --git a/block/rbd.c b/block/rbd.c
> index a34bf0be46..af8e186106 100644
> --- a/block/rbd.c
> +++ b/block/rbd.c

[...]

> @@ -370,54 +369,21 @@ static int qemu_rbd_do_create(BlockdevCreateOptions *options,
>          obj_order = ctz32(objsize);
>      }
>  
> -    ret = rados_create(&cluster, opts->location->user);
> +    ret = qemu_rbd_connect(&cluster, &io_ctx, opts->location, false, keypairs,
> +                           NULL, errp);

s/NULL/password_secret/?

Max


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

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

* Re: [Qemu-devel] [PATCH v2 27/36] sheepdog: QAPIfy "redundacy" create option
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 27/36] sheepdog: QAPIfy "redundacy" create option Kevin Wolf
@ 2018-02-22 23:43   ` Max Reitz
  2018-02-23 15:25   ` Kevin Wolf
  1 sibling, 0 replies; 77+ messages in thread
From: Max Reitz @ 2018-02-22 23:43 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

On 2018-02-21 14:53, Kevin Wolf wrote:
> The "redundacy" option for Sheepdog image creation is currently a string
> that can encode one or two integers depending on its format, which at
> the same time implicitly selects a mode.
> 
> This patch turns it into a QAPI union and converts the string into such
> a QAPI object before interpreting the values.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  qapi/block-core.json | 45 +++++++++++++++++++++++++
>  block/sheepdog.c     | 94 +++++++++++++++++++++++++++++++++++++---------------
>  2 files changed, 112 insertions(+), 27 deletions(-)

Ooooh, thanks!

Reviewed-by: Max Reitz <mreitz@redhat.com>


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

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

* Re: [Qemu-devel] [PATCH v2 28/36] sheepdog: Support .bdrv_co_create
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 28/36] sheepdog: Support .bdrv_co_create Kevin Wolf
@ 2018-02-22 23:51   ` Max Reitz
  0 siblings, 0 replies; 77+ messages in thread
From: Max Reitz @ 2018-02-22 23:51 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

On 2018-02-21 14:53, Kevin Wolf wrote:
> This adds the .bdrv_co_create driver callback to sheepdog, which enables
> image creation over QMP.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  qapi/block-core.json |  24 +++++-
>  block/sheepdog.c     | 240 +++++++++++++++++++++++++++++++++++----------------
>  2 files changed, 189 insertions(+), 75 deletions(-)

[...]

> diff --git a/block/sheepdog.c b/block/sheepdog.c
> index 22df2ba9d0..d45cf68ff2 100644
> --- a/block/sheepdog.c
> +++ b/block/sheepdog.c

[...]

> @@ -1882,6 +1866,42 @@ out_with_err_set:
>      return ret;
>  }
>  
> +static int sd_create_prealloc(BlockdevOptionsSheepdog *location, int64_t size,
> +                              Error **errp)
> +{
> +    BlockDriverState *bs;
> +    Visitor *v;
> +    QObject *obj = NULL;
> +    QDict *qdict;
> +    Error *local_err = NULL;
> +    int ret;
> +
> +    v = qobject_output_visitor_new(&obj);
> +    visit_type_BlockdevOptionsSheepdog(v, NULL, &location, &local_err);
> +    visit_free(v);
> +
> +    if (local_err) {
> +        error_propagate(errp, local_err);
> +        qobject_decref(obj);
> +        return -EINVAL;
> +    }
> +
> +    qdict = qobject_to_qdict(obj);
> +    qdict_flatten(qdict);
> +
> +    bs = bdrv_open(NULL, NULL, qdict, BDRV_O_PROTOCOL | BDRV_O_RDWR, errp);

Hu, nice, we can even get rid of the filename again.

But I am wondering where "driver": "sheepdog" comes into qdict...

Max

> +    if (bs == NULL) {
> +        ret = -EIO;
> +        goto fail;
> +    }
> +
> +    ret = sd_prealloc(bs, 0, size, errp);
> +fail:
> +    bdrv_unref(bs);
> +    QDECREF(qdict);
> +    return ret;
> +}
> +
>  static int parse_redundancy(BDRVSheepdogState *s, SheepdogRedundancy *opt)
>  {
>      struct SheepdogInode *inode = &s->inode;


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

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

* Re: [Qemu-devel] [PATCH v2 16/36] file-win32: Support .bdrv_co_create
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 16/36] file-win32: " Kevin Wolf
@ 2018-02-23 14:46   ` Eric Blake
  0 siblings, 0 replies; 77+ messages in thread
From: Eric Blake @ 2018-02-23 14:46 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: mreitz, pkrempa, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

On 02/21/2018 07:53 AM, Kevin Wolf wrote:
> This adds the .bdrv_co_create driver callback to file-win32, which
> enables image creation over QMP.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> Reviewed-by: Max Reitz <mreitz@redhat.com>
> ---
>   block/file-win32.c | 45 +++++++++++++++++++++++++++++++++++++--------
>   1 file changed, 37 insertions(+), 8 deletions(-)
> 

> +
> +    options = (BlockdevCreateOptions) {
> +        .driver     = BLOCKDEV_DRIVER_FILE,
> +        .u.file     = {
> +            .filename           = (char *) filename,
> +            .size               = total_size,
> +            .has_preallocation  = false,
> +            .has_nocow          = false,

Technically, these last two lines aren't needed (you get false by 
default), but it doesn't hurt to list them either.

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

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

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

* Re: [Qemu-devel] [PATCH v2 17/36] gluster: Support .bdrv_co_create
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 17/36] gluster: " Kevin Wolf
  2018-02-22 23:01   ` Max Reitz
@ 2018-02-23 15:10   ` Eric Blake
  1 sibling, 0 replies; 77+ messages in thread
From: Eric Blake @ 2018-02-23 15:10 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: mreitz, pkrempa, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

On 02/21/2018 07:53 AM, Kevin Wolf wrote:
> This adds the .bdrv_co_create driver callback to gluster, which enables
> image creation over QMP.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   qapi/block-core.json |  18 ++++++-
>   block/gluster.c      | 135 ++++++++++++++++++++++++++++++++++-----------------
>   2 files changed, 108 insertions(+), 45 deletions(-)
> 

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

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

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

* Re: [Qemu-devel] [PATCH v2 18/36] rbd: Fix use after free in qemu_rbd_set_keypairs() error path
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 18/36] rbd: Fix use after free in qemu_rbd_set_keypairs() error path Kevin Wolf
  2018-02-22 23:02   ` Max Reitz
@ 2018-02-23 15:15   ` Eric Blake
  2018-02-23 15:56     ` Kevin Wolf
  1 sibling, 1 reply; 77+ messages in thread
From: Eric Blake @ 2018-02-23 15:15 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: mreitz, pkrempa, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

On 02/21/2018 07:53 AM, Kevin Wolf wrote:
> If we want to include the invalid option name in the error message, we
> can't free the string earlier than that.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block/rbd.c | 3 ++-
>   1 file changed, 2 insertions(+), 1 deletion(-)

D'oh.  Should this one be cc'd to qemu-stable?

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

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

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

* Re: [Qemu-devel] [PATCH v2 19/36] rbd: Factor out qemu_rbd_connect()
  2018-02-22 23:10   ` Max Reitz
@ 2018-02-23 15:19     ` Kevin Wolf
  0 siblings, 0 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-23 15:19 UTC (permalink / raw)
  To: Max Reitz
  Cc: qemu-block, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

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

Am 23.02.2018 um 00:10 hat Max Reitz geschrieben:
> On 2018-02-21 14:53, Kevin Wolf wrote:
> > The code to establish an RBD connection is duplicated between open and
> > create. In order to be able to share the code, factor out the code from
> > qemu_rbd_open() as a first step.
> > 
> > Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> > ---
> >  block/rbd.c | 100 ++++++++++++++++++++++++++++++++++++------------------------
> >  1 file changed, 60 insertions(+), 40 deletions(-)
> > 
> > diff --git a/block/rbd.c b/block/rbd.c
> > index 27fa11b473..4bbcce4eca 100644
> > --- a/block/rbd.c
> > +++ b/block/rbd.c
> > @@ -544,32 +544,17 @@ out:
> >      return rados_str;
> >  }
> >  
> > -static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
> > -                         Error **errp)
> > +static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
> > +                            char **s_snap, char **s_image_name,
> > +                            QDict *options, bool cache, Error **errp)
> 
> Bikeshedding ahead:  Maybe this should be called qemu_rados_connect()?
> I don't know anything about this, but there seems to be a distinction
> between rados_* functions and rbd_* functions -- the former work on the
> pool, the latter on the single block device.
> 
> Since this function only connects to the pool and not to a single device
> within, I think it should be called qemu_rados_connect() instead of
> qemu_rbd_connect().
> 
> (Also because qemu_rbd_connect() seems so similar to qemu_rbd_open().)

I think librados is the lower level interface, and librbd builds a
higher level interface on top of it. But I don't know anything about the
details either.

However, for functions in the block driver, qemu_rbd_* is the only
prefix used, there is no qemu_rados_* function. So I assume the prefix
comes from the block driver name 'rbd' rather than which library it
accesses, and that it would be better to keep qemu_rbd_connect().

> Up to you:
> 
> Reviewed-by: Max Reitz <mreitz@redhat.com>

Thanks.

Kevin

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [Qemu-devel] [PATCH v2 33/36] file-posix: Fix no-op bdrv_truncate() with falloc preallocation
  2018-02-21 13:54 ` [Qemu-devel] [PATCH v2 33/36] file-posix: Fix no-op bdrv_truncate() with falloc preallocation Kevin Wolf
@ 2018-02-23 15:21   ` Eric Blake
  0 siblings, 0 replies; 77+ messages in thread
From: Eric Blake @ 2018-02-23 15:21 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: mreitz, pkrempa, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

On 02/21/2018 07:54 AM, Kevin Wolf wrote:
> If bdrv_truncate() is called, but the requested size is the same as
> before, don't call posix_fallocate(), which returns -EINVAL for length
> zero and would therefore make bdrv_truncate() fail.
> 
> The problem can be triggered by creating a zero-sized raw image with
> 'falloc' preallocation mode.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> Reviewed-by: Max Reitz <mreitz@redhat.com>
> ---
>   block/file-posix.c | 14 +++++++++-----
>   1 file changed, 9 insertions(+), 5 deletions(-)
> 

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

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

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

* Re: [Qemu-devel] [PATCH v2 27/36] sheepdog: QAPIfy "redundacy" create option
  2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 27/36] sheepdog: QAPIfy "redundacy" create option Kevin Wolf
  2018-02-22 23:43   ` Max Reitz
@ 2018-02-23 15:25   ` Kevin Wolf
  1 sibling, 0 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-23 15:25 UTC (permalink / raw)
  To: qemu-block
  Cc: mreitz, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

Am 21.02.2018 um 14:53 hat Kevin Wolf geschrieben:
> The "redundacy" option for Sheepdog image creation is currently a string
> that can encode one or two integers depending on its format, which at
> the same time implicitly selects a mode.
> 
> This patch turns it into a QAPI union and converts the string into such
> a QAPI object before interpreting the values.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>

s/redundacy/redundancy/

Both in the subject line and the commit message. Autocompletion is
great, it helps to apply typos consistently.

Kevin

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

* Re: [Qemu-devel] [PATCH v2 18/36] rbd: Fix use after free in qemu_rbd_set_keypairs() error path
  2018-02-23 15:15   ` Eric Blake
@ 2018-02-23 15:56     ` Kevin Wolf
  0 siblings, 0 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-23 15:56 UTC (permalink / raw)
  To: Eric Blake
  Cc: qemu-block, mreitz, pkrempa, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel, qemu-stable

Am 23.02.2018 um 16:15 hat Eric Blake geschrieben:
> On 02/21/2018 07:53 AM, Kevin Wolf wrote:
> > If we want to include the invalid option name in the error message, we
> > can't free the string earlier than that.
> > 
> > Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> > ---
> >   block/rbd.c | 3 ++-
> >   1 file changed, 2 insertions(+), 1 deletion(-)
> 
> D'oh.  Should this one be cc'd to qemu-stable?

Yes, good point. Adding the CC to this reply, and also adding a Cc: line
in the commit message.

Kevin

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

* Re: [Qemu-devel] [PATCH v2 21/36] rbd: Pass BlockdevOptionsRbd to qemu_rbd_connect()
  2018-02-22 23:25   ` Max Reitz
@ 2018-02-23 16:19     ` Kevin Wolf
  2018-02-23 16:43       ` Max Reitz
  0 siblings, 1 reply; 77+ messages in thread
From: Kevin Wolf @ 2018-02-23 16:19 UTC (permalink / raw)
  To: Max Reitz
  Cc: qemu-block, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

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

Am 23.02.2018 um 00:25 hat Max Reitz geschrieben:
> On 2018-02-21 14:53, Kevin Wolf wrote:
> > With the conversion to a QAPI options object, the function is now
> > prepared to be used in a .bdrv_co_create implementation.
> > 
> > Signed-off-by: Kevin Wolf <kwolf@redhat.com>

> > -    *s_snap = g_strdup(snap);
> > -    *s_image_name = g_strdup(image_name);
> > +    *s_snap = g_strdup(opts->snapshot);
> > +    *s_image_name = g_strdup(opts->image);
> >  
> >      /* try default location when conf=NULL, but ignore failure */
> > -    r = rados_conf_read_file(*cluster, conf);
> > -    if (conf && r < 0) {
> > -        error_setg_errno(errp, -r, "error reading conf file %s", conf);
> > +    r = rados_conf_read_file(*cluster, opts->conf);
> > +    if (opts->has_conf && r < 0) {
> 
> Reading opts->conf without knowing whether opts->has_conf is true is a
> bit weird.  Would you mind "s->has_conf ? opts->conf : NULL" for the
> rados_conf_read() call?
> 
> On that thought, opts->snapshot and opts->user are optional, too.  Are
> they guaranteed to be NULL if they haven't been specified?  Should we
> guard those accesses with opts->has_* queries, too?

These days, both the QMP marshalling code (for the outermost struct when
called from x-blockdev-create) and the input visitor (for nested structs
and non-QMP callers) initialise the objects with {0} and g_malloc0().

I think Markus once told me that I shouldn't do pointless has_* checks
any more in QMP commands, so I intentionally did the same here.

Kevin

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [Qemu-devel] [PATCH v2 21/36] rbd: Pass BlockdevOptionsRbd to qemu_rbd_connect()
  2018-02-23 16:19     ` Kevin Wolf
@ 2018-02-23 16:43       ` Max Reitz
  2018-02-23 17:09         ` Kevin Wolf
  0 siblings, 1 reply; 77+ messages in thread
From: Max Reitz @ 2018-02-23 16:43 UTC (permalink / raw)
  To: Kevin Wolf
  Cc: qemu-block, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

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

On 2018-02-23 17:19, Kevin Wolf wrote:
> Am 23.02.2018 um 00:25 hat Max Reitz geschrieben:
>> On 2018-02-21 14:53, Kevin Wolf wrote:
>>> With the conversion to a QAPI options object, the function is now
>>> prepared to be used in a .bdrv_co_create implementation.
>>>
>>> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> 
>>> -    *s_snap = g_strdup(snap);
>>> -    *s_image_name = g_strdup(image_name);
>>> +    *s_snap = g_strdup(opts->snapshot);
>>> +    *s_image_name = g_strdup(opts->image);
>>>  
>>>      /* try default location when conf=NULL, but ignore failure */
>>> -    r = rados_conf_read_file(*cluster, conf);
>>> -    if (conf && r < 0) {
>>> -        error_setg_errno(errp, -r, "error reading conf file %s", conf);
>>> +    r = rados_conf_read_file(*cluster, opts->conf);
>>> +    if (opts->has_conf && r < 0) {
>>
>> Reading opts->conf without knowing whether opts->has_conf is true is a
>> bit weird.  Would you mind "s->has_conf ? opts->conf : NULL" for the
>> rados_conf_read() call?
>>
>> On that thought, opts->snapshot and opts->user are optional, too.  Are
>> they guaranteed to be NULL if they haven't been specified?  Should we
>> guard those accesses with opts->has_* queries, too?
> 
> These days, both the QMP marshalling code (for the outermost struct when
> called from x-blockdev-create) and the input visitor (for nested structs
> and non-QMP callers) initialise the objects with {0} and g_malloc0().
> 
> I think Markus once told me that I shouldn't do pointless has_* checks
> any more in QMP commands, so I intentionally did the same here.

I'm a bit cautious because of non-zero defaults (like sslverify in the
ssh driver), but as long as you're aware...

Max


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

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

* Re: [Qemu-devel] [PATCH v2 21/36] rbd: Pass BlockdevOptionsRbd to qemu_rbd_connect()
  2018-02-23 16:43       ` Max Reitz
@ 2018-02-23 17:09         ` Kevin Wolf
  0 siblings, 0 replies; 77+ messages in thread
From: Kevin Wolf @ 2018-02-23 17:09 UTC (permalink / raw)
  To: Max Reitz
  Cc: qemu-block, pkrempa, eblake, jcody, jdurgin, mitake.hitoshi,
	namei.unix, qemu-devel

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

Am 23.02.2018 um 17:43 hat Max Reitz geschrieben:
> On 2018-02-23 17:19, Kevin Wolf wrote:
> > Am 23.02.2018 um 00:25 hat Max Reitz geschrieben:
> >> On 2018-02-21 14:53, Kevin Wolf wrote:
> >>> With the conversion to a QAPI options object, the function is now
> >>> prepared to be used in a .bdrv_co_create implementation.
> >>>
> >>> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> > 
> >>> -    *s_snap = g_strdup(snap);
> >>> -    *s_image_name = g_strdup(image_name);
> >>> +    *s_snap = g_strdup(opts->snapshot);
> >>> +    *s_image_name = g_strdup(opts->image);
> >>>  
> >>>      /* try default location when conf=NULL, but ignore failure */
> >>> -    r = rados_conf_read_file(*cluster, conf);
> >>> -    if (conf && r < 0) {
> >>> -        error_setg_errno(errp, -r, "error reading conf file %s", conf);
> >>> +    r = rados_conf_read_file(*cluster, opts->conf);
> >>> +    if (opts->has_conf && r < 0) {
> >>
> >> Reading opts->conf without knowing whether opts->has_conf is true is a
> >> bit weird.  Would you mind "s->has_conf ? opts->conf : NULL" for the
> >> rados_conf_read() call?
> >>
> >> On that thought, opts->snapshot and opts->user are optional, too.  Are
> >> they guaranteed to be NULL if they haven't been specified?  Should we
> >> guard those accesses with opts->has_* queries, too?
> > 
> > These days, both the QMP marshalling code (for the outermost struct when
> > called from x-blockdev-create) and the input visitor (for nested structs
> > and non-QMP callers) initialise the objects with {0} and g_malloc0().
> > 
> > I think Markus once told me that I shouldn't do pointless has_* checks
> > any more in QMP commands, so I intentionally did the same here.
> 
> I'm a bit cautious because of non-zero defaults (like sslverify in the
> ssh driver), but as long as you're aware...

I still hope that QAPI will allow specifying default values in the
schema sometime. But yes, for the time being, not checking has_*
obviously only works when the default is 0/false/NULL.

Kevin

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [Qemu-devel] [PATCH v2 32/36] ssh: Support .bdrv_co_create
  2018-02-21 13:54 ` [Qemu-devel] [PATCH v2 32/36] ssh: Support .bdrv_co_create Kevin Wolf
@ 2018-02-26 12:40   ` Max Reitz
  2018-02-26 12:40     ` Max Reitz
  0 siblings, 1 reply; 77+ messages in thread
From: Max Reitz @ 2018-02-26 12:40 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

On 2018-02-21 14:54, Kevin Wolf wrote:
> This adds the .bdrv_co_create driver callback to ssh, which enables
> image creation over QMP.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> Reviewed-by: Max Reitz <mreitz@redhat.com>
> ---
>  qapi/block-core.json | 16 ++++++++-
>  block/ssh.c          | 92 +++++++++++++++++++++++++++++-----------------------
>  2 files changed, 67 insertions(+), 41 deletions(-)

This needs a rebase on my ssh truncation patches (notably "block/ssh:
Pull ssh_grow_file() from ssh_create()") -- good thing for me you need
to rebase, because without those patches you cannot create qcow2 files
over ssh. O:-)

Max


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

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

* Re: [Qemu-devel] [PATCH v2 32/36] ssh: Support .bdrv_co_create
  2018-02-26 12:40   ` Max Reitz
@ 2018-02-26 12:40     ` Max Reitz
  0 siblings, 0 replies; 77+ messages in thread
From: Max Reitz @ 2018-02-26 12:40 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

On 2018-02-26 13:40, Max Reitz wrote:
> On 2018-02-21 14:54, Kevin Wolf wrote:
>> This adds the .bdrv_co_create driver callback to ssh, which enables
>> image creation over QMP.
>>
>> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
>> Reviewed-by: Max Reitz <mreitz@redhat.com>
>> ---
>>  qapi/block-core.json | 16 ++++++++-
>>  block/ssh.c          | 92 +++++++++++++++++++++++++++++-----------------------
>>  2 files changed, 67 insertions(+), 41 deletions(-)
> 
> This needs a rebase on my ssh truncation patches (notably "block/ssh:
> Pull ssh_grow_file() from ssh_create()") -- good thing for me you need
> to rebase, because without those patches you cannot create qcow2 files
> over ssh. O:-)

Oops, meant to reply to v3...

Max


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

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

* Re: [Qemu-devel] [PATCH v2 36/36] qemu-iotests: Test ssh image creation over QMP
  2018-02-21 13:54 ` [Qemu-devel] [PATCH v2 36/36] qemu-iotests: Test ssh image creation over QMP Kevin Wolf
@ 2018-02-26 12:53   ` Max Reitz
  0 siblings, 0 replies; 77+ messages in thread
From: Max Reitz @ 2018-02-26 12:53 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block
  Cc: pkrempa, eblake, jcody, jdurgin, mitake.hitoshi, namei.unix, qemu-devel

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

On 2018-02-21 14:54, Kevin Wolf wrote:
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> Reviewed-by: Max Reitz <mreitz@redhat.com>
> ---
>  tests/qemu-iotests/207     | 261 +++++++++++++++++++++++++++++++++++++++++++++
>  tests/qemu-iotests/207.out |  75 +++++++++++++
>  tests/qemu-iotests/group   |   1 +
>  3 files changed, 337 insertions(+)
>  create mode 100755 tests/qemu-iotests/207
>  create mode 100644 tests/qemu-iotests/207.out

Minor note: If this test tried to create a qcow2 image over ssh, it
would have seen "Image format driver does not support resize" without
the ssh truncation patches.

But I'm not sure whether such a test case should be added here, because
technically this test then becomes a qcow2+ssh test, and nobody is ever
going to run the iotests with the qcow2+ssh combination.

(We could cheat and still mark this test as raw and then just create a
qcow2 image nonetheless...)

Max


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

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

end of thread, other threads:[~2018-02-26 12:53 UTC | newest]

Thread overview: 77+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-21 13:53 [Qemu-devel] [PATCH v2 00/36] x-blockdev-create for protocols and qcow2 Kevin Wolf
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 01/36] block/qapi: Introduce BlockdevCreateOptions Kevin Wolf
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 02/36] block/qapi: Add qcow2 create options to schema Kevin Wolf
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 03/36] qcow2: Let qcow2_create() handle protocol layer Kevin Wolf
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 04/36] qcow2: Pass BlockdevCreateOptions to qcow2_create2() Kevin Wolf
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 05/36] qcow2: Use BlockdevRef in qcow2_create2() Kevin Wolf
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 06/36] qcow2: Use QCryptoBlockCreateOptions " Kevin Wolf
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 07/36] qcow2: Handle full/falloc preallocation " Kevin Wolf
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 08/36] util: Add qemu_opts_to_qdict_filtered() Kevin Wolf
2018-02-21 20:38   ` Eric Blake
2018-02-22 22:03   ` Max Reitz
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 09/36] test-qemu-opts: Test qemu_opts_append() Kevin Wolf
2018-02-21 20:53   ` Eric Blake
2018-02-22 22:19   ` Max Reitz
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 10/36] test-qemu-opts: Test qemu_opts_to_qdict_filtered() Kevin Wolf
2018-02-21 20:57   ` Eric Blake
2018-02-22  9:50     ` Kevin Wolf
2018-02-22 14:24       ` Eric Blake
2018-02-22 22:26   ` Max Reitz
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 11/36] qdict: Introduce qdict_rename_keys() Kevin Wolf
2018-02-22 22:40   ` Max Reitz
2018-02-22 23:13   ` Eric Blake
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 12/36] qcow2: Use visitor for options in qcow2_create() Kevin Wolf
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 13/36] block: Make bdrv_is_whitelisted() public Kevin Wolf
2018-02-22 22:45   ` Max Reitz
2018-02-22 23:17   ` Eric Blake
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 14/36] block: x-blockdev-create QMP command Kevin Wolf
2018-02-22 22:50   ` Max Reitz
2018-02-22 23:19   ` Eric Blake
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 15/36] file-posix: Support .bdrv_co_create Kevin Wolf
2018-02-22 23:34   ` Eric Blake
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 16/36] file-win32: " Kevin Wolf
2018-02-23 14:46   ` Eric Blake
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 17/36] gluster: " Kevin Wolf
2018-02-22 23:01   ` Max Reitz
2018-02-23 15:10   ` Eric Blake
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 18/36] rbd: Fix use after free in qemu_rbd_set_keypairs() error path Kevin Wolf
2018-02-22 23:02   ` Max Reitz
2018-02-23 15:15   ` Eric Blake
2018-02-23 15:56     ` Kevin Wolf
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 19/36] rbd: Factor out qemu_rbd_connect() Kevin Wolf
2018-02-22 23:10   ` Max Reitz
2018-02-23 15:19     ` Kevin Wolf
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 20/36] rbd: Remove non-schema options from runtime_opts Kevin Wolf
2018-02-22 23:13   ` Max Reitz
2018-02-22 23:16     ` Max Reitz
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 21/36] rbd: Pass BlockdevOptionsRbd to qemu_rbd_connect() Kevin Wolf
2018-02-22 23:25   ` Max Reitz
2018-02-23 16:19     ` Kevin Wolf
2018-02-23 16:43       ` Max Reitz
2018-02-23 17:09         ` Kevin Wolf
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 22/36] rbd: Support .bdrv_co_create Kevin Wolf
2018-02-22 23:30   ` Max Reitz
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 23/36] rbd: Assing s->snap/image_name in qemu_rbd_open() Kevin Wolf
2018-02-22 23:34   ` [Qemu-devel] [PATCH v2 23/36] rbd: ***ing " Max Reitz
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 24/36] rbd: Use qemu_rbd_connect() in qemu_rbd_do_create() Kevin Wolf
2018-02-22 23:37   ` Max Reitz
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 25/36] nfs: Use QAPI options in nfs_client_open() Kevin Wolf
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 26/36] nfs: Support .bdrv_co_create Kevin Wolf
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 27/36] sheepdog: QAPIfy "redundacy" create option Kevin Wolf
2018-02-22 23:43   ` Max Reitz
2018-02-23 15:25   ` Kevin Wolf
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 28/36] sheepdog: Support .bdrv_co_create Kevin Wolf
2018-02-22 23:51   ` Max Reitz
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 29/36] ssh: Use QAPI BlockdevOptionsSsh object Kevin Wolf
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 30/36] ssh: QAPIfy host-key-check option Kevin Wolf
2018-02-21 13:53 ` [Qemu-devel] [PATCH v2 31/36] ssh: Pass BlockdevOptionsSsh to connect_to_ssh() Kevin Wolf
2018-02-21 13:54 ` [Qemu-devel] [PATCH v2 32/36] ssh: Support .bdrv_co_create Kevin Wolf
2018-02-26 12:40   ` Max Reitz
2018-02-26 12:40     ` Max Reitz
2018-02-21 13:54 ` [Qemu-devel] [PATCH v2 33/36] file-posix: Fix no-op bdrv_truncate() with falloc preallocation Kevin Wolf
2018-02-23 15:21   ` Eric Blake
2018-02-21 13:54 ` [Qemu-devel] [PATCH v2 34/36] block: Fail bdrv_truncate() with negative size Kevin Wolf
2018-02-22 23:35   ` Eric Blake
2018-02-21 13:54 ` [Qemu-devel] [PATCH v2 35/36] qemu-iotests: Test qcow2 over file image creation with QMP Kevin Wolf
2018-02-21 13:54 ` [Qemu-devel] [PATCH v2 36/36] qemu-iotests: Test ssh image creation over QMP Kevin Wolf
2018-02-26 12:53   ` 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.