diff mbox

[PATCHv3,3/6] block: add a knob to disable multiwrite_merge

Message ID 1414256153-10148-4-git-send-email-pl@kamp.de
State New
Headers show

Commit Message

Peter Lieven Oct. 25, 2014, 4:55 p.m. UTC
The block layer silently merges write requests since
commit 40b4f539. This patch adds a knob to disable
this feature as there has been some discussion lately
if multiwrite is a good idea at all and as it falsifies
benchmarks.

Signed-off-by: Peter Lieven <pl@kamp.de>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 block.c                   |    9 +++++++++
 block/qapi.c              |    1 +
 hmp.c                     |    4 ++++
 include/block/block_int.h |    1 +
 qapi/block-core.json      |   10 +++++++++-
 qemu-options.hx           |    1 +
 qmp-commands.hx           |    2 ++
 7 files changed, 27 insertions(+), 1 deletion(-)

Comments

Stefan Hajnoczi Oct. 28, 2014, 11:11 a.m. UTC | #1
On Sat, Oct 25, 2014 at 06:55:50PM +0200, Peter Lieven wrote:
> diff --git a/block.c b/block.c
> index f05ea0c..f3da5dd 100644
> --- a/block.c
> +++ b/block.c
> @@ -884,6 +884,10 @@ static QemuOptsList bdrv_runtime_opts = {
>              .name = "node-name",
>              .type = QEMU_OPT_STRING,
>              .help = "Node name of the block device node",
> +        },{
> +            .name = "write-merging",
> +            .type = QEMU_OPT_BOOL,
> +            .help = "enable write merging (default: true)",

QEMU_OPT_BOOL takes "on"/"off" instead of "true"/"false":
s/true/on/

> diff --git a/qapi/block-core.json b/qapi/block-core.json
> index 2095f9e..74d1960 100644
> --- a/qapi/block-core.json
> +++ b/qapi/block-core.json
> @@ -214,6 +214,8 @@
>  #
>  # @detect_zeroes: detect and optimize zero writes (Since 2.1)
>  #
> +# @write_merging: true if write merging is enabled (Since 2.2)
> +#
>  # @bps: total throughput limit in bytes per second is specified
>  #
>  # @bps_rd: read throughput limit in bytes per second is specified
> @@ -250,6 +252,7 @@
>              '*backing_file': 'str', 'backing_file_depth': 'int',
>              'encrypted': 'bool', 'encryption_key_missing': 'bool',
>              'detect_zeroes': 'BlockdevDetectZeroesOptions',
> +            'write_merging': 'bool',
>              'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
>              'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
>              'image': 'ImageInfo',
> @@ -1185,6 +1188,10 @@
>  #                 (default: false)
>  # @detect-zeroes: #optional detect and optimize zero writes (Since 2.1)
>  #                 (default: off)
> +# @write-merging: #optional enable the merging of write requests
> +#                 also known as multiwrite_merge (Since 2.2)
> +#                 (default: true, but this might change in the future
> +#                 depending on format/protocol/features used)
>  #
>  # Since: 1.7
>  ##
> @@ -1198,7 +1205,8 @@
>              '*rerror': 'BlockdevOnError',
>              '*werror': 'BlockdevOnError',
>              '*read-only': 'bool',
> -            '*detect-zeroes': 'BlockdevDetectZeroesOptions' } }
> +            '*detect-zeroes': 'BlockdevDetectZeroesOptions',
> +            '*write-merging': 'bool' } }
>  
>  ##
>  # @BlockdevOptionsFile
> diff --git a/qemu-options.hx b/qemu-options.hx
> index 22cf3b9..d2f756f 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -432,6 +432,7 @@ DEF("drive", HAS_ARG, QEMU_OPTION_drive,
>      "       [,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"
> +    "       [,write-merging=on|off]\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"
> diff --git a/qmp-commands.hx b/qmp-commands.hx
> index 1abd619..2c20207 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -2104,6 +2104,7 @@ Each json-object contain the following:
>           - "iops_size": I/O size when limiting by iops (json-int)
>           - "detect_zeroes": detect and optimize zero writing (json-string)
>               - Possible values: "off", "on", "unmap"
> +         - "write_merging": enable merging of write requests (json-bool)
>           - "image": the detail of the image, it is a json-object containing
>              the following:
>               - "filename": image file name (json-string)
> @@ -2181,6 +2182,7 @@ Example:
>                 "iops_wr_max": 0,
>                 "iops_size": 0,
>                 "detect_zeroes": "on",
> +               "write_merging": "true",
>                 "image":{
>                    "filename":"disks/test.qcow2",
>                    "format":"qcow2",

The big question is whether these user-visible interfaces make sense if
write merging will be moved from block.c into virtio-blk.c in the
future.  Once an interface has been added it cannot be removed.

I think write merging in block.c is fine since other emulated storage
controllers like virtio-scsi might also choose to use it.

But I want to raise the point for discussion in case others have strong
feelings.

Stefan
Peter Lieven Oct. 28, 2014, 11:26 a.m. UTC | #2
On 28.10.2014 12:11, Stefan Hajnoczi wrote:
> On Sat, Oct 25, 2014 at 06:55:50PM +0200, Peter Lieven wrote:
>> diff --git a/block.c b/block.c
>> index f05ea0c..f3da5dd 100644
>> --- a/block.c
>> +++ b/block.c
>> @@ -884,6 +884,10 @@ static QemuOptsList bdrv_runtime_opts = {
>>               .name = "node-name",
>>               .type = QEMU_OPT_STRING,
>>               .help = "Node name of the block device node",
>> +        },{
>> +            .name = "write-merging",
>> +            .type = QEMU_OPT_BOOL,
>> +            .help = "enable write merging (default: true)",
> QEMU_OPT_BOOL takes "on"/"off" instead of "true"/"false":
> s/true/on/
>
>> diff --git a/qapi/block-core.json b/qapi/block-core.json
>> index 2095f9e..74d1960 100644
>> --- a/qapi/block-core.json
>> +++ b/qapi/block-core.json
>> @@ -214,6 +214,8 @@
>>   #
>>   # @detect_zeroes: detect and optimize zero writes (Since 2.1)
>>   #
>> +# @write_merging: true if write merging is enabled (Since 2.2)
>> +#
>>   # @bps: total throughput limit in bytes per second is specified
>>   #
>>   # @bps_rd: read throughput limit in bytes per second is specified
>> @@ -250,6 +252,7 @@
>>               '*backing_file': 'str', 'backing_file_depth': 'int',
>>               'encrypted': 'bool', 'encryption_key_missing': 'bool',
>>               'detect_zeroes': 'BlockdevDetectZeroesOptions',
>> +            'write_merging': 'bool',
>>               'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
>>               'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
>>               'image': 'ImageInfo',
>> @@ -1185,6 +1188,10 @@
>>   #                 (default: false)
>>   # @detect-zeroes: #optional detect and optimize zero writes (Since 2.1)
>>   #                 (default: off)
>> +# @write-merging: #optional enable the merging of write requests
>> +#                 also known as multiwrite_merge (Since 2.2)
>> +#                 (default: true, but this might change in the future
>> +#                 depending on format/protocol/features used)
>>   #
>>   # Since: 1.7
>>   ##
>> @@ -1198,7 +1205,8 @@
>>               '*rerror': 'BlockdevOnError',
>>               '*werror': 'BlockdevOnError',
>>               '*read-only': 'bool',
>> -            '*detect-zeroes': 'BlockdevDetectZeroesOptions' } }
>> +            '*detect-zeroes': 'BlockdevDetectZeroesOptions',
>> +            '*write-merging': 'bool' } }
>>   
>>   ##
>>   # @BlockdevOptionsFile
>> diff --git a/qemu-options.hx b/qemu-options.hx
>> index 22cf3b9..d2f756f 100644
>> --- a/qemu-options.hx
>> +++ b/qemu-options.hx
>> @@ -432,6 +432,7 @@ DEF("drive", HAS_ARG, QEMU_OPTION_drive,
>>       "       [,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"
>> +    "       [,write-merging=on|off]\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"
>> diff --git a/qmp-commands.hx b/qmp-commands.hx
>> index 1abd619..2c20207 100644
>> --- a/qmp-commands.hx
>> +++ b/qmp-commands.hx
>> @@ -2104,6 +2104,7 @@ Each json-object contain the following:
>>            - "iops_size": I/O size when limiting by iops (json-int)
>>            - "detect_zeroes": detect and optimize zero writing (json-string)
>>                - Possible values: "off", "on", "unmap"
>> +         - "write_merging": enable merging of write requests (json-bool)
>>            - "image": the detail of the image, it is a json-object containing
>>               the following:
>>                - "filename": image file name (json-string)
>> @@ -2181,6 +2182,7 @@ Example:
>>                  "iops_wr_max": 0,
>>                  "iops_size": 0,
>>                  "detect_zeroes": "on",
>> +               "write_merging": "true",
>>                  "image":{
>>                     "filename":"disks/test.qcow2",
>>                     "format":"qcow2",
> The big question is whether these user-visible interfaces make sense if
> write merging will be moved from block.c into virtio-blk.c in the
> future.  Once an interface has been added it cannot be removed.
>
> I think write merging in block.c is fine since other emulated storage
> controllers like virtio-scsi might also choose to use it.
>
> But I want to raise the point for discussion in case others have strong
> feelings.

It would be interesting to hear from Kevin what was the point why having
the merging outside block.c was an issue for his coroutine optimizations.

Maybe if you have the time the other alpha patch I sent you see that moving it
into virtio-blk.c makes some sense.

The reason merging was added in the past was that virtio-blk chops requests.
Maybe virtio-scsi doesn't do that. I personally would feel better if qemu would
not merge requests at all. But for virtio-blk it seems to be a big benefit in
some cases also for reading.

Peter
Eric Blake Oct. 28, 2014, 3:22 p.m. UTC | #3
On 10/25/2014 10:55 AM, Peter Lieven wrote:
> The block layer silently merges write requests since
> commit 40b4f539. This patch adds a knob to disable
> this feature as there has been some discussion lately
> if multiwrite is a good idea at all and as it falsifies
> benchmarks.
> 
> Signed-off-by: Peter Lieven <pl@kamp.de>
> Reviewed-by: Max Reitz <mreitz@redhat.com>
> ---

> +# @write-merging: #optional enable the merging of write requests
> +#                 also known as multiwrite_merge (Since 2.2)
> +#                 (default: true, but this might change in the future
> +#                 depending on format/protocol/features used)
>  #
>  # Since: 1.7
>  ##
> @@ -1198,7 +1205,8 @@
>              '*rerror': 'BlockdevOnError',
>              '*werror': 'BlockdevOnError',
>              '*read-only': 'bool',
> -            '*detect-zeroes': 'BlockdevDetectZeroesOptions' } }
> +            '*detect-zeroes': 'BlockdevDetectZeroesOptions',
> +            '*write-merging': 'bool' } }

