Re: [Qemu-block] [PATCH 4/4] block/rbd: Add blockdev-add support

2017-02-26 Thread Jeff Cody
On Mon, Feb 27, 2017 at 02:30:41AM -0500, Jeff Cody wrote:
> Signed-off-by: Jeff Cody 
> ---
>  qapi/block-core.json | 47 ---
>  1 file changed, 44 insertions(+), 3 deletions(-)
> 
> diff --git a/qapi/block-core.json b/qapi/block-core.json
> index 5f82d35..08a1419 100644
> --- a/qapi/block-core.json
> +++ b/qapi/block-core.json
> @@ -2111,6 +2111,7 @@
>  # @replication: Since 2.8
>  # @ssh: Since 2.8
>  # @iscsi: Since 2.9
> +# @rbd: Since 2.9
>  #
>  # Since: 2.0
>  ##
> @@ -2120,7 +2121,7 @@
>  'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
>  'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
>  'quorum', 'raw', 'replication', 'ssh', 'vdi', 'vhdx', 'vmdk',
> -'vpc', 'vvfat' ] }
> +'vpc', 'vvfat', 'rbd' ] }
>  
>  ##
>  # @BlockdevOptionsFile:
> @@ -2376,7 +2377,6 @@
>  'path': 'str',
>  '*user': 'str' } }
>  
> -
>  ##
>  # @BlkdebugEvent:
>  #
> @@ -2666,6 +2666,47 @@
>  '*timeout': 'int' } }
>  
>  ##
> +# @BlockdevOptionsRbd:
> +#
> +# @pool:   Ceph pool name
> +#
> +# @image:  Image name in the Ceph pool
> +#
> +# @conf:   # optional path to Ceph configuration file.  Values
> +#  in the configuration file will be overridden by
> +#  options specified via QAPI.
> +#
> +# @snapshot:   #optional Ceph snapshot name
> +#
> +# @rbd-id: #optional Ceph id name
> +#
> +# @password-secret:#optional The ID of a QCryptoSecret object providing
> +#   the password for the login.
> +#
> +# @keyvalue-pairs: #optional  string containing key/value pairs for
> +#  additional Ceph configuration, not including "id" or 
> "conf"
> +#  options. This can be used to specify any of the 
> options
> +#  that Ceph supports.  The format is of the form:
> +#   key1=value1:key2=value2:[...]
> +#
> +#  Special characters such as ":" and "=" can be escaped
> +#  with a '\' character, which means the QAPI needs an
> +#  extra '\' character to pass the needed escape 
> character.
> +#  For example:
> +#"keyvalue-pairs": "mon_host=127.0.0.1\\:6321"
> +#

This is the key / value pair issue mentioned in the cover letter.  Encoding
all the options as a string like this is ugly.  What is the preference on
how to handle these via QAPI, when the actual key and value pairs could be
anything?   Talking with Markus on IRC, one option he mentioned was an array
of a generic struct of 'key' and 'value' pairs.

Do the libvirt folks have any interface preferences here?


> +# Since: 2.9
> +##
> +{ 'struct': 'BlockdevOptionsRbd',
> +  'data': { 'pool': 'str',
> +'image': 'str',
> +'*conf': 'str',
> +'*snapshot': 'str',
> +'*rbd-id': 'str',
> +'*password-secret': 'str',
> +'*keyvalue-pairs': 'str' } }
> +
> +##
>  # @ReplicationMode:
>  #
>  # An enumeration of replication modes.
> @@ -2863,7 +2904,7 @@
>'qed':'BlockdevOptionsGenericCOWFormat',
>'quorum': 'BlockdevOptionsQuorum',
>'raw':'BlockdevOptionsRaw',
> -# TODO rbd: Wait for structured options
> +  'rbd':'BlockdevOptionsRbd',
>'replication':'BlockdevOptionsReplication',
>  # TODO sheepdog: Wait for structured options
>'ssh':'BlockdevOptionsSsh',
> -- 
> 2.9.3
> 



[Qemu-block] [PATCH 2/4] block/rbd: code movement

2017-02-26 Thread Jeff Cody
Signed-off-by: Jeff Cody 
---
 block/rbd.c | 64 +++--
 1 file changed, 45 insertions(+), 19 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index 3f1a9de..c8d4eb1 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -357,6 +357,51 @@ static void qemu_rbd_memset(RADOSCB *rcb, int64_t offs)
 }
 }
 
+static QemuOptsList runtime_opts = {
+.name = "rbd",
+.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
+.desc = {
+{
+.name = "filename",
+.type = QEMU_OPT_STRING,
+.help = "Specification of the rbd image",
+},
+{
+.name = "password-secret",
+.type = QEMU_OPT_STRING,
+.help = "ID of secret providing the password",
+},
+{
+.name = "conf",
+.type = QEMU_OPT_STRING,
+},
+{
+.name = "pool",
+.type = QEMU_OPT_STRING,
+},
+{
+.name = "image",
+.type = QEMU_OPT_STRING,
+},
+{
+.name = "snapshot",
+.type = QEMU_OPT_STRING,
+},
+{
+/* you might be tempted to call this 'id' to match
+ * the ceph documentation, but then it'll get gobbled
+ * up in the block layer before it gets to the image driver */
+.name = "rbd-id",
+.type = QEMU_OPT_STRING,
+},
+{
+.name = "keyvalue-pairs",
+.type = QEMU_OPT_STRING,
+},
+{ /* end of list */ }
+},
+};
+
 static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
 {
 Error *local_err = NULL;
@@ -500,25 +545,6 @@ static void qemu_rbd_complete_aio(RADOSCB *rcb)
 qemu_aio_unref(acb);
 }
 
-/* TODO Convert to fine grained options */
-static QemuOptsList runtime_opts = {
-.name = "rbd",
-.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
-.desc = {
-{
-.name = "filename",
-.type = QEMU_OPT_STRING,
-.help = "Specification of the rbd image",
-},
-{
-.name = "password-secret",
-.type = QEMU_OPT_STRING,
-.help = "ID of secret providing the password",
-},
-{ /* end of list */ }
-},
-};
-
 static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
  Error **errp)
 {
-- 
2.9.3




[Qemu-block] [PATCH 3/4] block/rbd: parse all options via bdrv_parse_filename

2017-02-26 Thread Jeff Cody
Get rid of qemu_rbd_parsename in favor of bdrv_parse_filename.
This simplifies a lot of the parsing as well, as we can treat everything
a bit simpler since nonexistent options are simply NULL pointers instead
of empy strings.

An important item to note:

Ceph has many extra option values that can be specified as key/value
pairs.  This was handled previously in the driver by extracting the
values that the QEMU driver cared about, and then blindly passing all
extra options to rbd after splitting them into key/value pairs, and
cleaning up any special character escaping.

The practice is continued in this patch; there is an option
"keyvalue-pairs" that is populated with all the key/value pairs that the
QEMU driver does not care about.  These key/value pairs will override
any settings in the 'conf' configuration file, just as they did before.

Signed-off-by: Jeff Cody 
---
 block/rbd.c | 296 ++--
 1 file changed, 148 insertions(+), 148 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index c8d4eb1..2eee502 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -18,6 +18,7 @@
 #include "block/block_int.h"
 #include "crypto/secret.h"
 #include "qemu/cutils.h"
+#include "qapi/qmp/qstring.h"
 
 #include 
 
@@ -151,113 +152,129 @@ static void qemu_rbd_unescape(char *src)
 *p = '\0';
 }
 