This says it is boolean...


> +++ b/qmp-commands.hx
> @@ -2104,6 +2104,7 @@ Each json-object contain the following:
>           - "iops_size": I/O size when limiting by iops (json-int)
>           - "detect_zeroes": detect and optimize zero writing (json-string)
>               - Possible values: "off", "on", "unmap"
> +         - "write_merging": enable merging of write requests (json-bool)
>           - "image": the detail of the image, it is a json-object containing
>              the following:
>               - "filename": image file name (json-string)
> @@ -2181,6 +2182,7 @@ Example:
>                 "iops_wr_max": 0,
>                 "iops_size": 0,
>                 "detect_zeroes": "on",
> +               "write_merging": "true",

...but this is not a JSON bool.  s/"true"/true/
Peter Lieven Oct. 31, 2014, 8:31 a.m. UTC | #4
Am 28.10.2014 um 12:11 schrieb Stefan Hajnoczi:
> On Sat, Oct 25, 2014 at 06:55:50PM +0200, Peter Lieven wrote:
>> diff --git a/block.c b/block.c
>> index f05ea0c..f3da5dd 100644
>> --- a/block.c
>> +++ b/block.c
>> @@ -884,6 +884,10 @@ static QemuOptsList bdrv_runtime_opts = {
>>              .name = "node-name",
>>              .type = QEMU_OPT_STRING,
>>              .help = "Node name of the block device node",
>> +        },{
>> +            .name = "write-merging",
>> +            .type = QEMU_OPT_BOOL,
>> +            .help = "enable write merging (default: true)",
> QEMU_OPT_BOOL takes "on"/"off" instead of "true"/"false":
> s/true/on/
>
>> diff --git a/qapi/block-core.json b/qapi/block-core.json
>> index 2095f9e..74d1960 100644
>> --- a/qapi/block-core.json
>> +++ b/qapi/block-core.json
>> @@ -214,6 +214,8 @@
>>  #
>>  # @detect_zeroes: detect and optimize zero writes (Since 2.1)
>>  #
>> +# @write_merging: true if write merging is enabled (Since 2.2)
>> +#
>>  # @bps: total throughput limit in bytes per second is specified
>>  #
>>  # @bps_rd: read throughput limit in bytes per second is specified
>> @@ -250,6 +252,7 @@
>>              '*backing_file': 'str', 'backing_file_depth': 'int',
>>              'encrypted': 'bool', 'encryption_key_missing': 'bool',
>>              'detect_zeroes': 'BlockdevDetectZeroesOptions',
>> +            'write_merging': 'bool',
>>              'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
>>              'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
>>              'image': 'ImageInfo',
>> @@ -1185,6 +1188,10 @@
>>  #                 (default: false)
>>  # @detect-zeroes: #optional detect and optimize zero writes (Since 2.1)
>>  #                 (default: off)
>> +# @write-merging: #optional enable the merging of write requests
>> +#                 also known as multiwrite_merge (Since 2.2)
>> +#                 (default: true, but this might change in the future
>> +#                 depending on format/protocol/features used)
>>  #
>>  # Since: 1.7
>>  ##
>> @@ -1198,7 +1205,8 @@
>>              '*rerror': 'BlockdevOnError',
>>              '*werror': 'BlockdevOnError',
>>              '*read-only': 'bool',
>> -            '*detect-zeroes': 'BlockdevDetectZeroesOptions' } }
>> +            '*detect-zeroes': 'BlockdevDetectZeroesOptions',
>> +            '*write-merging': 'bool' } }
>>  
>>  ##
>>  # @BlockdevOptionsFile
>> diff --git a/qemu-options.hx b/qemu-options.hx
>> index 22cf3b9..d2f756f 100644
>> --- a/qemu-options.hx
>> +++ b/qemu-options.hx
>> @@ -432,6 +432,7 @@ DEF("drive", HAS_ARG, QEMU_OPTION_drive,
>>      "       [,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"
>> +    "       [,write-merging=on|off]\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"
>> diff --git a/qmp-commands.hx b/qmp-commands.hx
>> index 1abd619..2c20207 100644
>> --- a/qmp-commands.hx
>> +++ b/qmp-commands.hx
>> @@ -2104,6 +2104,7 @@ Each json-object contain the following:
>>           - "iops_size": I/O size when limiting by iops (json-int)
>>           - "detect_zeroes": detect and optimize zero writing (json-string)
>>               - Possible values: "off", "on", "unmap"
>> +         - "write_merging": enable merging of write requests (json-bool)
>>           - "image": the detail of the image, it is a json-object containing
>>              the following:
>>               - "filename": image file name (json-string)
>> @@ -2181,6 +2182,7 @@ Example:
>>                 "iops_wr_max": 0,
>>                 "iops_size": 0,
>>                 "detect_zeroes": "on",
>> +               "write_merging": "true",
>>                 "image":{
>>                    "filename":"disks/test.qcow2",
>>                    "format":"qcow2",
> The big question is whether these user-visible interfaces make sense if
> write merging will be moved from block.c into virtio-blk.c in the
> future.  Once an interface has been added it cannot be removed.

Would you make it a feature of the virtio-blk-pci device then?

Peter

>
> I think write merging in block.c is fine since other emulated storage
> controllers like virtio-scsi might also choose to use it.
>
> But I want to raise the point for discussion in case others have strong
> feelings.
>
> Stefan
Stefan Hajnoczi Oct. 31, 2014, 10:59 a.m. UTC | #5
On Fri, Oct 31, 2014 at 09:31:53AM +0100, Peter Lieven wrote:
> Am 28.10.2014 um 12:11 schrieb Stefan Hajnoczi:
> > On Sat, Oct 25, 2014 at 06:55:50PM +0200, Peter Lieven wrote:
> > The big question is whether these user-visible interfaces make sense if
> > write merging will be moved from block.c into virtio-blk.c in the
> > future.  Once an interface has been added it cannot be removed.
> 
> Would you make it a feature of the virtio-blk-pci device then?

No, I myself feel that it is a generic feature and moving it into the
storage controller emulation code would be a step backwards.

Stefan
Peter Lieven Nov. 27, 2014, 9:32 a.m. UTC | #6
On 31.10.2014 11:59, Stefan Hajnoczi wrote:
> On Fri, Oct 31, 2014 at 09:31:53AM +0100, Peter Lieven wrote:
>> Am 28.10.2014 um 12:11 schrieb Stefan Hajnoczi:
>>> On Sat, Oct 25, 2014 at 06:55:50PM +0200, Peter Lieven wrote:
>>> The big question is whether these user-visible interfaces make sense if
>>> write merging will be moved from block.c into virtio-blk.c in the
>>> future.  Once an interface has been added it cannot be removed.
>> Would you make it a feature of the virtio-blk-pci device then?
> No, I myself feel that it is a generic feature and moving it into the
> storage controller emulation code would be a step backwards.

As noone else seems to have a strong opinion here I would go for
making bdrv_multiwrite a bdrv_multireq and adjust everything accordingly?

Ok?

Peter
diff mbox

Patch

diff --git a/block.c b/block.c
index f05ea0c..f3da5dd 100644
--- a/block.c
+++ b/block.c
@@ -884,6 +884,10 @@  static QemuOptsList bdrv_runtime_opts = {
             .name = "node-name",
             .type = QEMU_OPT_STRING,
             .help = "Node name of the block device node",
+        },{
+            .name = "write-merging",
+            .type = QEMU_OPT_BOOL,
+            .help = "enable write merging (default: true)",
         },
         { /* end of list */ }
     },
@@ -986,6 +990,7 @@  static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
     bs->opaque = g_malloc0(drv->instance_size);
 
     bs->enable_write_cache = !!(flags & BDRV_O_CACHE_WB);
+    bs->write_merging = qemu_opt_get_bool(opts, "write-merging", true);
 
     /* Open the image, either directly or using a protocol */
     if (drv->bdrv_file_open) {
@@ -4451,6 +4456,10 @@  static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs,
 {
     int i, outidx;
 
+    if (!bs->write_merging) {
+        return num_reqs;
+    }
+
     // Sort requests by start sector
     qsort(reqs, num_reqs, sizeof(*reqs), &multiwrite_req_compare);
 
diff --git a/block/qapi.c b/block/qapi.c
index 28ea4db..9136705 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -59,6 +59,7 @@  BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs)
 
     info->backing_file_depth = bdrv_get_backing_file_depth(bs);
     info->detect_zeroes = bs->detect_zeroes;
+    info->write_merging = bs->write_merging;
 
     if (bs->io_limits_enabled) {
         ThrottleConfig cfg;
diff --git a/hmp.c b/hmp.c
index 5741dfd..48b85dd 100644
--- a/hmp.c
+++ b/hmp.c
@@ -348,6 +348,10 @@  void hmp_info_block(Monitor *mon, const QDict *qdict)
                            BlockdevDetectZeroesOptions_lookup[info->value->inserted->detect_zeroes]);
         }
 
+        if (!info->value->inserted->write_merging) {
+            monitor_printf(mon, "    Write Merging:    off\n");
+        }
+
         if (info->value->inserted->bps
             || info->value->inserted->bps_rd
             || info->value->inserted->bps_wr
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 8898c6c..e3d382f 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -402,6 +402,7 @@  struct BlockDriverState {
 
     QDict *options;
     BlockdevDetectZeroesOptions detect_zeroes;
+    bool write_merging;
 
     /* The error object in use for blocking operations on backing_hd */
     Error *backing_blocker;
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 2095f9e..74d1960 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -214,6 +214,8 @@ 
 #
 # @detect_zeroes: detect and optimize zero writes (Since 2.1)
 #
+# @write_merging: true if write merging is enabled (Since 2.2)
+#
 # @bps: total throughput limit in bytes per second is specified
 #
 # @bps_rd: read throughput limit in bytes per second is specified
@@ -250,6 +252,7 @@ 
             '*backing_file': 'str', 'backing_file_depth': 'int',
             'encrypted': 'bool', 'encryption_key_missing': 'bool',
             'detect_zeroes': 'BlockdevDetectZeroesOptions',
+            'write_merging': 'bool',
             'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
             'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int',
             'image': 'ImageInfo',
@@ -1185,6 +1188,10 @@ 
 #                 (default: false)
 # @detect-zeroes: #optional detect and optimize zero writes (Since 2.1)
 #                 (default: off)
+# @write-merging: #optional enable the merging of write requests
+#                 also known as multiwrite_merge (Since 2.2)
+#                 (default: true, but this might change in the future
+#                 depending on format/protocol/features used)
 #
 # Since: 1.7
 ##
@@ -1198,7 +1205,8 @@ 
             '*rerror': 'BlockdevOnError',
             '*werror': 'BlockdevOnError',
             '*read-only': 'bool',
-            '*detect-zeroes': 'BlockdevDetectZeroesOptions' } }
+            '*detect-zeroes': 'BlockdevDetectZeroesOptions',
+            '*write-merging': 'bool' } }
 
 ##
 # @BlockdevOptionsFile
diff --git a/qemu-options.hx b/qemu-options.hx
index 22cf3b9..d2f756f 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -432,6 +432,7 @@  DEF("drive", HAS_ARG, QEMU_OPTION_drive,
     "       [,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"
+    "       [,write-merging=on|off]\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"
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 1abd619..2c20207 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2104,6 +2104,7 @@  Each json-object contain the following:
          - "iops_size": I/O size when limiting by iops (json-int)
          - "detect_zeroes": detect and optimize zero writing (json-string)
              - Possible values: "off", "on", "unmap"
+         - "write_merging": enable merging of write requests (json-bool)
          - "image": the detail of the image, it is a json-object containing
             the following:
              - "filename": image file name (json-string)
@@ -2181,6 +2182,7 @@  Example:
                "iops_wr_max": 0,
                "iops_size": 0,
                "detect_zeroes": "on",
+               "write_merging": "true",
                "image":{
                   "filename":"disks/test.qcow2",
                   "format":"qcow2",