-static int qemu_rbd_parsename(const char *filename,
-  char *pool, int pool_len,
-  char *snap, int snap_len,
-  char *name, int name_len,
-  char *conf, int conf_len,
-  Error **errp)
+static void qemu_rbd_parse_filename(const char *filename, QDict *options,
+Error **errp)
 {
 const char *start;
-char *p, *buf;
-int ret = 0;
+char *p, *buf, *keypairs;
 char *found_str;
+size_t max_keypair_size;
 Error *local_err = NULL;
 
 if (!strstart(filename, "rbd:", )) {
 error_setg(errp, "File name must start with 'rbd:'");
-return -EINVAL;
+return;
 }
 
+max_keypair_size = strlen(start) + 1;
 buf = g_strdup(start);
+keypairs = g_malloc0(max_keypair_size);
 p = buf;
-*snap = '\0';
-*conf = '\0';
 
-found_str = qemu_rbd_next_tok(pool_len, p,
+found_str = qemu_rbd_next_tok(RBD_MAX_POOL_NAME_SIZE, p,
  '/', "pool name", , _err);
 if (local_err) {
 goto done;
 }
 if (!p) {
-ret = -EINVAL;
 error_setg(errp, "Pool name is required");
 goto done;
 }
 qemu_rbd_unescape(found_str);
-g_strlcpy(pool, found_str, pool_len);
+qdict_put(options, "pool", qstring_from_str(found_str));
 
 if (strchr(p, '@')) {
-found_str = qemu_rbd_next_tok(name_len, p,
+found_str = qemu_rbd_next_tok(RBD_MAX_IMAGE_NAME_SIZE, p,
  '@', "object name", , _err);
 if (local_err) {
 goto done;
 }
 qemu_rbd_unescape(found_str);
-g_strlcpy(name, found_str, name_len);
+qdict_put(options, "image", qstring_from_str(found_str));
 
-found_str = qemu_rbd_next_tok(snap_len, p,
+found_str = qemu_rbd_next_tok(RBD_MAX_SNAP_NAME_SIZE, p,
   ':', "snap name", , _err);
 if (local_err) {
 goto done;
 }
 qemu_rbd_unescape(found_str);
-g_strlcpy(snap, found_str, snap_len);
+qdict_put(options, "snapshot", qstring_from_str(found_str));
 } else {
-found_str = qemu_rbd_next_tok(name_len, p,
+found_str = qemu_rbd_next_tok(RBD_MAX_IMAGE_NAME_SIZE, p,
  ':', "object name", , _err);
 if (local_err) {
 goto done;
 }
 qemu_rbd_unescape(found_str);
-g_strlcpy(name, found_str, name_len);
+qdict_put(options, "image", qstring_from_str(found_str));
 }
 if (!p) {
 goto done;
 }
 
-found_str = qemu_rbd_next_tok(conf_len, p,
+found_str = qemu_rbd_next_tok(RBD_MAX_CONF_NAME_SIZE, p,
  '\0', "configuration", , _err);
 if (local_err) {
 goto done;
 }
-g_strlcpy(conf, found_str, conf_len);
+
+p = found_str;
+
+/* The following are essentially all key/value pairs, and we treat
+ * 'id' and 'conf' a bit special.  Key/value pairs may be in any order. */
+while (p) {
+char *name, *value;
+name = qemu_rbd_next_tok(RBD_MAX_CONF_NAME_SIZE, p,
+ '=', "conf option name", , _err);
+if (local_err) {
+break;
+}
+
+if (!p) {
+error_setg(errp, "conf option %s has no value", name);
+break;
+}
+
+qemu_rbd_unescape(name);
+
+value = qemu_rbd_next_tok(RBD_MAX_CONF_VAL_SIZE, 

[Qemu-block] [PATCH 1/4] block/rbd: don't copy strings in qemu_rbd_next_tok()

2017-02-26 Thread Jeff Cody
This patch is prep work for parsing options for .bdrv_parse_filename,
and using QDict options.

The function qemu_rbd_next_tok() searched for various key/value pairs,
and copied them into buffers.  This will soon be an unnecessary extra
step, so we will now return found strings by reference only, and
offload the responsibility for safely handling/coping these strings to
the caller.

This also cleans up error handling some, as the callers now rely on
the Error object to determine if there is a parse error.

Signed-off-by: Jeff Cody 
---
 block/rbd.c | 99 +++--
 1 file changed, 64 insertions(+), 35 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index 22e8e69..3f1a9de 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -102,10 +102,10 @@ typedef struct BDRVRBDState {
 char *snap;
 } BDRVRBDState;
 
-static int qemu_rbd_next_tok(char *dst, int dst_len,
- char *src, char delim,
- const char *name,
- char **p, Error **errp)
+static char *qemu_rbd_next_tok(int max_len,
+   char *src, char delim,
+   const char *name,
+   char **p, Error **errp)
 {
 int l;
 char *end;
@@ -127,17 +127,15 @@ static int qemu_rbd_next_tok(char *dst, int dst_len,
 }
 }
 l = strlen(src);
-if (l >= dst_len) {
+if (l >= max_len) {
 error_setg(errp, "%s too long", name);
-return -EINVAL;
+return NULL;
 } else if (l == 0) {
 error_setg(errp, "%s too short", name);
-return -EINVAL;
+return NULL;
 }
 
-pstrcpy(dst, dst_len, src);
-
-return 0;
+return src;
 }
 
 static void qemu_rbd_unescape(char *src)
@@ -162,7 +160,9 @@ static int qemu_rbd_parsename(const char *filename,
 {
 const char *start;
 char *p, *buf;
-int ret;
+int ret = 0;
+char *found_str;
+Error *local_err = NULL;
 
 if (!strstart(filename, "rbd:", )) {
 error_setg(errp, "File name must start with 'rbd:'");
@@ -174,36 +174,60 @@ static int qemu_rbd_parsename(const char *filename,
 *snap = '\0';
 *conf = '\0';
 
-ret = qemu_rbd_next_tok(pool, pool_len, p,
-'/', "pool name", , errp);
-if (ret < 0 || !p) {
+found_str = qemu_rbd_next_tok(pool_len, p,
+ '/', "pool name", , _err);
+if (local_err) {
+goto done;
+}
+if (!p) {
 ret = -EINVAL;
+error_setg(errp, "Pool name is required");
 goto done;
 }
-qemu_rbd_unescape(pool);
+qemu_rbd_unescape(found_str);
+g_strlcpy(pool, found_str, pool_len);
 
 if (strchr(p, '@')) {
-ret = qemu_rbd_next_tok(name, name_len, p,
-'@', "object name", , errp);
-if (ret < 0) {
+found_str = qemu_rbd_next_tok(name_len, p,
+ '@', "object name", , _err);
+if (local_err) {
 goto done;
 }
-ret = qemu_rbd_next_tok(snap, snap_len, p,
-':', "snap name", , errp);
-qemu_rbd_unescape(snap);
+qemu_rbd_unescape(found_str);
+g_strlcpy(name, found_str, name_len);
+
+found_str = qemu_rbd_next_tok(snap_len, p,
+  ':', "snap name", , _err);
+if (local_err) {
+goto done;
+}
+qemu_rbd_unescape(found_str);
+g_strlcpy(snap, found_str, snap_len);
 } else {
-ret = qemu_rbd_next_tok(name, name_len, p,
-':', "object name", , errp);
+found_str = qemu_rbd_next_tok(name_len, p,
+ ':', "object name", , _err);
+if (local_err) {
+goto done;
+}
+qemu_rbd_unescape(found_str);
+g_strlcpy(name, found_str, name_len);
 }
-qemu_rbd_unescape(name);
-if (ret < 0 || !p) {
+if (!p) {
 goto done;
 }
 
-ret = qemu_rbd_next_tok(conf, conf_len, p,
-'\0', "configuration", , errp);
+found_str = qemu_rbd_next_tok(conf_len, p,
+ '\0', "configuration", , _err);
+if (local_err) {
+goto done;
+}
+g_strlcpy(conf, found_str, conf_len);
 
 done:
+if (local_err) {
+ret = -EINVAL;
+error_propagate(errp, local_err);
+}
 g_free(buf);
 return ret;
 }
@@ -262,17 +286,18 @@ static int qemu_rbd_set_conf(rados_t cluster, const char 
*conf,
  Error **errp)
 {
 char *p, *buf;
-char name[RBD_MAX_CONF_NAME_SIZE];
-char value[RBD_MAX_CONF_VAL_SIZE];
+char *name;
+char *value;
+Error *local_err = NULL;
 int ret = 0;
 
 buf = g_strdup(conf);
 p = buf;
 
 while (p) {
-ret = qemu_rbd_next_tok(name, 

[Qemu-block] [PATCH 0/4] RBD: blockdev-add

2017-02-26 Thread Jeff Cody

This series adds blockdev-add for rbd.

However, there is an area that will likely need to change.  In the RBD
driver, all options for Ceph are supported, but the qemu driver is not
explicitly aware of all the options.

There are a few options that the QEMU driver cares about and handles, while
the other options are merely split out until their string key/value pairs
and passed along to Ceph.  In patches 3 and 4, this patch series does
the same practice, and parses all the extra options as a long string.

For QAPI, this is not acceptable - so I presume the best way to handle it
is with an array schema of structs.  I'll reply to the specific patches in
the problem areas, and see what the preference is from an API perspective
 to handle this.




Jeff Cody (4):
  block/rbd: don't copy strings in qemu_rbd_next_tok()
  block/rbd: code movement
  block/rbd: parse all options via bdrv_parse_filename
  block/rbd: Add blockdev-add support

 block/rbd.c  | 435 +--
 qapi/block-core.json |  47 +-
 2 files changed, 289 insertions(+), 193 deletions(-)

-- 
2.9.3




[Qemu-block] [PATCH 4/4] block/rbd: Add blockdev-add support

2017-02-26 Thread Jeff Cody
Signed-off-by: Jeff Cody 
---
 qapi/block-core.json | 47 ---
 1 file changed, 44 insertions(+), 3 deletions(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 5f82d35..08a1419 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -2111,6 +2111,7 @@
 # @replication: Since 2.8
 # @ssh: Since 2.8
 # @iscsi: Since 2.9
+# @rbd: Since 2.9
 #
 # Since: 2.0
 ##
@@ -2120,7 +2121,7 @@
 'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
 'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
 'quorum', 'raw', 'replication', 'ssh', 'vdi', 'vhdx', 'vmdk',
-'vpc', 'vvfat' ] }
+'vpc', 'vvfat', 'rbd' ] }
 
 ##
 # @BlockdevOptionsFile:
@@ -2376,7 +2377,6 @@
 'path': 'str',
 '*user': 'str' } }
 
-
 ##
 # @BlkdebugEvent:
 #
@@ -2666,6 +2666,47 @@
 '*timeout': 'int' } }
 
 ##
+# @BlockdevOptionsRbd:
+#
+# @pool:   Ceph pool name
+#
+# @image:  Image name in the Ceph pool
+#
+# @conf:   # optional path to Ceph configuration file.  Values
+#  in the configuration file will be overridden by
+#  options specified via QAPI.
+#
+# @snapshot:   #optional Ceph snapshot name
+#
+# @rbd-id: #optional Ceph id name
+#
+# @password-secret:#optional The ID of a QCryptoSecret object providing
+#   the password for the login.
+#
+# @keyvalue-pairs: #optional  string containing key/value pairs for
+#  additional Ceph configuration, not including "id" or 
"conf"
+#  options. This can be used to specify any of the options
+#  that Ceph supports.  The format is of the form:
+#   key1=value1:key2=value2:[...]
+#
+#  Special characters such as ":" and "=" can be escaped
+#  with a '\' character, which means the QAPI needs an
+#  extra '\' character to pass the needed escape character.
+#  For example:
+#"keyvalue-pairs": "mon_host=127.0.0.1\\:6321"
+#
+# Since: 2.9
+##
+{ 'struct': 'BlockdevOptionsRbd',
+  'data': { 'pool': 'str',
+'image': 'str',
+'*conf': 'str',
+'*snapshot': 'str',
+'*rbd-id': 'str',
+'*password-secret': 'str',
+'*keyvalue-pairs': 'str' } }
+
+##
 # @ReplicationMode:
 #
 # An enumeration of replication modes.
@@ -2863,7 +2904,7 @@
   'qed':'BlockdevOptionsGenericCOWFormat',
   'quorum': 'BlockdevOptionsQuorum',
   'raw':'BlockdevOptionsRaw',
-# TODO rbd: Wait for structured options
+  'rbd':'BlockdevOptionsRbd',
   'replication':'BlockdevOptionsReplication',
 # TODO sheepdog: Wait for structured options
   'ssh':'BlockdevOptionsSsh',
-- 
2.9.3




[Qemu-block] [PATCH] blk: Add discard=sparse mode

2017-02-26 Thread Samuel Thibault
By default, on discard requests, the posix block backend punches holes but
re-fallocates them to keep the allocated size intact. In some situations
it is however convenient, when using sparse disk images, to see disk image
sizes shrink on discard requests.

This commit adds a discard=sparse mode which does this, by disabling the
fallocate call.

Signed-off-by: Samuel Thibault 

diff --git a/block.c b/block.c
index b663204f3f..e9cd83210a 100644
--- a/block.c
+++ b/block.c
@@ -665,12 +665,14 @@ static void bdrv_join_options(BlockDriverState *bs, QDict 
*options,
  */
 int bdrv_parse_discard_flags(const char *mode, int *flags)
 {
-*flags &= ~BDRV_O_UNMAP;
+*flags &= ~(BDRV_O_UNMAP | BDRV_O_SPARSE);
 
 if (!strcmp(mode, "off") || !strcmp(mode, "ignore")) {
 /* do nothing */
 } else if (!strcmp(mode, "on") || !strcmp(mode, "unmap")) {
 *flags |= BDRV_O_UNMAP;
+} else if (!strcmp(mode, "sparse")) {
+*flags |= BDRV_O_UNMAP | BDRV_O_SPARSE;
 } else {
 return -1;
 }
diff --git a/block/file-posix.c b/block/file-posix.c
index 4de1abd023..f9efadc5be 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -1057,6 +1057,10 @@ static ssize_t handle_aiocb_write_zeroes(RawPosixAIOData 
*aiocb)
 BDRVRawState *s = aiocb->bs->opaque;
 #endif
 
+#if defined(CONFIG_FALLOCATE_PUNCH_HOLE) || defined(CONFIG_FALLOCATE)
+int open_flags = aiocb->bs->open_flags;
+#endif
+
 if (aiocb->aio_type & QEMU_AIO_BLKDEV) {
 return handle_aiocb_write_zeroes_block(aiocb);
 }
@@ -1079,7 +1083,7 @@ static ssize_t handle_aiocb_write_zeroes(RawPosixAIOData 
*aiocb)
 #endif
 
 #ifdef CONFIG_FALLOCATE_PUNCH_HOLE
-if (s->has_discard && s->has_fallocate) {
+if (s->has_discard && (s->has_fallocate || open_flags & BDRV_O_SPARSE)) {
 int ret = do_fallocate(s->fd,
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
aiocb->aio_offset, aiocb->aio_nbytes);
@@ -1098,7 +1102,8 @@ static ssize_t handle_aiocb_write_zeroes(RawPosixAIOData 
*aiocb)
 #endif
 
 #ifdef CONFIG_FALLOCATE
-if (s->has_fallocate && aiocb->aio_offset >= bdrv_getlength(aiocb->bs)) {
+if (s->has_fallocate && !(open_flags & BDRV_O_SPARSE)
+&& aiocb->aio_offset >= bdrv_getlength(aiocb->bs)) {
 int ret = do_fallocate(s->fd, 0, aiocb->aio_offset, aiocb->aio_nbytes);
 if (ret == 0 || ret != -ENOTSUP) {
 return ret;
diff --git a/include/block/block.h b/include/block/block.h
index bde5ebda18..103313bee0 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -97,6 +97,8 @@ typedef struct HDGeometry {
   select an appropriate protocol driver,
   ignoring the format layer */
 #define BDRV_O_NO_IO   0x1 /* don't initialize for I/O */
+#define BDRV_O_SPARSE  0x2 /* make guest UNMAP/TRIM operations make 
image
+  possibly sparse */
 
 #define BDRV_O_CACHE_MASK  (BDRV_O_NOCACHE | BDRV_O_NO_FLUSH)
 
diff --git a/qemu-nbd.texi b/qemu-nbd.texi
index 9a84e81eed..8df4f58ddc 100644
--- a/qemu-nbd.texi
+++ b/qemu-nbd.texi
@@ -63,8 +63,8 @@ and @samp{native} (Linux only).
 @item --discard=@var{discard}
 Control whether @dfn{discard} (also known as @dfn{trim} or @dfn{unmap})
 requests are ignored or passed to the filesystem.  @var{discard} is one of
-@samp{ignore} (or @samp{off}), @samp{unmap} (or @samp{on}).  The default is
-@samp{ignore}.
+@samp{ignore} (or @samp{off}), @samp{unmap} (or @samp{on}), or @samp{sparse}.
+The default is @samp{ignore}.
 @item --detect-zeroes=@var{detect-zeroes}
 Control the automatic conversion of plain zero writes by the OS to
 driver-specific optimized zero write commands.  @var{detect-zeroes} is one of
diff --git a/qemu-options.hx b/qemu-options.hx
index bf458f83c3..f5c7455fd1 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -539,7 +539,7 @@ DEF("drive", HAS_ARG, QEMU_OPTION_drive,
 "   [,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
 "   
[,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
 "   [,readonly=on|off][,copy-on-read=on|off]\n"
-"   [,discard=ignore|unmap][,detect-zeroes=on|off|unmap]\n"
+"   [,discard=ignore|unmap|sparse][,detect-zeroes=on|off|unmap]\n"
 "   [[,bps=b]|[[,bps_rd=r][,bps_wr=w]]]\n"
 "   [[,iops=i]|[[,iops_rd=r][,iops_wr=w]]]\n"
 "   [[,bps_max=bm]|[[,bps_rd_max=rm][,bps_wr_max=wm]]]\n"
@@ -582,7 +582,7 @@ These options have the same definition as they have in 
@option{-hdachs}.
 @item aio=@var{aio}
 @var{aio} is "threads", or "native" and selects between pthread based disk I/O 
and native Linux AIO.
 @item discard=@var{discard}
-@var{discard} is one of "ignore" (or "off") or "unmap" (or "on") and controls 
whether @dfn{discard} (also known as @dfn{trim} or @dfn{unmap}) requests are 
ignored or passed 

Re: [Qemu-block] [PULL 0/3] Block patches

2017-02-26 Thread Peter Maydell
On 24 February 2017 at 17:46, Jeff Cody  wrote:
> The following changes since commit fe8ee082db5038a05dbd8872e946049e9a9c550e:
>
>   Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2017-02-22' 
> into staging (2017-02-24 15:00:51 +)
>
> are available in the git repository at:
>
>   https://github.com/codyprime/qemu-kvm-jtc.git tags/block-pull-request
>
> for you to fetch changes up to 1d393bdeae22fde2cb83c1ea719675747c85c40e:
>
>   RBD: Add support readv,writev for rbd (2017-02-24 12:43:01 -0500)
>
> 
> Block patches for 2.9
> 

Applied, thanks.

-- PMM