All of lore.kernel.org
 help / color / mirror / Atom feed
* [PULL 00/18] Block layer patches
@ 2022-06-09 17:21 Kevin Wolf
  2022-06-09 20:18 ` Richard Henderson
  0 siblings, 1 reply; 29+ messages in thread
From: Kevin Wolf @ 2022-06-09 17:21 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel

The following changes since commit 028f2361d0c2d28d6f918fe618f389228ac22b60:

  Merge tag 'pull-target-arm-20220609' of https://git.linaro.org/people/pmaydell/qemu-arm into staging (2022-06-09 06:47:03 -0700)

are available in the Git repository at:

  git://repo.or.cz/qemu/kevin.git tags/for-upstream

for you to fetch changes up to 7f9a8b3342ff00d3398fdc08264948762d748edb:

  nbd: Drop dead code spotted by Coverity (2022-06-09 18:07:17 +0200)

----------------------------------------------------------------
Block layer patches

- Add vduse-blk export
- Dirty bitmaps: Fix and improve bitmap merge
- gluster: correctly set max_pdiscard
- rbd: report a better error when namespace does not exist
- aio_wait_kick: add missing memory barrier
- Code cleanups

----------------------------------------------------------------
Emanuele Giuseppe Esposito (1):
      aio_wait_kick: add missing memory barrier

Eric Blake (1):
      nbd: Drop dead code spotted by Coverity

Fabian Ebner (1):
      block/gluster: correctly set max_pdiscard

Stefan Hajnoczi (3):
      block: drop unused bdrv_co_drain() API
      block: get rid of blk->guest_block_size
      qsd: document vduse-blk exports

Stefano Garzarella (1):
      block/rbd: report a better error when namespace does not exist

Vladimir Sementsov-Ogievskiy (3):
      block: block_dirty_bitmap_merge(): fix error path
      block: improve block_dirty_bitmap_merge(): don't allocate extra bitmap
      block: simplify handling of try to merge different sized bitmaps

Xie Yongji (8):
      block: Support passing NULL ops to blk_set_dev_ops()
      block/export: Fix incorrect length passed to vu_queue_push()
      block/export: Abstract out the logic of virtio-blk I/O process
      linux-headers: Add vduse.h
      libvduse: Add VDUSE (vDPA Device in Userspace) library
      vduse-blk: Implement vduse-blk export
      vduse-blk: Add vduse-blk resize support
      libvduse: Add support for reconnecting

 qapi/block-export.json                      |   28 +-
 docs/tools/qemu-storage-daemon.rst          |   21 +
 meson_options.txt                           |    4 +
 block/export/vduse-blk.h                    |   20 +
 block/export/virtio-blk-handler.h           |   37 +
 include/block/aio-wait.h                    |    2 +
 include/block/block-io.h                    |    1 -
 include/block/block_int-io.h                |    2 +-
 include/qemu/hbitmap.h                      |   15 +-
 include/sysemu/block-backend-io.h           |    1 -
 linux-headers/linux/vduse.h                 |  306 ++++++
 subprojects/libvduse/include/atomic.h       |    1 +
 subprojects/libvduse/include/compiler.h     |    1 +
 subprojects/libvduse/libvduse.h             |  247 +++++
 block/backup.c                              |    6 +-
 block/block-backend.c                       |   12 +-
 block/dirty-bitmap.c                        |   26 +-
 block/export/export.c                       |    6 +
 block/export/vduse-blk.c                    |  341 +++++++
 block/export/vhost-user-blk-server.c        |  261 +----
 block/export/virtio-blk-handler.c           |  240 +++++
 block/gluster.c                             |    2 +-
 block/io.c                                  |   15 -
 block/monitor/bitmap-qmp-cmds.c             |   40 +-
 block/nbd.c                                 |    8 +-
 block/rbd.c                                 |   24 +
 hw/block/virtio-blk.c                       |    1 -
 hw/block/xen-block.c                        |    1 -
 hw/ide/core.c                               |    1 -
 hw/scsi/scsi-disk.c                         |    1 -
 hw/scsi/scsi-generic.c                      |    1 -
 storage-daemon/qemu-storage-daemon.c        |    9 +
 subprojects/libvduse/libvduse.c             | 1392 +++++++++++++++++++++++++++
 util/aio-wait.c                             |   16 +-
 util/hbitmap.c                              |   25 +-
 MAINTAINERS                                 |    9 +
 block/export/meson.build                    |    7 +-
 meson.build                                 |   34 +
 scripts/meson-buildoptions.sh               |    7 +
 scripts/update-linux-headers.sh             |    2 +-
 subprojects/libvduse/linux-headers/linux    |    1 +
 subprojects/libvduse/meson.build            |   10 +
 subprojects/libvduse/standard-headers/linux |    1 +
 43 files changed, 2830 insertions(+), 355 deletions(-)
 create mode 100644 block/export/vduse-blk.h
 create mode 100644 block/export/virtio-blk-handler.h
 create mode 100644 linux-headers/linux/vduse.h
 create mode 120000 subprojects/libvduse/include/atomic.h
 create mode 120000 subprojects/libvduse/include/compiler.h
 create mode 100644 subprojects/libvduse/libvduse.h
 create mode 100644 block/export/vduse-blk.c
 create mode 100644 block/export/virtio-blk-handler.c
 create mode 100644 subprojects/libvduse/libvduse.c
 create mode 120000 subprojects/libvduse/linux-headers/linux
 create mode 100644 subprojects/libvduse/meson.build
 create mode 120000 subprojects/libvduse/standard-headers/linux



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

* Re: [PULL 00/18] Block layer patches
  2022-06-09 17:21 Kevin Wolf
@ 2022-06-09 20:18 ` Richard Henderson
  2022-06-13 17:04   ` Kevin Wolf
  0 siblings, 1 reply; 29+ messages in thread
From: Richard Henderson @ 2022-06-09 20:18 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: qemu-devel

On 6/9/22 10:21, Kevin Wolf wrote:
> The following changes since commit 028f2361d0c2d28d6f918fe618f389228ac22b60:
> 
>    Merge tag 'pull-target-arm-20220609' of https://git.linaro.org/people/pmaydell/qemu-arm into staging (2022-06-09 06:47:03 -0700)
> 
> are available in the Git repository at:
> 
>    git://repo.or.cz/qemu/kevin.git tags/for-upstream
> 
> for you to fetch changes up to 7f9a8b3342ff00d3398fdc08264948762d748edb:
> 
>    nbd: Drop dead code spotted by Coverity (2022-06-09 18:07:17 +0200)
> 
> ----------------------------------------------------------------
> Block layer patches
> 
> - Add vduse-blk export
> - Dirty bitmaps: Fix and improve bitmap merge
> - gluster: correctly set max_pdiscard
> - rbd: report a better error when namespace does not exist
> - aio_wait_kick: add missing memory barrier
> - Code cleanups

Several sets of compile failures:

https://gitlab.com/qemu-project/qemu/-/jobs/2571008901

../subprojects/libvduse/libvduse.c:578:20: error: unused function 
'vring_used_flags_set_bit' [-Werror,-Wunused-function]
static inline void vring_used_flags_set_bit(VduseVirtq *vq, int mask)
                    ^
../subprojects/libvduse/libvduse.c:587:20: error: unused function 
'vring_used_flags_unset_bit' [-Werror,-Wunused-function]
static inline void vring_used_flags_unset_bit(VduseVirtq *vq, int mask)
                    ^

https://gitlab.com/qemu-project/qemu/-/jobs/2571008908

../meson.build:1652:2: ERROR: Tried to use 'add_global_arguments' after a build target has 
been declared.

https://gitlab.com/qemu-project/qemu/-/jobs/2571008833

../subprojects/libvduse/libvduse.c:325:20: error: cast to pointer from integer of 
different size [-Werror=int-to-pointer-cast]
   325 |             munmap((void *)dev->regions[i].mmap_addr,
       |                    ^
../subprojects/libvduse/libvduse.c: In function 'vduse_dev_create':
../subprojects/libvduse/libvduse.c:1318:54: error: format '%lu' expects argument of type 
'long unsigned int', but argument 3 has type 'uint64_t' {aka 'long long unsigned int'} 
[-Werror=format=]
  1318 |         fprintf(stderr, "Failed to set api version %lu: %s\n",
       |                                                    ~~^
       |                                                      |
       |                                                      long unsigned int
       |                                                    %llu
  1319 |                 version, strerror(errno));
       |                 ~~~~~~~
       |                 |
       |                 uint64_t {aka long long unsigned int}


r~


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

* Re: [PULL 00/18] Block layer patches
  2022-06-09 20:18 ` Richard Henderson
@ 2022-06-13 17:04   ` Kevin Wolf
  0 siblings, 0 replies; 29+ messages in thread
From: Kevin Wolf @ 2022-06-13 17:04 UTC (permalink / raw)
  To: Richard Henderson; +Cc: qemu-block, qemu-devel, xieyongji

Am 09.06.2022 um 22:18 hat Richard Henderson geschrieben:
> On 6/9/22 10:21, Kevin Wolf wrote:
> > The following changes since commit 028f2361d0c2d28d6f918fe618f389228ac22b60:
> > 
> >    Merge tag 'pull-target-arm-20220609' of https://git.linaro.org/people/pmaydell/qemu-arm into staging (2022-06-09 06:47:03 -0700)
> > 
> > are available in the Git repository at:
> > 
> >    git://repo.or.cz/qemu/kevin.git tags/for-upstream
> > 
> > for you to fetch changes up to 7f9a8b3342ff00d3398fdc08264948762d748edb:
> > 
> >    nbd: Drop dead code spotted by Coverity (2022-06-09 18:07:17 +0200)
> > 
> > ----------------------------------------------------------------
> > Block layer patches
> > 
> > - Add vduse-blk export
> > - Dirty bitmaps: Fix and improve bitmap merge
> > - gluster: correctly set max_pdiscard
> > - rbd: report a better error when namespace does not exist
> > - aio_wait_kick: add missing memory barrier
> > - Code cleanups
> 
> Several sets of compile failures:

Hi Yongji,

the vduse-blk code fails to compile with clang as shown below. As you
already sent another series to fix up other bugs introduced in the
series, maybe it would be better if you can send a new version with all
of the necessary fixes squashed in instead of me trying to make minimal
fixes to get it to compile with clang.

Kevin

> https://gitlab.com/qemu-project/qemu/-/jobs/2571008901
> 
> ../subprojects/libvduse/libvduse.c:578:20: error: unused function
> 'vring_used_flags_set_bit' [-Werror,-Wunused-function]
> static inline void vring_used_flags_set_bit(VduseVirtq *vq, int mask)
>                    ^
> ../subprojects/libvduse/libvduse.c:587:20: error: unused function
> 'vring_used_flags_unset_bit' [-Werror,-Wunused-function]
> static inline void vring_used_flags_unset_bit(VduseVirtq *vq, int mask)
>                    ^
> 
> https://gitlab.com/qemu-project/qemu/-/jobs/2571008908
> 
> ../meson.build:1652:2: ERROR: Tried to use 'add_global_arguments' after a
> build target has been declared.
> 
> https://gitlab.com/qemu-project/qemu/-/jobs/2571008833
> 
> ../subprojects/libvduse/libvduse.c:325:20: error: cast to pointer from
> integer of different size [-Werror=int-to-pointer-cast]
>   325 |             munmap((void *)dev->regions[i].mmap_addr,
>       |                    ^
> ../subprojects/libvduse/libvduse.c: In function 'vduse_dev_create':
> ../subprojects/libvduse/libvduse.c:1318:54: error: format '%lu' expects
> argument of type 'long unsigned int', but argument 3 has type 'uint64_t'
> {aka 'long long unsigned int'} [-Werror=format=]
>  1318 |         fprintf(stderr, "Failed to set api version %lu: %s\n",
>       |                                                    ~~^
>       |                                                      |
>       |                                                      long unsigned int
>       |                                                    %llu
>  1319 |                 version, strerror(errno));
>       |                 ~~~~~~~
>       |                 |
>       |                 uint64_t {aka long long unsigned int}
> 
> 
> r~
> 



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

* [PULL 00/18] Block layer patches
@ 2022-09-30 16:52 Kevin Wolf
  2022-10-03 23:02 ` Stefan Hajnoczi
  0 siblings, 1 reply; 29+ messages in thread
From: Kevin Wolf @ 2022-09-30 16:52 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

The following changes since commit c8de6ec63d766ca1998c5af468483ce912fdc0c2:

  Merge tag 'pull-request-2022-09-28' of https://gitlab.com/thuth/qemu into staging (2022-09-28 17:04:11 -0400)

are available in the Git repository at:

  git://repo.or.cz/qemu/kevin.git tags/for-upstream

for you to fetch changes up to 176e4961bb33d559da1af441fb0ee2e0cb8245ae:

  hw/ide/core.c: Implement ATA INITIALIZE_DEVICE_PARAMETERS command (2022-09-30 18:43:44 +0200)

----------------------------------------------------------------
Block layer patches

- Fix missing block_acct_setup() with -blockdev
- Keep auto_backing_file post-migration
- file-posix: Fixed O_DIRECT memory alignment
- ide: Fix state after EXECUTE DEVICE DIAGNOSTIC and implement
  INITIALIZE DEVICE PARAMETERS
- qemu-img: Wean documentation and help output off '?' for help
- qcow2: fix memory leak and compiler warning
- Code cleanups

----------------------------------------------------------------
Denis V. Lunev (4):
      block: pass OnOffAuto instead of bool to block_acct_setup()
      block: add missed block_acct_setup with new block device init procedure
      block: use bdrv_is_sg() helper instead of raw bs->sg reading
      block: make serializing requests functions 'void'

Hanna Reitz (3):
      block/qcow2: Keep auto_backing_file if possible
      block/qed: Keep auto_backing_file if possible
      iotests/backing-file-invalidation: Add new test

Keith Busch (2):
      block: move bdrv_qiov_is_aligned to file-posix
      block: use the request length for iov alignment

Lev Kujawski (5):
      piix_ide_reset: Use pci_set_* functions instead of direct access
      tests/qtest/ide-test.c: Create disk image for use as a secondary
      hw/ide/core: Clear LBA and drive bits for EXECUTE DEVICE DIAGNOSTIC
      tests/qtest/ide-test: Verify that DIAGNOSTIC clears DEV to zero
      hw/ide/core.c: Implement ATA INITIALIZE_DEVICE_PARAMETERS command

Markus Armbruster (1):
      qemu-img: Wean documentation and help output off '?' for help

Philippe Mathieu-Daudé (1):
      block/qcow2-bitmap: Add missing cast to silent GCC error

Stefan Hajnoczi (1):
      gluster: stop using .bdrv_needs_filename

lu zhipeng (1):
      qcow2: fix memory leak in qcow2_read_extensions

 docs/tools/qemu-img.rst                            |   2 +-
 include/block/accounting.h                         |   6 +-
 include/block/block-io.h                           |   1 -
 include/block/block_int-io.h                       |   2 +-
 include/hw/block/block.h                           |   7 +-
 include/hw/ide/internal.h                          |   3 +
 block/accounting.c                                 |  26 +++-
 block/file-posix.c                                 |  24 +++-
 block/gluster.c                                    |   4 -
 block/io.c                                         |  44 +-----
 block/iscsi.c                                      |   2 +-
 block/qcow2-bitmap.c                               |   2 +-
 block/qcow2.c                                      |  22 ++-
 block/qed.c                                        |  15 +-
 block/raw-format.c                                 |   4 +-
 blockdev.c                                         |  17 ++-
 hw/block/block.c                                   |   2 +
 hw/ide/core.c                                      |  35 ++++-
 hw/ide/piix.c                                      |  17 +--
 qemu-img.c                                         |   4 +-
 tests/qtest/ide-test.c                             |  72 +++++++---
 tests/qemu-iotests/172.out                         |  76 +++++++++++
 tests/qemu-iotests/227.out                         |   4 +-
 tests/qemu-iotests/tests/backing-file-invalidation | 152 +++++++++++++++++++++
 .../tests/backing-file-invalidation.out            |   5 +
 25 files changed, 447 insertions(+), 101 deletions(-)
 create mode 100755 tests/qemu-iotests/tests/backing-file-invalidation
 create mode 100644 tests/qemu-iotests/tests/backing-file-invalidation.out



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

* Re: [PULL 00/18] Block layer patches
  2022-09-30 16:52 Kevin Wolf
@ 2022-10-03 23:02 ` Stefan Hajnoczi
  0 siblings, 0 replies; 29+ messages in thread
From: Stefan Hajnoczi @ 2022-10-03 23:02 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-block, kwolf, stefanha, qemu-devel

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

Applied, thanks.

Please update the changelog at https://wiki.qemu.org/ChangeLog/7.2 for any user-visible changes.

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

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

* [PULL 00/18] Block layer patches
@ 2023-05-17 16:50 Kevin Wolf
  0 siblings, 0 replies; 29+ messages in thread
From: Kevin Wolf @ 2023-05-17 16:50 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, richard.henderson, qemu-devel

The following changes since commit 6972ef1440a9d685482d78672620a7482f2bd09a:

  Merge tag 'pull-tcg-20230516-3' of https://gitlab.com/rth7680/qemu into staging (2023-05-16 21:30:27 -0700)

are available in the Git repository at:

  https://repo.or.cz/qemu/kevin.git tags/for-upstream

for you to fetch changes up to 75b2591bbce5dc9f3da89f140b7bdc00e92fa8ec:

  tested: add test for nested aio_poll() in poll handlers (2023-05-17 18:01:22 +0200)

----------------------------------------------------------------
Block layer patches

- qcow2 spec: Rename "zlib" compression to "deflate"
- Honour graph read lock even in the main thread + prerequisite fixes
- aio-posix: do not nest poll handlers (fixes infinite recursion)
- Refactor QMP blockdev transactions
- iotests/245: Check if 'compress' driver is available

----------------------------------------------------------------
Akihiro Suda (1):
      docs/interop/qcow2.txt: fix description about "zlib" clusters

Kevin Wolf (9):
      block: Call .bdrv_co_create(_opts) unlocked
      block/export: Fix null pointer dereference in error path
      qcow2: Unlock the graph in qcow2_do_open() where necessary
      qemu-img: Take graph lock more selectively
      test-bdrv-drain: Take graph lock more selectively
      test-bdrv-drain: Call bdrv_co_unref() in coroutine context
      blockjob: Adhere to rate limit even when reentered early
      graph-lock: Honour read locks even in the main thread
      iotests/245: Check if 'compress' driver is available

Stefan Hajnoczi (2):
      aio-posix: do not nest poll handlers
      tested: add test for nested aio_poll() in poll handlers

Vladimir Sementsov-Ogievskiy (6):
      blockdev: refactor transaction to use Transaction API
      blockdev: transactions: rename some things
      blockdev: qmp_transaction: refactor loop to classic for
      blockdev: transaction: refactor handling transaction properties
      blockdev: use state.bitmap in block-dirty-bitmap-add action
      blockdev: qmp_transaction: drop extra generic layer

 docs/interop/qcow2.txt             |  10 +-
 include/block/block-global-state.h |   8 +-
 include/block/block_int-common.h   |   4 +-
 include/block/blockjob_int.h       |  14 +-
 block.c                            |   1 -
 block/commit.c                     |   7 +-
 block/create.c                     |   1 -
 block/crypto.c                     |  25 +-
 block/export/export.c              |   6 +-
 block/graph-lock.c                 |  10 -
 block/mirror.c                     |  23 +-
 block/parallels.c                  |   6 +-
 block/qcow.c                       |   6 +-
 block/qcow2.c                      |  43 ++-
 block/qed.c                        |   6 +-
 block/raw-format.c                 |   2 +-
 block/stream.c                     |   7 +-
 block/vdi.c                        |  11 +-
 block/vhdx.c                       |   8 +-
 block/vmdk.c                       |  27 +-
 block/vpc.c                        |   6 +-
 blockdev.c                         | 606 +++++++++++++++----------------------
 blockjob.c                         |  22 +-
 qemu-img.c                         |   5 +-
 tests/unit/test-bdrv-drain.c       |   6 +-
 tests/unit/test-nested-aio-poll.c  | 130 ++++++++
 util/aio-posix.c                   |  11 +
 tests/qemu-iotests/245             |   7 +-
 tests/qemu-iotests/245.out         |   9 +-
 tests/unit/meson.build             |   1 +
 30 files changed, 541 insertions(+), 487 deletions(-)
 create mode 100644 tests/unit/test-nested-aio-poll.c



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

* [PULL 00/18] Block layer patches
@ 2025-10-29 12:06 Kevin Wolf
  2025-10-31  9:25 ` Richard Henderson
  0 siblings, 1 reply; 29+ messages in thread
From: Kevin Wolf @ 2025-10-29 12:06 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel

The following changes since commit bc831f37398b51dfe65d99a67bcff9352f84a9d2:

  Merge tag 'hw-misc-20251028' of https://github.com/philmd/qemu into staging (2025-10-28 11:48:05 +0100)

are available in the Git repository at:

  https://repo.or.cz/qemu/kevin.git tags/for-upstream

for you to fetch changes up to 911992fd6ec7a84c7cc82831b4bcd8a2ca5ccc76:

  qemu-img info: Add cache mode option (2025-10-29 12:10:10 +0100)

----------------------------------------------------------------
Block layer patches

- Expose block limits in monitor and qemu-img info
- Resize: Refresh filter node size when its child was resized
- Support configuring stats-intervals in -device (instead of only -drive)
- luks: Fix QMP x-blockdev-amend crash and image creation with detached-header
- iotests: Several test case fixes
- Code cleanups

----------------------------------------------------------------
Bin Guo (1):
      block/monitor: Use hmp_handle_error to report error

Chandan Somani (1):
      block: enable stats-intervals for storage devices

Daniel P. Berrangé (2):
      block: remove 'detached-header' option from opts after use
      block: fix luks 'amend' when run in coroutine

Eric Blake (2):
      iotests: Adjust nbd expected outputs to match current behavior
      iotests: Adjust fuse-allow-other expected output

Fiona Ebner (5):
      include/block/block_int-common: document when resize callback is used
      block: make bdrv_co_parent_cb_resize() a proper IO API function
      block: implement 'resize' callback for child_of_bds class
      iotests: add test for resizing a node below filters
      iotests: add test for resizing a 'file' node below a 'raw' node

Kevin Wolf (4):
      block: Improve comments in BlockLimits
      block: Expose block limits for images in QMP
      qemu-img info: Optionally show block limits
      qemu-img info: Add cache mode option

Peter Maydell (1):
      MAINTAINERS: Mark VHDX block driver as "Odd Fixes"

Richard W.M. Jones (1):
      block/curl.c: Fix CURLOPT_VERBOSE parameter type

Thomas Huth (1):
      tests/qemu-iotests: Mark the 'inactive-node-nbd' as unsupported with -luks

 qapi/block-core.json                             | 66 +++++++++++++++++++++
 docs/tools/qemu-img.rst                          |  6 +-
 include/block/accounting.h                       |  5 +-
 include/block/block_int-common.h                 | 35 +++++++-----
 include/block/block_int-io.h                     |  6 ++
 include/block/qapi.h                             |  2 +-
 include/hw/block/block.h                         |  7 ++-
 block.c                                          | 12 ++++
 block/accounting.c                               | 17 +++++-
 block/crypto.c                                   | 32 ++++++++---
 block/curl.c                                     |  2 +-
 block/io.c                                       |  9 +--
 block/monitor/block-hmp-cmds.c                   | 45 ++++++++-------
 block/qapi.c                                     | 66 +++++++++++++++++++--
 blockdev.c                                       |  3 +-
 hw/block/block.c                                 |  7 ++-
 qemu-img.c                                       | 40 ++++++++++---
 MAINTAINERS                                      |  2 +-
 qemu-img-cmds.hx                                 |  4 +-
 tests/qemu-iotests/094.out                       |  2 +-
 tests/qemu-iotests/119.out                       |  2 +-
 tests/qemu-iotests/172.out                       | 38 ++++++++++++
 tests/qemu-iotests/184                           |  5 +-
 tests/qemu-iotests/184.out                       |  8 ---
 tests/qemu-iotests/267.out                       |  8 +--
 tests/qemu-iotests/common.filter                 |  3 +-
 tests/qemu-iotests/tests/fuse-allow-other.out    |  6 +-
 tests/qemu-iotests/tests/inactive-node-nbd       |  1 +
 tests/qemu-iotests/tests/resize-below-filter     | 73 ++++++++++++++++++++++++
 tests/qemu-iotests/tests/resize-below-filter.out |  5 ++
 tests/qemu-iotests/tests/resize-below-raw        | 53 +++++++++++++++++
 tests/qemu-iotests/tests/resize-below-raw.out    |  5 ++
 32 files changed, 479 insertions(+), 96 deletions(-)
 create mode 100755 tests/qemu-iotests/tests/resize-below-filter
 create mode 100644 tests/qemu-iotests/tests/resize-below-filter.out
 create mode 100755 tests/qemu-iotests/tests/resize-below-raw
 create mode 100644 tests/qemu-iotests/tests/resize-below-raw.out



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

* Re: [PULL 00/18] Block layer patches
  2025-10-29 12:06 Kevin Wolf
@ 2025-10-31  9:25 ` Richard Henderson
  0 siblings, 0 replies; 29+ messages in thread
From: Richard Henderson @ 2025-10-31  9:25 UTC (permalink / raw)
  To: qemu-devel

On 10/29/25 13:06, Kevin Wolf wrote:
> The following changes since commit bc831f37398b51dfe65d99a67bcff9352f84a9d2:
> 
>    Merge tag 'hw-misc-20251028' ofhttps://github.com/philmd/qemu into staging (2025-10-28 11:48:05 +0100)
> 
> are available in the Git repository at:
> 
>    https://repo.or.cz/qemu/kevin.git tags/for-upstream
> 
> for you to fetch changes up to 911992fd6ec7a84c7cc82831b4bcd8a2ca5ccc76:
> 
>    qemu-img info: Add cache mode option (2025-10-29 12:10:10 +0100)
> 
> ----------------------------------------------------------------
> Block layer patches
> 
> - Expose block limits in monitor and qemu-img info
> - Resize: Refresh filter node size when its child was resized
> - Support configuring stats-intervals in -device (instead of only -drive)
> - luks: Fix QMP x-blockdev-amend crash and image creation with detached-header
> - iotests: Several test case fixes
> - Code cleanups

Applied, thanks.  Please update https://wiki.qemu.org/ChangeLog/10.2 as appropriate.

r~


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

* [PULL 00/18] Block layer patches
@ 2026-05-19 17:02 Kevin Wolf
  2026-05-19 17:03 ` [PULL 01/18] blkdebug: Add 'delay-ns' option Kevin Wolf
                   ` (18 more replies)
  0 siblings, 19 replies; 29+ messages in thread
From: Kevin Wolf @ 2026-05-19 17:02 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

The following changes since commit 6d17fd91f6cf88df5cb2205e578640d72605cc43:

  Merge tag 'pull-nvme-20260518' of https://gitlab.com/birkelund/qemu into staging (2026-05-18 08:33:20 -0400)

are available in the Git repository at:

  https://repo.or.cz/qemu/kevin.git tags/for-upstream

for you to fetch changes up to 8b663f7d0d96d915d0e0fc5923dc6cc36133f19f:

  block: Improve readability in HMP 'info blockstats' output (2026-05-19 17:34:13 +0200)

----------------------------------------------------------------
Block layer patches

- qcow2: Fix corruption on discard during write with COW
- Remove the deprecated glusterfs block driver
- graph-lock: fix missed wakeup in bdrv_graph_co_rdunlock()
- ide: Fix deadlock between TRIM and drain
- scsi: Fix discard_granularity for -drive if=scsi
- blkdebug: Add 'delay-ns' option
- qemu-io: Add 'aio_discard' command
- Improve readability in HMP 'info blockstats' output
- MAINTAINERS: Lukas Straub will maintain COLO block replication

----------------------------------------------------------------
Denis V. Lunev (1):
      block/graph-lock: fix missed wakeup in bdrv_graph_co_rdunlock()

Kevin Wolf (14):
      blkdebug: Add 'delay-ns' option
      block: Add blk_co_start/end_request() and BDRV_REQ_NO_QUEUE
      block: Add flags parameter to blk_*_pdiscard()
      ide: Minimal fix for deadlock between TRIM and drain
      ide: Clean up ide_trim_co_entry() to be idiomatic coroutine code
      ide-test: Factor out wait_dma_completion()
      ide-test: Test reset during TRIM
      block: Create DEFAULT_BLOCK_CONF macro
      block: Add more defaults to DEFAULT_BLOCK_CONF
      commit: Drain nodes across all of bdrv_commit()
      qemu-io: Add 'aio_discard' command
      qcow2: Fix corruption on discard during write with COW
      iotests/046: Test that discard/write_zeroes wait for dependencies
      block: Improve readability in HMP 'info blockstats' output

Lukas Straub (2):
      MAINTAINERS: Add myself as maintainer for replication
      MAINTAINERS: Rename Replication -> COLO block replication

Thomas Huth (1):
      Remove the deprecated glusterfs block driver

 qapi/block-core.json                               |   56 +-
 docs/about/deprecated.rst                          |    8 -
 docs/about/removed-features.rst                    |    7 +
 docs/system/device-url-syntax.rst.inc              |   39 -
 docs/system/qemu-block-drivers.rst.inc             |   84 -
 meson_options.txt                                  |    2 -
 include/block/block-common.h                       |   11 +-
 include/hw/block/block.h                           |   12 +
 include/system/block-backend-io.h                  |    6 +-
 block/blkdebug.c                                   |   15 +-
 block/block-backend.c                              |   47 +-
 block/commit.c                                     |   10 +-
 block/export/virtio-blk-handler.c                  |    2 +-
 block/gluster.c                                    | 1644 --------------------
 block/graph-lock.c                                 |   12 +-
 block/mirror.c                                     |    4 +-
 block/monitor/block-hmp-cmds.c                     |   38 +-
 block/qcow2-cluster.c                              |   52 +-
 hw/ide/core.c                                      |  110 +-
 hw/scsi/scsi-bus.c                                 |    7 +-
 nbd/server.c                                       |    2 +-
 qemu-io-cmds.c                                     |  117 +-
 tests/qtest/ide-test.c                             |  137 +-
 tests/qtest/modules-test.c                         |    3 -
 tests/unit/test-block-iothread.c                   |    4 +-
 MAINTAINERS                                        |   11 +-
 block/meson.build                                  |    1 -
 meson.build                                        |   47 -
 scripts/ci/setup/debian/debian-13-ppc64le.yaml     |    1 -
 scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml   |    1 -
 scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml     |    1 -
 scripts/coverity-scan/coverity-scan.docker         |    1 -
 scripts/coverity-scan/run-coverity-scan            |    2 +-
 scripts/meson-buildoptions.sh                      |    3 -
 tests/docker/dockerfiles/debian-amd64-cross.docker |    1 -
 tests/docker/dockerfiles/debian-arm64-cross.docker |    1 -
 .../dockerfiles/debian-mips64el-cross.docker       |    1 -
 .../docker/dockerfiles/debian-mipsel-cross.docker  |    1 -
 .../docker/dockerfiles/debian-ppc64el-cross.docker |    1 -
 .../docker/dockerfiles/debian-riscv64-cross.docker |    1 -
 tests/docker/dockerfiles/debian-s390x-cross.docker |    1 -
 tests/docker/dockerfiles/debian.docker             |    1 -
 .../docker/dockerfiles/fedora-rust-nightly.docker  |    1 -
 tests/docker/dockerfiles/fedora.docker             |    1 -
 tests/docker/dockerfiles/opensuse-leap.docker      |    1 -
 tests/docker/dockerfiles/ubuntu2204.docker         |    1 -
 tests/lcitool/projects/qemu.yml                    |    1 -
 tests/qemu-iotests/046                             |   46 +
 tests/qemu-iotests/046.out                         |   36 +
 49 files changed, 537 insertions(+), 2055 deletions(-)
 delete mode 100644 block/gluster.c



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

* [PULL 01/18] blkdebug: Add 'delay-ns' option
  2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
@ 2026-05-19 17:03 ` Kevin Wolf
  2026-05-19 17:03 ` [PULL 02/18] block: Add blk_co_start/end_request() and BDRV_REQ_NO_QUEUE Kevin Wolf
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Kevin Wolf @ 2026-05-19 17:03 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

Sometimes reproducing a problem for debugging involves slow I/O, so
let's add something to blkdebug to make I/O slow when we need it. This
can be used either together with an error so that the request fails
after the delay, or with errno=0, which allows the request to succeed
after the delay.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260421161132.99878-2-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 qapi/block-core.json |  4 ++++
 block/blkdebug.c     | 15 ++++++++++++++-
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 508b081ac16..0efd51787b4 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3919,6 +3919,9 @@
 #
 # @errno: error identifier (errno) to be returned; defaults to EIO
 #
+# @delay-ns: request delay before completion in nanoseconds
+#            (default: 0, since: 11.1)
+#
 # @sector: specifies the sector index which has to be affected in
 #     order to actually trigger the event; defaults to "any sector"
 #
@@ -3934,6 +3937,7 @@
             '*state': 'int',
             '*iotype': 'BlkdebugIOType',
             '*errno': 'int',
+            '*delay-ns': 'int',
             '*sector': 'int',
             '*once': 'bool',
             '*immediately': 'bool' } }
diff --git a/block/blkdebug.c b/block/blkdebug.c
index fdc96d1f45d..78cc03746f0 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -95,6 +95,7 @@ typedef struct BlkdebugRule {
             int immediately;
             int once;
             int64_t offset;
+            int64_t delay_ns;
         } inject;
         struct {
             int new_state;
@@ -144,6 +145,10 @@ static QemuOptsList inject_error_opts = {
             .name = "immediately",
             .type = QEMU_OPT_BOOL,
         },
+        {
+            .name = "delay-ns",
+            .type = QEMU_OPT_NUMBER,
+        },
         { /* end of list */ }
     },
 };
@@ -216,6 +221,8 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
         rule->options.inject.once  = qemu_opt_get_bool(opts, "once", 0);
         rule->options.inject.immediately =
             qemu_opt_get_bool(opts, "immediately", 0);
+        rule->options.inject.delay_ns =
+            qemu_opt_get_number(opts, "delay-ns", 0);
         sector = qemu_opt_get_number(opts, "sector", -1);
         rule->options.inject.offset =
             sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE;
@@ -594,6 +601,7 @@ static int coroutine_fn rule_check(BlockDriverState *bs, uint64_t offset,
     BlkdebugRule *rule;
     int error;
     bool immediately;
+    int64_t delay_ns;
 
     qemu_mutex_lock(&s->lock);
     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
@@ -608,13 +616,14 @@ static int coroutine_fn rule_check(BlockDriverState *bs, uint64_t offset,
         }
     }
 
-    if (!rule || !rule->options.inject.error) {
+    if (!rule) {
         qemu_mutex_unlock(&s->lock);
         return 0;
     }
 
     immediately = rule->options.inject.immediately;
     error = rule->options.inject.error;
+    delay_ns  = rule->options.inject.delay_ns;
 
     if (rule->options.inject.once) {
         QSIMPLEQ_REMOVE(&s->active_rules, rule, BlkdebugRule, active_next);
@@ -622,6 +631,10 @@ static int coroutine_fn rule_check(BlockDriverState *bs, uint64_t offset,
     }
 
     qemu_mutex_unlock(&s->lock);
+
+    if (delay_ns) {
+        qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, delay_ns);
+    }
     if (!immediately) {
         aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self());
         qemu_coroutine_yield();
-- 
2.54.0



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

* [PULL 02/18] block: Add blk_co_start/end_request() and BDRV_REQ_NO_QUEUE
  2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
  2026-05-19 17:03 ` [PULL 01/18] blkdebug: Add 'delay-ns' option Kevin Wolf
@ 2026-05-19 17:03 ` Kevin Wolf
  2026-05-19 17:03 ` [PULL 03/18] block: Add flags parameter to blk_*_pdiscard() Kevin Wolf
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Kevin Wolf @ 2026-05-19 17:03 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

If a device uses blk_inc/dec_in_flight() in order to build macro
operations that involve multiple requests for the block layer and that
need to be completed as a unit before the BlockBackend can be considered
drained, it sets the stage for a deadlock: When a drain is requested,
the inner request at the BlockBackend level will be queued in
blk_wait_while_drained() and wait until the drained section ends, but at
the same time, drain_begin can only return if the whole macro operation
at the device level has completed.

Introduce a new interface to allow implementing the logic correctly:
Instead of queueing individual requests, blk_co_start_request() calls
blk_wait_while_drained() once at the beginning. The individual requests
must then set BDRV_REQ_NO_QUEUE to avoid being queued and running into
the deadlock; being wrapped in blk_co_start/end_request() makes sure
that drain_begin waits for them and they don't sneak in when the
BlockBackend is supposed to already be quiescent.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260421161132.99878-3-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 include/block/block-common.h      | 11 ++++++++-
 include/system/block-backend-io.h |  2 ++
 block/block-backend.c             | 38 +++++++++++++++++++++++--------
 3 files changed, 41 insertions(+), 10 deletions(-)

diff --git a/include/block/block-common.h b/include/block/block-common.h
index c8c626daeaa..895ea175413 100644
--- a/include/block/block-common.h
+++ b/include/block/block-common.h
@@ -215,8 +215,17 @@ typedef enum {
      */
     BDRV_REQ_NO_WAIT = 0x400,
 
+    /*
+     * Used between blk_co_start_request() and blk_end_request() to avoid
+     * that the request waits in a drained BlockBackend until the drained
+     * section ends. Waiting would cause a deadlock because drain waits for
+     * blk_end_request() to be called, but the request never completes
+     * because it waits for the drain to end.
+     */
+    BDRV_REQ_NO_QUEUE = 0x800,
+
     /* Mask of valid flags */
-    BDRV_REQ_MASK               = 0x7ff,
+    BDRV_REQ_MASK               = 0xfff,
 } BdrvRequestFlags;
 
 #define BDRV_O_NO_SHARE    0x0001 /* don't share permissions */
diff --git a/include/system/block-backend-io.h b/include/system/block-backend-io.h
index 6d5ac476fc0..0248c1c36e2 100644
--- a/include/system/block-backend-io.h
+++ b/include/system/block-backend-io.h
@@ -71,6 +71,8 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
 
 void blk_inc_in_flight(BlockBackend *blk);
 void blk_dec_in_flight(BlockBackend *blk);
+void coroutine_fn blk_co_start_request(BlockBackend *blk);
+void blk_end_request(BlockBackend *blk);
 
 bool coroutine_fn GRAPH_RDLOCK blk_co_is_inserted(BlockBackend *blk);
 bool co_wrapper_mixed_bdrv_rdlock blk_is_inserted(BlockBackend *blk);
diff --git a/block/block-backend.c b/block/block-backend.c
index 99446571201..ee00440e28d 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -82,6 +82,7 @@ struct BlockBackend {
     QemuMutex queued_requests_lock; /* protects queued_requests */
     CoQueue queued_requests;
     bool disable_request_queuing; /* atomic */
+    int start_request_count; /* atomic */
 
     VMChangeStateEntry *vmsh;
     bool force_allow_inactivate;
@@ -1306,10 +1307,16 @@ bool blk_in_drain(BlockBackend *blk)
 }
 
 /* To be called between exactly one pair of blk_inc/dec_in_flight() */
-static void coroutine_fn blk_wait_while_drained(BlockBackend *blk)
+static void coroutine_fn blk_wait_while_drained(BlockBackend *blk,
+                                                BdrvRequestFlags flags)
 {
     assert(blk->in_flight > 0);
 
+    if (flags & BDRV_REQ_NO_QUEUE) {
+        assert(qatomic_read(&blk->start_request_count));
+        return;
+    }
+
     if (qatomic_read(&blk->quiesce_counter) &&
         !qatomic_read(&blk->disable_request_queuing)) {
         /*
@@ -1335,7 +1342,7 @@ blk_co_do_preadv_part(BlockBackend *blk, int64_t offset, int64_t bytes,
     BlockDriverState *bs;
     IO_CODE();
 
-    blk_wait_while_drained(blk);
+    blk_wait_while_drained(blk, flags);
     GRAPH_RDLOCK_GUARD();
 
     /* Call blk_bs() only after waiting, the graph may have changed */
@@ -1410,7 +1417,7 @@ blk_co_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes,
     BlockDriverState *bs;
     IO_CODE();
 
-    blk_wait_while_drained(blk);
+    blk_wait_while_drained(blk, flags);
     GRAPH_RDLOCK_GUARD();
 
     /* Call blk_bs() only after waiting, the graph may have changed */
@@ -1523,6 +1530,19 @@ void blk_dec_in_flight(BlockBackend *blk)
     aio_wait_kick();
 }
 
+void coroutine_fn blk_co_start_request(BlockBackend *blk)
+{
+    blk_inc_in_flight(blk);
+    blk_wait_while_drained(blk, 0);
+    qatomic_inc(&blk->start_request_count);
+}
+
+void blk_end_request(BlockBackend *blk)
+{
+    qatomic_dec(&blk->start_request_count);
+    blk_dec_in_flight(blk);
+}
+
 static void error_callback_bh(void *opaque)
 {
     struct BlockBackendAIOCB *acb = opaque;
@@ -1741,7 +1761,7 @@ blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
 {
     IO_CODE();
 
-    blk_wait_while_drained(blk);
+    blk_wait_while_drained(blk, 0);
     GRAPH_RDLOCK_GUARD();
 
     if (!blk_co_is_available(blk)) {
@@ -1788,7 +1808,7 @@ blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes)
     int ret;
     IO_CODE();
 
-    blk_wait_while_drained(blk);
+    blk_wait_while_drained(blk, 0);
     GRAPH_RDLOCK_GUARD();
 
     ret = blk_check_byte_request(blk, offset, bytes);
@@ -1834,7 +1854,7 @@ int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset,
 static int coroutine_fn blk_co_do_flush(BlockBackend *blk)
 {
     IO_CODE();
-    blk_wait_while_drained(blk);
+    blk_wait_while_drained(blk, 0);
     GRAPH_RDLOCK_GUARD();
 
     if (!blk_co_is_available(blk)) {
@@ -2009,7 +2029,7 @@ int coroutine_fn blk_co_zone_report(BlockBackend *blk, int64_t offset,
     IO_CODE();
 
     blk_inc_in_flight(blk); /* increase before waiting */
-    blk_wait_while_drained(blk);
+    blk_wait_while_drained(blk, 0);
     GRAPH_RDLOCK_GUARD();
     if (!blk_is_available(blk)) {
         blk_dec_in_flight(blk);
@@ -2034,7 +2054,7 @@ int coroutine_fn blk_co_zone_mgmt(BlockBackend *blk, BlockZoneOp op,
     IO_CODE();
 
     blk_inc_in_flight(blk);
-    blk_wait_while_drained(blk);
+    blk_wait_while_drained(blk, 0);
     GRAPH_RDLOCK_GUARD();
 
     ret = blk_check_byte_request(blk, offset, len);
@@ -2058,7 +2078,7 @@ int coroutine_fn blk_co_zone_append(BlockBackend *blk, int64_t *offset,
     IO_CODE();
 
     blk_inc_in_flight(blk);
-    blk_wait_while_drained(blk);
+    blk_wait_while_drained(blk, flags);
     GRAPH_RDLOCK_GUARD();
     if (!blk_is_available(blk)) {
         blk_dec_in_flight(blk);
-- 
2.54.0



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

* [PULL 03/18] block: Add flags parameter to blk_*_pdiscard()
  2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
  2026-05-19 17:03 ` [PULL 01/18] blkdebug: Add 'delay-ns' option Kevin Wolf
  2026-05-19 17:03 ` [PULL 02/18] block: Add blk_co_start/end_request() and BDRV_REQ_NO_QUEUE Kevin Wolf
@ 2026-05-19 17:03 ` Kevin Wolf
  2026-05-19 17:03 ` [PULL 04/18] ide: Minimal fix for deadlock between TRIM and drain Kevin Wolf
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Kevin Wolf @ 2026-05-19 17:03 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

All existing callers pass 0, but we need a way to pass BDRV_REQ_NO_QUEUE
for discard requests.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260421161132.99878-4-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 include/system/block-backend-io.h |  4 ++--
 block/block-backend.c             | 11 ++++++-----
 block/export/virtio-blk-handler.c |  2 +-
 block/mirror.c                    |  4 ++--
 nbd/server.c                      |  2 +-
 qemu-io-cmds.c                    |  2 +-
 tests/unit/test-block-iothread.c  |  4 ++--
 7 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/include/system/block-backend-io.h b/include/system/block-backend-io.h
index 0248c1c36e2..fd84723d9d0 100644
--- a/include/system/block-backend-io.h
+++ b/include/system/block-backend-io.h
@@ -218,9 +218,9 @@ int co_wrapper_mixed blk_zone_append(BlockBackend *blk, int64_t *offset,
                                          BdrvRequestFlags flags);
 
 int co_wrapper_mixed blk_pdiscard(BlockBackend *blk, int64_t offset,
-                                  int64_t bytes);
+                                  int64_t bytes, BdrvRequestFlags flags);
 int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset,
-                                 int64_t bytes);
+                                 int64_t bytes, BdrvRequestFlags flags);
 
 int co_wrapper_mixed blk_flush(BlockBackend *blk);
 int coroutine_fn blk_co_flush(BlockBackend *blk);
diff --git a/block/block-backend.c b/block/block-backend.c
index ee00440e28d..37ba7e9fc40 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -1803,12 +1803,13 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
 
 /* To be called between exactly one pair of blk_inc/dec_in_flight() */
 static int coroutine_fn
-blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes)
+blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes,
+                   BdrvRequestFlags flags)
 {
     int ret;
     IO_CODE();
 
-    blk_wait_while_drained(blk, 0);
+    blk_wait_while_drained(blk, flags);
     GRAPH_RDLOCK_GUARD();
 
     ret = blk_check_byte_request(blk, offset, bytes);
@@ -1824,7 +1825,7 @@ static void coroutine_fn blk_aio_pdiscard_entry(void *opaque)
     BlkAioEmAIOCB *acb = opaque;
     BlkRwCo *rwco = &acb->rwco;
 
-    rwco->ret = blk_co_do_pdiscard(rwco->blk, rwco->offset, acb->bytes);
+    rwco->ret = blk_co_do_pdiscard(rwco->blk, rwco->offset, acb->bytes, 0);
     blk_aio_complete(acb);
 }
 
@@ -1838,13 +1839,13 @@ BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk,
 }
 
 int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset,
-                                 int64_t bytes)
+                                 int64_t bytes, BdrvRequestFlags flags)
 {
     int ret;
     IO_OR_GS_CODE();
 
     blk_inc_in_flight(blk);
-    ret = blk_co_do_pdiscard(blk, offset, bytes);
+    ret = blk_co_do_pdiscard(blk, offset, bytes, flags);
     blk_dec_in_flight(blk);
 
     return ret;
diff --git a/block/export/virtio-blk-handler.c b/block/export/virtio-blk-handler.c
index 3dd6c43af1a..eaa6fc19067 100644
--- a/block/export/virtio-blk-handler.c
+++ b/block/export/virtio-blk-handler.c
@@ -122,7 +122,7 @@ virtio_blk_discard_write_zeroes(VirtioBlkHandler *handler, struct iovec *iov,
         }
 
         if (blk_co_pdiscard(blk, sector << VIRTIO_BLK_SECTOR_BITS,
-                            bytes) == 0) {
+                            bytes, 0) == 0) {
             return VIRTIO_BLK_S_OK;
         }
     }
diff --git a/block/mirror.c b/block/mirror.c
index 2fcded9e93d..089856f4a84 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -454,7 +454,7 @@ static void coroutine_fn mirror_co_discard(void *opaque)
     *op->bytes_handled = op->bytes;
     op->is_in_flight = true;
 
-    ret = blk_co_pdiscard(op->s->target, op->offset, op->bytes);
+    ret = blk_co_pdiscard(op->s->target, op->offset, op->bytes, 0);
     mirror_write_complete(op, ret);
 }
 
@@ -1532,7 +1532,7 @@ do_sync_target_write(MirrorBlockJob *job, MirrorMethod method,
                          zero_bitmap_end - zero_bitmap_offset);
         }
         assert(!qiov);
-        ret = blk_co_pdiscard(job->target, offset, bytes);
+        ret = blk_co_pdiscard(job->target, offset, bytes, 0);
         break;
 
     default:
diff --git a/nbd/server.c b/nbd/server.c
index 620097c58ca..78ec9844097 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -2990,7 +2990,7 @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
                                       "flush failed", errp);
 
     case NBD_CMD_TRIM:
-        ret = blk_co_pdiscard(exp->common.blk, request->from, request->len);
+        ret = blk_co_pdiscard(exp->common.blk, request->from, request->len, 0);
         if (ret >= 0 && request->flags & NBD_CMD_FLAG_FUA) {
             ret = blk_co_flush(exp->common.blk);
         }
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 13e03301624..f6d077908f2 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -2201,7 +2201,7 @@ static int discard_f(BlockBackend *blk, int argc, char **argv)
     }
 
     clock_gettime(CLOCK_MONOTONIC, &t1);
-    ret = blk_pdiscard(blk, offset, bytes);
+    ret = blk_pdiscard(blk, offset, bytes, 0);
     clock_gettime(CLOCK_MONOTONIC, &t2);
 
     if (ret < 0) {
diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c
index e26b3be5939..5273ff235a2 100644
--- a/tests/unit/test-block-iothread.c
+++ b/tests/unit/test-block-iothread.c
@@ -270,11 +270,11 @@ static void test_sync_op_blk_pdiscard(BlockBackend *blk)
     int ret;
 
     /* Early success: UNMAP not supported */
-    ret = blk_pdiscard(blk, 0, 512);
+    ret = blk_pdiscard(blk, 0, 512, 0);
     g_assert_cmpint(ret, ==, 0);
 
     /* Early error: Negative offset */
-    ret = blk_pdiscard(blk, -2, 512);
+    ret = blk_pdiscard(blk, -2, 512, 0);
     g_assert_cmpint(ret, ==, -EIO);
 }
 
-- 
2.54.0



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

* [PULL 04/18] ide: Minimal fix for deadlock between TRIM and drain
  2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
                   ` (2 preceding siblings ...)
  2026-05-19 17:03 ` [PULL 03/18] block: Add flags parameter to blk_*_pdiscard() Kevin Wolf
@ 2026-05-19 17:03 ` Kevin Wolf
  2026-05-19 17:03 ` [PULL 05/18] ide: Clean up ide_trim_co_entry() to be idiomatic coroutine code Kevin Wolf
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Kevin Wolf @ 2026-05-19 17:03 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

The implementation of TRIM in IDE can chain multiple discard requests
and uses blk_inc/dec_in_flight() to make sure that the whole TRIM
operation has completed when the device needs to be quiescent (e.g. for
the drain when performing an IDE reset, it would be bad if an IDE
request like TRIM were still in flight).

The problem is that each drain request calls blk_wait_while_drained()
and when draining, it waits until the drained section ends. At the same
time, drain_begin can only return if the whole TRIM operation has
completed. This is a classic deadlock.

Use blk_co_start/end_request() and BDRV_REQ_NO_QUEUE to avoid the
problem. This requires moving the TRIM state machine to a coroutine.
This commit does the minimal conversion so that we do have a coroutine
that works for the fix, but it still looks much like a callback-based
implementation. This will be cleaned up in the next patch.

Cc: qemu-stable@nongnu.org
Fixes: 7e5cdb345f77 ('ide: Increment BB in-flight counter for TRIM BH')
Buglink: https://redhat.atlassian.net/browse/RHEL-121686
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260421161132.99878-5-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 hw/ide/core.c | 37 ++++++++++++++++++-------------------
 1 file changed, 18 insertions(+), 19 deletions(-)

diff --git a/hw/ide/core.c b/hw/ide/core.c
index 7a15d6cac9b..48359c934c1 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -420,7 +420,6 @@ typedef struct TrimAIOCB {
     QEMUBH *bh;
     int ret;
     QEMUIOVector *qiov;
-    BlockAIOCB *aiocb;
     int i, j;
 } TrimAIOCB;
 
@@ -433,11 +432,6 @@ static void trim_aio_cancel(BlockAIOCB *acb)
     iocb->i = (iocb->qiov->iov[iocb->j].iov_len / 8) - 1;
 
     iocb->ret = -ECANCELED;
-
-    if (iocb->aiocb) {
-        blk_aio_cancel_async(iocb->aiocb);
-        iocb->aiocb = NULL;
-    }
 }
 
 static const AIOCBInfo trim_aiocb_info = {
@@ -456,15 +450,20 @@ static void ide_trim_bh_cb(void *opaque)
     iocb->bh = NULL;
     qemu_aio_unref(iocb);
 
-    /* Paired with an increment in ide_issue_trim() */
-    blk_dec_in_flight(blk);
+    /* Paired with blk_co_start_request in ide_trim_co_entry() */
+    blk_end_request(blk);
 }
 
-static void ide_issue_trim_cb(void *opaque, int ret)
+static void coroutine_fn ide_trim_co_entry(void *opaque)
 {
     TrimAIOCB *iocb = opaque;
     IDEState *s = iocb->s;
+    int ret = 0;
+
+    /* Paired with blk_end_request in ide_trim_bh_cb() */
+    blk_co_start_request(s->blk);
 
+loop:
     if (iocb->i >= 0) {
         if (ret >= 0) {
             block_acct_done(blk_get_stats(s->blk), &s->acct);
@@ -499,11 +498,11 @@ static void ide_issue_trim_cb(void *opaque, int ret)
                                  count << BDRV_SECTOR_BITS, BLOCK_ACCT_UNMAP);
 
                 /* Got an entry! Submit and exit.  */
-                iocb->aiocb = blk_aio_pdiscard(s->blk,
-                                               sector << BDRV_SECTOR_BITS,
-                                               count << BDRV_SECTOR_BITS,
-                                               ide_issue_trim_cb, opaque);
-                return;
+                ret = blk_co_pdiscard(s->blk,
+                                      sector << BDRV_SECTOR_BITS,
+                                      count << BDRV_SECTOR_BITS,
+                                      BDRV_REQ_NO_QUEUE);
+                goto loop;
             }
 
             iocb->j++;
@@ -514,7 +513,6 @@ static void ide_issue_trim_cb(void *opaque, int ret)
     }
 
 done:
-    iocb->aiocb = NULL;
     if (iocb->bh) {
         replay_bh_schedule_event(iocb->bh);
     }
@@ -527,9 +525,7 @@ BlockAIOCB *ide_issue_trim(
     IDEState *s = opaque;
     IDEDevice *dev = s->unit ? s->bus->slave : s->bus->master;
     TrimAIOCB *iocb;
-
-    /* Paired with a decrement in ide_trim_bh_cb() */
-    blk_inc_in_flight(s->blk);
+    Coroutine *co;
 
     iocb = blk_aio_get(&trim_aiocb_info, s->blk, cb, cb_opaque);
     iocb->s = s;
@@ -539,7 +535,10 @@ BlockAIOCB *ide_issue_trim(
     iocb->qiov = qiov;
     iocb->i = -1;
     iocb->j = 0;
-    ide_issue_trim_cb(iocb, 0);
+
+    co = qemu_coroutine_create(ide_trim_co_entry, iocb);
+    aio_co_enter(qemu_get_current_aio_context(), co);
+
     return &iocb->common;
 }
 
-- 
2.54.0



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

* [PULL 05/18] ide: Clean up ide_trim_co_entry() to be idiomatic coroutine code
  2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
                   ` (3 preceding siblings ...)
  2026-05-19 17:03 ` [PULL 04/18] ide: Minimal fix for deadlock between TRIM and drain Kevin Wolf
@ 2026-05-19 17:03 ` Kevin Wolf
  2026-05-19 17:03 ` [PULL 06/18] ide-test: Factor out wait_dma_completion() Kevin Wolf
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Kevin Wolf @ 2026-05-19 17:03 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

The previous commit did a minimal conversion of the callback based state
machine for TRIM to a coroutine in order to fix a bug. Refactor it to
actually look like normal coroutine based code, which improves its
readability.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260421161132.99878-6-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 hw/ide/core.c | 87 +++++++++++++++++++++++----------------------------
 1 file changed, 39 insertions(+), 48 deletions(-)

diff --git a/hw/ide/core.c b/hw/ide/core.c
index 48359c934c1..f78b00220b8 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -420,18 +420,15 @@ typedef struct TrimAIOCB {
     QEMUBH *bh;
     int ret;
     QEMUIOVector *qiov;
-    int i, j;
+    bool canceled;
 } TrimAIOCB;
 
 static void trim_aio_cancel(BlockAIOCB *acb)
 {
     TrimAIOCB *iocb = container_of(acb, TrimAIOCB, common);
 
-    /* Exit the loop so ide_issue_trim_cb will not continue  */
-    iocb->j = iocb->qiov->niov - 1;
-    iocb->i = (iocb->qiov->iov[iocb->j].iov_len / 8) - 1;
-
-    iocb->ret = -ECANCELED;
+    /* Exit the loop so ide_trim_co_entry will not continue */
+    iocb->canceled = true;
 }
 
 static const AIOCBInfo trim_aiocb_info = {
@@ -458,60 +455,55 @@ static void coroutine_fn ide_trim_co_entry(void *opaque)
 {
     TrimAIOCB *iocb = opaque;
     IDEState *s = iocb->s;
-    int ret = 0;
+    int i, j;
+    int ret;
 
     /* Paired with blk_end_request in ide_trim_bh_cb() */
     blk_co_start_request(s->blk);
 
-loop:
-    if (iocb->i >= 0) {
-        if (ret >= 0) {
-            block_acct_done(blk_get_stats(s->blk), &s->acct);
-        } else {
-            block_acct_failed(blk_get_stats(s->blk), &s->acct);
-        }
-    }
+    for (j = 0; j < iocb->qiov->niov; j++) {
+        for (i = 0; i < iocb->qiov->iov[j].iov_len / 8; i++) {
+            uint64_t *buffer = iocb->qiov->iov[j].iov_base;
 
-    if (ret >= 0) {
-        while (iocb->j < iocb->qiov->niov) {
-            int j = iocb->j;
-            while (++iocb->i < iocb->qiov->iov[j].iov_len / 8) {
-                int i = iocb->i;
-                uint64_t *buffer = iocb->qiov->iov[j].iov_base;
+            /* 6-byte LBA + 2-byte range per entry */
+            uint64_t entry = le64_to_cpu(buffer[i]);
+            uint64_t sector = entry & 0x0000ffffffffffffULL;
+            uint16_t count = entry >> 48;
 
-                /* 6-byte LBA + 2-byte range per entry */
-                uint64_t entry = le64_to_cpu(buffer[i]);
-                uint64_t sector = entry & 0x0000ffffffffffffULL;
-                uint16_t count = entry >> 48;
+            if (count == 0) {
+                continue;
+            }
 
-                if (count == 0) {
-                    continue;
-                }
+            if (iocb->canceled) {
+                iocb->ret = -ECANCELED;
+                goto done;
+            }
 
-                if (!ide_sect_range_ok(s, sector, count)) {
-                    block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_UNMAP);
-                    iocb->ret = -EINVAL;
-                    goto done;
-                }
+            if (!ide_sect_range_ok(s, sector, count)) {
+                block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_UNMAP);
+                iocb->ret = -EINVAL;
+                goto done;
+            }
 
-                block_acct_start(blk_get_stats(s->blk), &s->acct,
-                                 count << BDRV_SECTOR_BITS, BLOCK_ACCT_UNMAP);
+            block_acct_start(blk_get_stats(s->blk), &s->acct,
+                             count << BDRV_SECTOR_BITS, BLOCK_ACCT_UNMAP);
 
-                /* Got an entry! Submit and exit.  */
-                ret = blk_co_pdiscard(s->blk,
-                                      sector << BDRV_SECTOR_BITS,
-                                      count << BDRV_SECTOR_BITS,
-                                      BDRV_REQ_NO_QUEUE);
-                goto loop;
+            /* Got an entry! Submit and exit.  */
+            ret = blk_co_pdiscard(s->blk,
+                                  sector << BDRV_SECTOR_BITS,
+                                  count << BDRV_SECTOR_BITS,
+                                  BDRV_REQ_NO_QUEUE);
+            if (ret >= 0) {
+                block_acct_done(blk_get_stats(s->blk), &s->acct);
+            } else {
+                iocb->ret = ret;
+                block_acct_failed(blk_get_stats(s->blk), &s->acct);
+                goto done;
             }
-
-            iocb->j++;
-            iocb->i = -1;
         }
-    } else {
-        iocb->ret = ret;
     }
 
+    iocb->ret = 0;
 done:
     if (iocb->bh) {
         replay_bh_schedule_event(iocb->bh);
@@ -533,8 +525,7 @@ BlockAIOCB *ide_issue_trim(
                                    &DEVICE(dev)->mem_reentrancy_guard);
     iocb->ret = 0;
     iocb->qiov = qiov;
-    iocb->i = -1;
-    iocb->j = 0;
+    iocb->canceled = false;
 
     co = qemu_coroutine_create(ide_trim_co_entry, iocb);
     aio_co_enter(qemu_get_current_aio_context(), co);
-- 
2.54.0



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

* [PULL 06/18] ide-test: Factor out wait_dma_completion()
  2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
                   ` (4 preceding siblings ...)
  2026-05-19 17:03 ` [PULL 05/18] ide: Clean up ide_trim_co_entry() to be idiomatic coroutine code Kevin Wolf
@ 2026-05-19 17:03 ` Kevin Wolf
  2026-05-19 17:03 ` [PULL 07/18] ide-test: Test reset during TRIM Kevin Wolf
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Kevin Wolf @ 2026-05-19 17:03 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260421161132.99878-7-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 tests/qtest/ide-test.c | 48 +++++++++++++++++++++++++-----------------
 1 file changed, 29 insertions(+), 19 deletions(-)

diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c
index ceee444a9ec..c6dcb2c0745 100644
--- a/tests/qtest/ide-test.c
+++ b/tests/qtest/ide-test.c
@@ -200,6 +200,34 @@ static uint64_t trim_range_le(uint64_t sector, uint16_t count)
     return cpu_to_le64(((uint64_t)count << 48) + sector);
 }
 
+static uint8_t wait_dma_completion(QTestState *qts, QPCIDevice *dev,
+                                   QPCIBar bmdma_bar, QPCIBar ide_bar)
+{
+    uint8_t status;
+
+    /* Wait for the DMA transfer to complete */
+    do {
+        status = qpci_io_readb(dev, bmdma_bar, bmreg_status);
+    } while ((status & (BM_STS_ACTIVE | BM_STS_INTR)) == BM_STS_ACTIVE);
+
+    g_assert_cmpint(qtest_get_irq(qts, IDE_PRIMARY_IRQ), ==,
+                    !!(status & BM_STS_INTR));
+
+    /* Check IDE status code */
+    assert_bit_set(qpci_io_readb(dev, ide_bar, reg_status), DRDY);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), BSY | DRQ);
+
+    /* Reading the status register clears the IRQ */
+    g_assert(!qtest_get_irq(qts, IDE_PRIMARY_IRQ));
+
+    /* Stop DMA transfer if still active */
+    if (status & BM_STS_ACTIVE) {
+        qpci_io_writeb(dev, bmdma_bar, bmreg_cmd, 0);
+    }
+
+    return status;
+}
+
 static int send_dma_request(QTestState *qts, int cmd, uint64_t sector,
                             int nb_sectors, PrdtEntry *prdt, int prdt_entries,
                             void(*post_exec)(QPCIDevice *dev, QPCIBar ide_bar,
@@ -280,25 +308,7 @@ static int send_dma_request(QTestState *qts, int cmd, uint64_t sector,
         qpci_io_writeb(dev, bmdma_bar, bmreg_cmd, 0);
     }
 
-    /* Wait for the DMA transfer to complete */
-    do {
-        status = qpci_io_readb(dev, bmdma_bar, bmreg_status);
-    } while ((status & (BM_STS_ACTIVE | BM_STS_INTR)) == BM_STS_ACTIVE);
-
-    g_assert_cmpint(qtest_get_irq(qts, IDE_PRIMARY_IRQ), ==,
-                    !!(status & BM_STS_INTR));
-
-    /* Check IDE status code */
-    assert_bit_set(qpci_io_readb(dev, ide_bar, reg_status), DRDY);
-    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), BSY | DRQ);
-
-    /* Reading the status register clears the IRQ */
-    g_assert(!qtest_get_irq(qts, IDE_PRIMARY_IRQ));
-
-    /* Stop DMA transfer if still active */
-    if (status & BM_STS_ACTIVE) {
-        qpci_io_writeb(dev, bmdma_bar, bmreg_cmd, 0);
-    }
+    status = wait_dma_completion(qts, dev, bmdma_bar, ide_bar);
 
     free_pci_device(dev);
 
-- 
2.54.0



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

* [PULL 07/18] ide-test: Test reset during TRIM
  2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
                   ` (5 preceding siblings ...)
  2026-05-19 17:03 ` [PULL 06/18] ide-test: Factor out wait_dma_completion() Kevin Wolf
@ 2026-05-19 17:03 ` Kevin Wolf
  2026-05-19 17:03 ` [PULL 08/18] Remove the deprecated glusterfs block driver Kevin Wolf
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Kevin Wolf @ 2026-05-19 17:03 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

This is a regression test for the bug fixed in the previous commits, a
deadlock between the drain issued by an IDE reset and the TRIM state
machine.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260421161132.99878-8-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 tests/qtest/ide-test.c | 95 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 87 insertions(+), 8 deletions(-)

diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c
index c6dcb2c0745..721e78170bc 100644
--- a/tests/qtest/ide-test.c
+++ b/tests/qtest/ide-test.c
@@ -41,8 +41,11 @@
 #define IDE_PCI_FUNC    1
 
 #define IDE_BASE 0x1f0
+#define IDE_BASE2 0x3f6
 #define IDE_PRIMARY_IRQ 14
 
+#define IDE_CTRL_RESET 0x04
+
 #define ATAPI_BLOCK_SIZE 2048
 
 /* How many bytes to receive via ATAPI PIO at one time.
@@ -99,6 +102,7 @@ enum {
 
     CMDF_ABORT      = 0x100,
     CMDF_NO_BM      = 0x200,
+    CMDF_NO_WAIT    = 0x400,
 };
 
 enum {
@@ -228,21 +232,21 @@ static uint8_t wait_dma_completion(QTestState *qts, QPCIDevice *dev,
     return status;
 }
 
-static int send_dma_request(QTestState *qts, int cmd, uint64_t sector,
-                            int nb_sectors, PrdtEntry *prdt, int prdt_entries,
-                            void(*post_exec)(QPCIDevice *dev, QPCIBar ide_bar,
-                                             uint64_t sector, int nb_sectors))
+static int send_dma_request_dev(QTestState *qts, QPCIDevice *dev,
+                                QPCIBar bmdma_bar, QPCIBar ide_bar, int cmd,
+                                uint64_t sector, int nb_sectors,
+                                PrdtEntry *prdt, int prdt_entries,
+                                void(*post_exec)(QPCIDevice *dev,
+                                                 QPCIBar ide_bar,
+                                                 uint64_t sector,
+                                                 int nb_sectors))
 {
-    QPCIDevice *dev;
-    QPCIBar bmdma_bar, ide_bar;
     uintptr_t guest_prdt;
     size_t len;
     bool from_dev;
     uint8_t status;
     int flags;
 
-    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
-
     flags = cmd & ~0xff;
     cmd &= 0xff;
 
@@ -308,8 +312,28 @@ static int send_dma_request(QTestState *qts, int cmd, uint64_t sector,
         qpci_io_writeb(dev, bmdma_bar, bmreg_cmd, 0);
     }
 
+    if (flags & CMDF_NO_WAIT) {
+        return 0;
+    }
+
     status = wait_dma_completion(qts, dev, bmdma_bar, ide_bar);
 
+    return status;
+}
+
+static int send_dma_request(QTestState *qts, int cmd, uint64_t sector,
+                            int nb_sectors, PrdtEntry *prdt, int prdt_entries,
+                            void(*post_exec)(QPCIDevice *dev, QPCIBar ide_bar,
+                                             uint64_t sector, int nb_sectors))
+{
+    QPCIDevice *dev;
+    QPCIBar bmdma_bar, ide_bar;
+    uint8_t status;
+
+    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+    status = send_dma_request_dev(qts, dev, bmdma_bar, ide_bar,
+                                  cmd, sector, nb_sectors, prdt, prdt_entries,
+                                  post_exec);
     free_pci_device(dev);
 
     return status;
@@ -457,6 +481,60 @@ static void test_bmdma_trim(void)
     test_bmdma_teardown(qts);
 }
 
+static void test_bmdma_trim_reset(void)
+{
+    QTestState *qts;
+    QPCIDevice *dev;
+    QPCIBar bmdma_bar, ide_bar, ide_bar2;
+    uint8_t status;
+    const uint64_t trim_range[] = {
+        trim_range_le(0, 2),
+        trim_range_le(6, 8),
+    };
+    size_t len = 512;
+    uint8_t *buf;
+    uintptr_t guest_buf;
+    PrdtEntry prdt[1];
+
+    qts = ide_test_start(
+        "-blockdev file,filename=%s,node-name=img "
+        "-blockdev blkdebug,image=img,node-name=dbg,discard=unmap,"
+        "inject-error.0.event=none,inject-error.0.iotype=discard,"
+        "inject-error.0.errno=0,inject-error.0.delay-ns=1000000 "
+        "-device ide-hd,drive=dbg,bus=ide.0",
+        tmp_path[0]);
+    qtest_irq_intercept_in(qts, "ioapic");
+
+    guest_buf = guest_alloc(&guest_malloc, len);
+    prdt[0].addr = cpu_to_le32(guest_buf),
+    prdt[0].size = cpu_to_le32(len | PRDT_EOT),
+
+    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+    ide_bar2 = qpci_legacy_iomap(dev, IDE_BASE2);
+
+    buf = g_malloc(len);
+
+    /* TRIM request with two segments */
+    *((uint64_t *)buf) = trim_range[0];
+    *((uint64_t *)buf + 1) = trim_range[1];
+
+    qtest_memwrite(qts, guest_buf, buf, 2 * sizeof(uint64_t));
+
+    send_dma_request_dev(qts, dev, bmdma_bar, ide_bar, CMD_DSM | CMDF_NO_WAIT, 0, 1, prdt,
+                     ARRAY_SIZE(prdt), NULL);
+
+    /* Reset the device while the first segment is in flight */
+    qpci_io_writeb(dev, ide_bar2, 0, IDE_CTRL_RESET);
+
+    status = wait_dma_completion(qts, dev, bmdma_bar, ide_bar);
+    g_assert_cmphex(status, ==, BM_STS_INTR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
+
+    free_pci_device(dev);
+    g_free(buf);
+    test_bmdma_teardown(qts);
+}
+
 /*
  * This test is developed according to the Programming Interface for
  * Bus Master IDE Controller (Revision 1.0 5/16/94)
@@ -1138,6 +1216,7 @@ int main(int argc, char **argv)
 
     qtest_add_func("/ide/bmdma/simple_rw", test_bmdma_simple_rw);
     qtest_add_func("/ide/bmdma/trim", test_bmdma_trim);
+    qtest_add_func("/ide/bmdma/trim_reset", test_bmdma_trim_reset);
     qtest_add_func("/ide/bmdma/various_prdts", test_bmdma_various_prdts);
     qtest_add_func("/ide/bmdma/no_busmaster", test_bmdma_no_busmaster);
 
-- 
2.54.0



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

* [PULL 08/18] Remove the deprecated glusterfs block driver
  2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
                   ` (6 preceding siblings ...)
  2026-05-19 17:03 ` [PULL 07/18] ide-test: Test reset during TRIM Kevin Wolf
@ 2026-05-19 17:03 ` Kevin Wolf
  2026-05-19 17:03 ` [PULL 09/18] MAINTAINERS: Add myself as maintainer for replication Kevin Wolf
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Kevin Wolf @ 2026-05-19 17:03 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

From: Thomas Huth <thuth@redhat.com>

Glusterfs has been marked as deprecated since QEMU v9.2, and as far
as I know, nobody spoke up 'til today that it should be kept.
The listed e-mail address integration@gluster.org in our MAINTAINERS
file seems to be bouncing nowadays, and looking at their website
https://www.gluster.org/ the most recent news are from 2020 / 2021 ...
so it seems like there is really hardly any interest in Glusterfs
anymore. Thus it's time to remove the code now from QEMU.

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Thomas Huth <thuth@redhat.com>
Message-ID: <20260511063013.39805-1-thuth@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 qapi/block-core.json                          |   52 -
 docs/about/deprecated.rst                     |    8 -
 docs/about/removed-features.rst               |    7 +
 docs/system/device-url-syntax.rst.inc         |   39 -
 docs/system/qemu-block-drivers.rst.inc        |   84 -
 meson_options.txt                             |    2 -
 block/gluster.c                               | 1644 -----------------
 tests/qtest/modules-test.c                    |    3 -
 MAINTAINERS                                   |    6 -
 block/meson.build                             |    1 -
 meson.build                                   |   47 -
 .../ci/setup/debian/debian-13-ppc64le.yaml    |    1 -
 .../ci/setup/ubuntu/ubuntu-2404-aarch64.yaml  |    1 -
 .../ci/setup/ubuntu/ubuntu-2404-s390x.yaml    |    1 -
 scripts/coverity-scan/coverity-scan.docker    |    1 -
 scripts/coverity-scan/run-coverity-scan       |    2 +-
 scripts/meson-buildoptions.sh                 |    3 -
 .../dockerfiles/debian-amd64-cross.docker     |    1 -
 .../dockerfiles/debian-arm64-cross.docker     |    1 -
 .../dockerfiles/debian-mips64el-cross.docker  |    1 -
 .../dockerfiles/debian-mipsel-cross.docker    |    1 -
 .../dockerfiles/debian-ppc64el-cross.docker   |    1 -
 .../dockerfiles/debian-riscv64-cross.docker   |    1 -
 .../dockerfiles/debian-s390x-cross.docker     |    1 -
 tests/docker/dockerfiles/debian.docker        |    1 -
 .../dockerfiles/fedora-rust-nightly.docker    |    1 -
 tests/docker/dockerfiles/fedora.docker        |    1 -
 tests/docker/dockerfiles/opensuse-leap.docker |    1 -
 tests/docker/dockerfiles/ubuntu2204.docker    |    1 -
 tests/lcitool/projects/qemu.yml               |    1 -
 30 files changed, 8 insertions(+), 1907 deletions(-)
 delete mode 100644 block/gluster.c

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 0efd51787b4..1f87b078505 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3334,18 +3334,12 @@
 #
 # @snapshot-access: Since 7.0
 #
-# Features:
-#
-# @deprecated: Member @gluster is deprecated because GlusterFS
-#     development ceased.
-#
 # Since: 2.9
 ##
 { 'enum': 'BlockdevDriver',
   'data': [ 'blkdebug', 'blklogwrites', 'blkreplay', 'blkverify', 'bochs',
             'cloop', 'compress', 'copy-before-write', 'copy-on-read', 'dmg',
             'file', 'snapshot-access', 'ftp', 'ftps',
-            {'name': 'gluster', 'features': [ 'deprecated' ] },
             {'name': 'host_cdrom', 'if': 'HAVE_HOST_BLOCK_DEVICE' },
             {'name': 'host_device', 'if': 'HAVE_HOST_BLOCK_DEVICE' },
             'http', 'https',
@@ -4118,30 +4112,6 @@
             '*rewrite-corrupted': 'bool',
             '*read-pattern': 'QuorumReadPattern' } }
 
-##
-# @BlockdevOptionsGluster:
-#
-# Driver specific block device options for Gluster
-#
-# @volume: name of gluster volume where VM image resides
-#
-# @path: absolute path to image file in gluster volume
-#
-# @server: gluster servers description
-#
-# @debug: libgfapi log level (default '4' which is Error) (Since 2.8)
-#
-# @logfile: libgfapi log file (default /dev/stderr) (Since 2.8)
-#
-# Since: 2.9
-##
-{ 'struct': 'BlockdevOptionsGluster',
-  'data': { 'volume': 'str',
-            'path': 'str',
-            'server': ['SocketAddress'],
-            '*debug': 'int',
-            '*logfile': 'str' } }
-
 ##
 # @BlockdevOptionsIoUring:
 #
@@ -4875,7 +4845,6 @@
       'file':       'BlockdevOptionsFile',
       'ftp':        'BlockdevOptionsCurlFtp',
       'ftps':       'BlockdevOptionsCurlFtps',
-      'gluster':    'BlockdevOptionsGluster',
       'host_cdrom':  { 'type': 'BlockdevOptionsFile',
                        'if': 'HAVE_HOST_BLOCK_DEVICE' },
       'host_device': { 'type': 'BlockdevOptionsFile',
@@ -5146,26 +5115,6 @@
             '*nocow':               'bool',
             '*extent-size-hint':    'size'} }
 
-##
-# @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;
-#     allowed values: off, falloc (if CONFIG_GLUSTERFS_FALLOCATE),
-#     full (if CONFIG_GLUSTERFS_ZEROFILL))
-#
-# Since: 2.12
-##
-{ 'struct': 'BlockdevCreateOptionsGluster',
-  'data': { 'location':         'BlockdevOptionsGluster',
-            'size':             'size',
-            '*preallocation':   'PreallocMode' } }
-
 ##
 # @BlockdevCreateOptionsLUKS:
 #
@@ -5593,7 +5542,6 @@
   'discriminator': 'driver',
   'data': {
       'file':           'BlockdevCreateOptionsFile',
-      'gluster':        'BlockdevCreateOptionsGluster',
       'luks':           'BlockdevCreateOptionsLUKS',
       'nfs':            'BlockdevCreateOptionsNfs',
       'parallels':      'BlockdevCreateOptionsParallels',
diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst
index bf6182d61c6..e64328c5b2b 100644
--- a/docs/about/deprecated.rst
+++ b/docs/about/deprecated.rst
@@ -382,14 +382,6 @@ Specifying the iSCSI password in plain text on the command line using the
 used instead, to refer to a ``--object secret...`` instance that provides
 a password via a file, or encrypted.
 
-``gluster`` backend (since 9.2)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-According to https://marc.info/?l=fedora-devel-list&m=171934833215726
-the GlusterFS development effectively ended. Unless the development
-gains momentum again, the QEMU project will remove the gluster backend
-in a future release.
-
 
 Character device options
 ''''''''''''''''''''''''
diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst
index 9bd83b183f4..1ee4ab07944 100644
--- a/docs/about/removed-features.rst
+++ b/docs/about/removed-features.rst
@@ -1429,6 +1429,13 @@ The corresponding upstream server project is no longer maintained.
 Users are recommended to switch to an alternative distributed block
 device driver such as RBD.
 
+``gluster`` backend (removed in 11.1)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+According to https://marc.info/?l=fedora-devel-list&m=171934833215726
+the GlusterFS development effectively ended.
+
+
 VFIO devices
 ------------
 
diff --git a/docs/system/device-url-syntax.rst.inc b/docs/system/device-url-syntax.rst.inc
index 996ce5418ff..3521a3d053f 100644
--- a/docs/system/device-url-syntax.rst.inc
+++ b/docs/system/device-url-syntax.rst.inc
@@ -85,45 +85,6 @@ These are specified using a special URL syntax.
    Currently authentication must be done using ssh-agent. Other
    authentication methods may be supported in future.
 
-``GlusterFS``
-   GlusterFS is a user space distributed file system. QEMU supports the
-   use of GlusterFS volumes for hosting VM disk images using TCP and Unix
-   Domain Sockets transport protocols.
-
-   Syntax for specifying a VM disk image on GlusterFS volume is
-
-   .. parsed-literal::
-
-      URI:
-      gluster[+type]://[host[:port]]/volume/path[?socket=...][,debug=N][,logfile=...]
-
-      JSON:
-      'json:{"driver":"qcow2","file":{"driver":"gluster","volume":"testvol","path":"a.img","debug":N,"logfile":"...",
-                                       "server":[{"type":"tcp","host":"...","port":"..."},
-                                                 {"type":"unix","socket":"..."}]}}'
-
-   Example
-
-   .. parsed-literal::
-
-      URI:
-      |qemu_system| --drive file=gluster://192.0.2.1/testvol/a.img,
-                                     file.debug=9,file.logfile=/var/log/qemu-gluster.log
-
-      JSON:
-      |qemu_system| 'json:{"driver":"qcow2",
-                                "file":{"driver":"gluster",
-                                         "volume":"testvol","path":"a.img",
-                                         "debug":9,"logfile":"/var/log/qemu-gluster.log",
-                                         "server":[{"type":"tcp","host":"1.2.3.4","port":24007},
-                                                   {"type":"unix","socket":"/var/run/glusterd.socket"}]}}'
-      |qemu_system| -drive driver=qcow2,file.driver=gluster,file.volume=testvol,file.path=/path/a.img,
-                                            file.debug=9,file.logfile=/var/log/qemu-gluster.log,
-                                            file.server.0.type=tcp,file.server.0.host=1.2.3.4,file.server.0.port=24007,
-                                            file.server.1.type=unix,file.server.1.socket=/var/run/glusterd.socket
-
-   See also http://www.gluster.org.
-
 ``HTTP/HTTPS/FTP/FTPS``
    QEMU supports read-only access to files accessed over http(s) and
    ftp(s).
diff --git a/docs/system/qemu-block-drivers.rst.inc b/docs/system/qemu-block-drivers.rst.inc
index 384e95ba765..675daa72f97 100644
--- a/docs/system/qemu-block-drivers.rst.inc
+++ b/docs/system/qemu-block-drivers.rst.inc
@@ -665,90 +665,6 @@ systems as the package 'scsi-target-utils'.
     -boot d -drive file=iscsi://127.0.0.1/iqn.qemu.test/1 \\
     -cdrom iscsi://127.0.0.1/iqn.qemu.test/2
 
-GlusterFS disk images
-~~~~~~~~~~~~~~~~~~~~~
-
-GlusterFS is a user space distributed file system.
-
-You can boot from the GlusterFS disk image with the command:
-
-URI:
-
-.. parsed-literal::
-
-  |qemu_system| -drive file=gluster[+TYPE]://[HOST}[:PORT]]/VOLUME/PATH
-                               [?socket=...][,file.debug=9][,file.logfile=...]
-
-JSON:
-
-.. parsed-literal::
-
-  |qemu_system| 'json:{"driver":"qcow2",
-                           "file":{"driver":"gluster",
-                                    "volume":"testvol","path":"a.img","debug":9,"logfile":"...",
-                                    "server":[{"type":"tcp","host":"...","port":"..."},
-                                              {"type":"unix","socket":"..."}]}}'
-
-*gluster* is the protocol.
-
-*TYPE* specifies the transport type used to connect to gluster
-management daemon (glusterd). Valid transport types are
-tcp and unix. In the URI form, if a transport type isn't specified,
-then tcp type is assumed.
-
-*HOST* specifies the server where the volume file specification for
-the given volume resides. This can be either a hostname or an ipv4 address.
-If transport type is unix, then *HOST* field should not be specified.
-Instead *socket* field needs to be populated with the path to unix domain
-socket.
-
-*PORT* is the port number on which glusterd is listening. This is optional
-and if not specified, it defaults to port 24007. If the transport type is unix,
-then *PORT* should not be specified.
-
-*VOLUME* is the name of the gluster volume which contains the disk image.
-
-*PATH* is the path to the actual disk image that resides on gluster volume.
-
-*debug* is the logging level of the gluster protocol driver. Debug levels
-are 0-9, with 9 being the most verbose, and 0 representing no debugging output.
-The default level is 4. The current logging levels defined in the gluster source
-are 0 - None, 1 - Emergency, 2 - Alert, 3 - Critical, 4 - Error, 5 - Warning,
-6 - Notice, 7 - Info, 8 - Debug, 9 - Trace
-
-*logfile* is a commandline option to mention log file path which helps in
-logging to the specified file and also help in persisting the gfapi logs. The
-default is stderr.
-
-You can create a GlusterFS disk image with the command:
-
-.. parsed-literal::
-
-  qemu-img create gluster://HOST/VOLUME/PATH SIZE
-
-Examples
-
-.. parsed-literal::
-
-  |qemu_system| -drive file=gluster://1.2.3.4/testvol/a.img
-  |qemu_system| -drive file=gluster+tcp://1.2.3.4/testvol/a.img
-  |qemu_system| -drive file=gluster+tcp://1.2.3.4:24007/testvol/dir/a.img
-  |qemu_system| -drive file=gluster+tcp://[1:2:3:4:5:6:7:8]/testvol/dir/a.img
-  |qemu_system| -drive file=gluster+tcp://[1:2:3:4:5:6:7:8]:24007/testvol/dir/a.img
-  |qemu_system| -drive file=gluster+tcp://server.domain.com:24007/testvol/dir/a.img
-  |qemu_system| -drive file=gluster+unix:///testvol/dir/a.img?socket=/tmp/glusterd.socket
-  |qemu_system| -drive file=gluster://1.2.3.4/testvol/a.img,file.debug=9,file.logfile=/var/log/qemu-gluster.log
-  |qemu_system| 'json:{"driver":"qcow2",
-                           "file":{"driver":"gluster",
-                                    "volume":"testvol","path":"a.img",
-                                    "debug":9,"logfile":"/var/log/qemu-gluster.log",
-                                    "server":[{"type":"tcp","host":"1.2.3.4","port":24007},
-                                              {"type":"unix","socket":"/var/run/glusterd.socket"}]}}'
-  |qemu_system| -drive driver=qcow2,file.driver=gluster,file.volume=testvol,file.path=/path/a.img,
-                                       file.debug=9,file.logfile=/var/log/qemu-gluster.log,
-                                       file.server.0.type=tcp,file.server.0.host=1.2.3.4,file.server.0.port=24007,
-                                       file.server.1.type=unix,file.server.1.socket=/var/run/glusterd.socket
-
 Secure Shell (ssh) disk images
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/meson_options.txt b/meson_options.txt
index ae17a3d8830..a07cb47d35e 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -160,8 +160,6 @@ option('curl', type : 'feature', value : 'auto',
        description: 'CURL block device driver')
 option('gio', type : 'feature', value : 'auto',
        description: 'use libgio for D-Bus support')
-option('glusterfs', type : 'feature', value : 'auto',
-       description: 'Glusterfs block device driver')
 option('hv_balloon', type : 'feature', value : 'auto',
        description: 'hv-balloon driver (requires Glib 2.68+ GTree API)')
 option('libdw', type : 'feature', value : 'auto',
diff --git a/block/gluster.c b/block/gluster.c
deleted file mode 100644
index 279f650241c..00000000000
--- a/block/gluster.c
+++ /dev/null
@@ -1,1644 +0,0 @@
-/*
- * GlusterFS backend for QEMU
- *
- * Copyright (C) 2012 Bharata B Rao <bharata@linux.vnet.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qemu/units.h"
-#include <glusterfs/api/glfs.h>
-#include "block/block-io.h"
-#include "block/block_int.h"
-#include "block/qdict.h"
-#include "qapi/error.h"
-#include "qobject/qdict.h"
-#include "qapi/qmp/qerror.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "qemu/option.h"
-#include "qemu/cutils.h"
-
-#ifdef CONFIG_GLUSTERFS_FTRUNCATE_HAS_STAT
-# define glfs_ftruncate(fd, offset) glfs_ftruncate(fd, offset, NULL, NULL)
-#endif
-
-#define GLUSTER_OPT_FILENAME        "filename"
-#define GLUSTER_OPT_VOLUME          "volume"
-#define GLUSTER_OPT_PATH            "path"
-#define GLUSTER_OPT_TYPE            "type"
-#define GLUSTER_OPT_SERVER_PATTERN  "server."
-#define GLUSTER_OPT_HOST            "host"
-#define GLUSTER_OPT_PORT            "port"
-#define GLUSTER_OPT_TO              "to"
-#define GLUSTER_OPT_IPV4            "ipv4"
-#define GLUSTER_OPT_IPV6            "ipv6"
-#define GLUSTER_OPT_SOCKET          "socket"
-#define GLUSTER_OPT_DEBUG           "debug"
-#define GLUSTER_DEFAULT_PORT        24007
-#define GLUSTER_DEBUG_DEFAULT       4
-#define GLUSTER_DEBUG_MAX           9
-#define GLUSTER_OPT_LOGFILE         "logfile"
-#define GLUSTER_LOGFILE_DEFAULT     "-" /* handled in libgfapi as /dev/stderr */
-/*
- * Several versions of GlusterFS (3.12? -> 6.0.1) fail when the transfer size
- * is greater or equal to 1024 MiB, so we are limiting the transfer size to 512
- * MiB to avoid this rare issue.
- */
-#define GLUSTER_MAX_TRANSFER        (512 * MiB)
-
-#define GERR_INDEX_HINT "hint: check in 'server' array index '%d'\n"
-
-typedef struct GlusterAIOCB {
-    int64_t size;
-    int ret;
-    Coroutine *coroutine;
-} GlusterAIOCB;
-
-typedef struct BDRVGlusterState {
-    struct glfs *glfs;
-    struct glfs_fd *fd;
-    char *logfile;
-    bool supports_seek_data;
-    int debug;
-} BDRVGlusterState;
-
-typedef struct BDRVGlusterReopenState {
-    struct glfs *glfs;
-    struct glfs_fd *fd;
-} BDRVGlusterReopenState;
-
-
-typedef struct GlfsPreopened {
-    char *volume;
-    glfs_t *fs;
-    int ref;
-} GlfsPreopened;
-
-typedef struct ListElement {
-    QLIST_ENTRY(ListElement) list;
-    GlfsPreopened saved;
-} ListElement;
-
-static QLIST_HEAD(, ListElement) glfs_list;
-
-static QemuOptsList qemu_gluster_create_opts = {
-    .name = "qemu-gluster-create-opts",
-    .head = QTAILQ_HEAD_INITIALIZER(qemu_gluster_create_opts.head),
-    .desc = {
-        {
-            .name = BLOCK_OPT_SIZE,
-            .type = QEMU_OPT_SIZE,
-            .help = "Virtual disk size"
-        },
-        {
-            .name = BLOCK_OPT_PREALLOC,
-            .type = QEMU_OPT_STRING,
-            .help = "Preallocation mode (allowed values: off"
-#ifdef CONFIG_GLUSTERFS_FALLOCATE
-                    ", falloc"
-#endif
-#ifdef CONFIG_GLUSTERFS_ZEROFILL
-                    ", full"
-#endif
-                    ")"
-        },
-        {
-            .name = GLUSTER_OPT_DEBUG,
-            .type = QEMU_OPT_NUMBER,
-            .help = "Gluster log level, valid range is 0-9",
-        },
-        {
-            .name = GLUSTER_OPT_LOGFILE,
-            .type = QEMU_OPT_STRING,
-            .help = "Logfile path of libgfapi",
-        },
-        { /* end of list */ }
-    }
-};
-
-static QemuOptsList runtime_opts = {
-    .name = "gluster",
-    .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
-    .desc = {
-        {
-            .name = GLUSTER_OPT_FILENAME,
-            .type = QEMU_OPT_STRING,
-            .help = "URL to the gluster image",
-        },
-        {
-            .name = GLUSTER_OPT_DEBUG,
-            .type = QEMU_OPT_NUMBER,
-            .help = "Gluster log level, valid range is 0-9",
-        },
-        {
-            .name = GLUSTER_OPT_LOGFILE,
-            .type = QEMU_OPT_STRING,
-            .help = "Logfile path of libgfapi",
-        },
-        { /* end of list */ }
-    },
-};
-
-static QemuOptsList runtime_json_opts = {
-    .name = "gluster_json",
-    .head = QTAILQ_HEAD_INITIALIZER(runtime_json_opts.head),
-    .desc = {
-        {
-            .name = GLUSTER_OPT_VOLUME,
-            .type = QEMU_OPT_STRING,
-            .help = "name of gluster volume where VM image resides",
-        },
-        {
-            .name = GLUSTER_OPT_PATH,
-            .type = QEMU_OPT_STRING,
-            .help = "absolute path to image file in gluster volume",
-        },
-        {
-            .name = GLUSTER_OPT_DEBUG,
-            .type = QEMU_OPT_NUMBER,
-            .help = "Gluster log level, valid range is 0-9",
-        },
-        { /* end of list */ }
-    },
-};
-
-static QemuOptsList runtime_type_opts = {
-    .name = "gluster_type",
-    .head = QTAILQ_HEAD_INITIALIZER(runtime_type_opts.head),
-    .desc = {
-        {
-            .name = GLUSTER_OPT_TYPE,
-            .type = QEMU_OPT_STRING,
-            .help = "inet|unix",
-        },
-        { /* end of list */ }
-    },
-};
-
-static QemuOptsList runtime_unix_opts = {
-    .name = "gluster_unix",
-    .head = QTAILQ_HEAD_INITIALIZER(runtime_unix_opts.head),
-    .desc = {
-        {
-            .name = GLUSTER_OPT_SOCKET,
-            .type = QEMU_OPT_STRING,
-            .help = "socket file path (legacy)",
-        },
-        {
-            .name = GLUSTER_OPT_PATH,
-            .type = QEMU_OPT_STRING,
-            .help = "socket file path (QAPI)",
-        },
-        { /* end of list */ }
-    },
-};
-
-static QemuOptsList runtime_inet_opts = {
-    .name = "gluster_inet",
-    .head = QTAILQ_HEAD_INITIALIZER(runtime_inet_opts.head),
-    .desc = {
-        {
-            .name = GLUSTER_OPT_TYPE,
-            .type = QEMU_OPT_STRING,
-            .help = "inet|unix",
-        },
-        {
-            .name = GLUSTER_OPT_HOST,
-            .type = QEMU_OPT_STRING,
-            .help = "host address (hostname/ipv4/ipv6 addresses)",
-        },
-        {
-            .name = GLUSTER_OPT_PORT,
-            .type = QEMU_OPT_STRING,
-            .help = "port number on which glusterd is listening (default 24007)",
-        },
-        {
-            .name = "to",
-            .type = QEMU_OPT_NUMBER,
-            .help = "max port number, not supported by gluster",
-        },
-        {
-            .name = "ipv4",
-            .type = QEMU_OPT_BOOL,
-            .help = "ipv4 bool value, not supported by gluster",
-        },
-        {
-            .name = "ipv6",
-            .type = QEMU_OPT_BOOL,
-            .help = "ipv6 bool value, not supported by gluster",
-        },
-        { /* end of list */ }
-    },
-};
-
-static void glfs_set_preopened(const char *volume, glfs_t *fs)
-{
-    ListElement *entry = NULL;
-
-    entry = g_new(ListElement, 1);
-
-    entry->saved.volume = g_strdup(volume);
-
-    entry->saved.fs = fs;
-    entry->saved.ref = 1;
-
-    QLIST_INSERT_HEAD(&glfs_list, entry, list);
-}
-
-static glfs_t *glfs_find_preopened(const char *volume)
-{
-    ListElement *entry;
-
-     QLIST_FOREACH(entry, &glfs_list, list) {
-        if (strcmp(entry->saved.volume, volume) == 0) {
-            entry->saved.ref++;
-            return entry->saved.fs;
-        }
-     }
-
-    return NULL;
-}
-
-static void glfs_clear_preopened(glfs_t *fs)
-{
-    ListElement *entry;
-    ListElement *next;
-
-    if (fs == NULL) {
-        return;
-    }
-
-    QLIST_FOREACH_SAFE(entry, &glfs_list, list, next) {
-        if (entry->saved.fs == fs) {
-            if (--entry->saved.ref) {
-                return;
-            }
-
-            QLIST_REMOVE(entry, list);
-
-            glfs_fini(entry->saved.fs);
-            g_free(entry->saved.volume);
-            g_free(entry);
-        }
-    }
-}
-
-static int parse_volume_options(BlockdevOptionsGluster *gconf, const char *path)
-{
-    const char *p, *q;
-
-    if (!path) {
-        return -EINVAL;
-    }
-
-    /* volume */
-    p = q = path + strspn(path, "/");
-    p += strcspn(p, "/");
-    if (*p == '\0') {
-        return -EINVAL;
-    }
-    gconf->volume = g_strndup(q, p - q);
-
-    /* path */
-    p += strspn(p, "/");
-    if (*p == '\0') {
-        return -EINVAL;
-    }
-    gconf->path = g_strdup(p);
-    return 0;
-}
-
-/*
- * file=gluster[+transport]://[host[:port]]/volume/path[?socket=...]
- *
- * 'gluster' is the protocol.
- *
- * 'transport' specifies the transport type used to connect to gluster
- * management daemon (glusterd). Valid transport types are
- * tcp or unix. If a transport type isn't specified, then tcp type is assumed.
- *
- * 'host' specifies the host where the volume file specification for
- * the given volume resides. This can be either hostname or ipv4 address.
- * If transport type is 'unix', then 'host' field should not be specified.
- * The 'socket' field needs to be populated with the path to unix domain
- * socket.
- *
- * 'port' is the port number on which glusterd is listening. This is optional
- * and if not specified, QEMU will send 0 which will make gluster to use the
- * default port. If the transport type is unix, then 'port' should not be
- * specified.
- *
- * 'volume' is the name of the gluster volume which contains the VM image.
- *
- * 'path' is the path to the actual VM image that resides on gluster volume.
- *
- * Examples:
- *
- * file=gluster://1.2.3.4/testvol/a.img
- * file=gluster+tcp://1.2.3.4/testvol/a.img
- * file=gluster+tcp://1.2.3.4:24007/testvol/dir/a.img
- * file=gluster+tcp://host.domain.com:24007/testvol/dir/a.img
- * file=gluster+unix:///testvol/dir/a.img?socket=/tmp/glusterd.socket
- */
-static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf,
-                                  const char *filename)
-{
-    g_autoptr(GUri) uri = g_uri_parse(filename, G_URI_FLAGS_NONE, NULL);
-    g_autoptr(GHashTable) qp = NULL;
-    SocketAddress *gsconf;
-    bool is_unix = false;
-    const char *uri_scheme, *uri_query, *uri_server;
-    int uri_port, ret;
-
-    if (!uri) {
-        return -EINVAL;
-    }
-
-    gsconf = g_new0(SocketAddress, 1);
-    QAPI_LIST_PREPEND(gconf->server, gsconf);
-
-    /* transport */
-    uri_scheme = g_uri_get_scheme(uri);
-    if (!uri_scheme || !strcmp(uri_scheme, "gluster")) {
-        gsconf->type = SOCKET_ADDRESS_TYPE_INET;
-    } else if (!strcmp(uri_scheme, "gluster+tcp")) {
-        gsconf->type = SOCKET_ADDRESS_TYPE_INET;
-    } else if (!strcmp(uri_scheme, "gluster+unix")) {
-        gsconf->type = SOCKET_ADDRESS_TYPE_UNIX;
-        is_unix = true;
-    } else {
-        return -EINVAL;
-    }
-
-    ret = parse_volume_options(gconf, g_uri_get_path(uri));
-    if (ret < 0) {
-        return ret;
-    }
-
-    uri_query = g_uri_get_query(uri);
-    if (uri_query) {
-        qp = g_uri_parse_params(uri_query, -1, "&", G_URI_PARAMS_NONE, NULL);
-        if (!qp) {
-            return -EINVAL;
-        }
-        ret = g_hash_table_size(qp);
-        if (ret > 1 || (is_unix && !ret) || (!is_unix && ret)) {
-            return -EINVAL;
-        }
-    }
-
-    uri_server = g_uri_get_host(uri);
-    uri_port = g_uri_get_port(uri);
-
-    if (is_unix) {
-        char *uri_socket = g_hash_table_lookup(qp, "socket");
-        if (uri_server || uri_port != -1 || !uri_socket) {
-            return -EINVAL;
-        }
-        gsconf->u.q_unix.path = g_strdup(uri_socket);
-    } else {
-        gsconf->u.inet.host = g_strdup(uri_server ? uri_server : "localhost");
-        if (uri_port > 0) {
-            gsconf->u.inet.port = g_strdup_printf("%d", uri_port);
-        } else {
-            gsconf->u.inet.port = g_strdup_printf("%d", GLUSTER_DEFAULT_PORT);
-        }
-    }
-
-    return 0;
-}
-
-static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
-                                           Error **errp)
-{
-    struct glfs *glfs;
-    int ret;
-    int old_errno;
-    SocketAddressList *server;
-    uint64_t port;
-
-    glfs = glfs_find_preopened(gconf->volume);
-    if (glfs) {
-        return glfs;
-    }
-
-    glfs = glfs_new(gconf->volume);
-    if (!glfs) {
-        goto out;
-    }
-
-    glfs_set_preopened(gconf->volume, glfs);
-
-    for (server = gconf->server; server; server = server->next) {
-        switch (server->value->type) {
-        case SOCKET_ADDRESS_TYPE_UNIX:
-            ret = glfs_set_volfile_server(glfs, "unix",
-                                   server->value->u.q_unix.path, 0);
-            break;
-        case SOCKET_ADDRESS_TYPE_INET:
-            if (parse_uint_full(server->value->u.inet.port, 10, &port) < 0 ||
-                port > 65535) {
-                error_setg(errp, "'%s' is not a valid port number",
-                           server->value->u.inet.port);
-                errno = EINVAL;
-                goto out;
-            }
-            ret = glfs_set_volfile_server(glfs, "tcp",
-                                   server->value->u.inet.host,
-                                   (int)port);
-            break;
-        case SOCKET_ADDRESS_TYPE_VSOCK:
-        case SOCKET_ADDRESS_TYPE_FD:
-        default:
-            abort();
-        }
-
-        if (ret < 0) {
-            goto out;
-        }
-    }
-
-    ret = glfs_set_logging(glfs, gconf->logfile, gconf->debug);
-    if (ret < 0) {
-        goto out;
-    }
-
-    ret = glfs_init(glfs);
-    if (ret) {
-        error_setg(errp, "Gluster connection for volume %s, path %s failed"
-                         " to connect", gconf->volume, gconf->path);
-        for (server = gconf->server; server; server = server->next) {
-            if (server->value->type  == SOCKET_ADDRESS_TYPE_UNIX) {
-                error_append_hint(errp, "hint: failed on socket %s ",
-                                  server->value->u.q_unix.path);
-            } else {
-                error_append_hint(errp, "hint: failed on host %s and port %s ",
-                                  server->value->u.inet.host,
-                                  server->value->u.inet.port);
-            }
-        }
-
-        error_append_hint(errp, "Please refer to gluster logs for more info\n");
-
-        /* glfs_init sometimes doesn't set errno although docs suggest that */
-        if (errno == 0) {
-            errno = EINVAL;
-        }
-
-        goto out;
-    }
-    return glfs;
-
-out:
-    if (glfs) {
-        old_errno = errno;
-        glfs_clear_preopened(glfs);
-        errno = old_errno;
-    }
-    return NULL;
-}
-
-/*
- * Convert the json formatted command line into qapi.
-*/
-static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
-                                  QDict *options, Error **errp)
-{
-    QemuOpts *opts;
-    SocketAddress *gsconf = NULL;
-    SocketAddressList **tail;
-    QDict *backing_options = NULL;
-    Error *local_err = NULL;
-    const char *ptr;
-    int i, type, num_servers;
-
-    /* create opts info from runtime_json_opts list */
-    opts = qemu_opts_create(&runtime_json_opts, NULL, 0, &error_abort);
-    if (!qemu_opts_absorb_qdict(opts, options, errp)) {
-        goto out;
-    }
-
-    num_servers = qdict_array_entries(options, GLUSTER_OPT_SERVER_PATTERN);
-    if (num_servers < 1) {
-        error_setg(&local_err, QERR_MISSING_PARAMETER, "server");
-        goto out;
-    }
-
-    ptr = qemu_opt_get(opts, GLUSTER_OPT_VOLUME);
-    if (!ptr) {
-        error_setg(&local_err, QERR_MISSING_PARAMETER, GLUSTER_OPT_VOLUME);
-        goto out;
-    }
-    gconf->volume = g_strdup(ptr);
-
-    ptr = qemu_opt_get(opts, GLUSTER_OPT_PATH);
-    if (!ptr) {
-        error_setg(&local_err, QERR_MISSING_PARAMETER, GLUSTER_OPT_PATH);
-        goto out;
-    }
-    gconf->path = g_strdup(ptr);
-    qemu_opts_del(opts);
-    tail = &gconf->server;
-
-    for (i = 0; i < num_servers; i++) {
-        g_autofree char *str = g_strdup_printf(GLUSTER_OPT_SERVER_PATTERN"%d.",
-                                               i);
-        qdict_extract_subqdict(options, &backing_options, str);
-
-        /* create opts info from runtime_type_opts list */
-        opts = qemu_opts_create(&runtime_type_opts, NULL, 0, &error_abort);
-        if (!qemu_opts_absorb_qdict(opts, backing_options, errp)) {
-            goto out;
-        }
-
-        ptr = qemu_opt_get(opts, GLUSTER_OPT_TYPE);
-        if (!ptr) {
-            error_setg(&local_err, QERR_MISSING_PARAMETER, GLUSTER_OPT_TYPE);
-            error_append_hint(&local_err, GERR_INDEX_HINT, i);
-            goto out;
-
-        }
-        gsconf = g_new0(SocketAddress, 1);
-        if (!strcmp(ptr, "tcp")) {
-            ptr = "inet";       /* accept legacy "tcp" */
-        }
-        type = qapi_enum_parse(&SocketAddressType_lookup, ptr, -1, NULL);
-        if (type != SOCKET_ADDRESS_TYPE_INET
-            && type != SOCKET_ADDRESS_TYPE_UNIX) {
-            error_setg(&local_err,
-                       "Parameter '%s' may be 'inet' or 'unix'",
-                       GLUSTER_OPT_TYPE);
-            error_append_hint(&local_err, GERR_INDEX_HINT, i);
-            goto out;
-        }
-        gsconf->type = type;
-        qemu_opts_del(opts);
-
-        if (gsconf->type == SOCKET_ADDRESS_TYPE_INET) {
-            /* create opts info from runtime_inet_opts list */
-            opts = qemu_opts_create(&runtime_inet_opts, NULL, 0, &error_abort);
-            if (!qemu_opts_absorb_qdict(opts, backing_options, errp)) {
-                goto out;
-            }
-
-            ptr = qemu_opt_get(opts, GLUSTER_OPT_HOST);
-            if (!ptr) {
-                error_setg(&local_err, QERR_MISSING_PARAMETER,
-                           GLUSTER_OPT_HOST);
-                error_append_hint(&local_err, GERR_INDEX_HINT, i);
-                goto out;
-            }
-            gsconf->u.inet.host = g_strdup(ptr);
-            ptr = qemu_opt_get(opts, GLUSTER_OPT_PORT);
-            if (!ptr) {
-                error_setg(&local_err, QERR_MISSING_PARAMETER,
-                           GLUSTER_OPT_PORT);
-                error_append_hint(&local_err, GERR_INDEX_HINT, i);
-                goto out;
-            }
-            gsconf->u.inet.port = g_strdup(ptr);
-
-            /* defend for unsupported fields in InetSocketAddress,
-             * i.e. @ipv4, @ipv6  and @to
-             */
-            ptr = qemu_opt_get(opts, GLUSTER_OPT_TO);
-            if (ptr) {
-                gsconf->u.inet.has_to = true;
-            }
-            ptr = qemu_opt_get(opts, GLUSTER_OPT_IPV4);
-            if (ptr) {
-                gsconf->u.inet.has_ipv4 = true;
-            }
-            ptr = qemu_opt_get(opts, GLUSTER_OPT_IPV6);
-            if (ptr) {
-                gsconf->u.inet.has_ipv6 = true;
-            }
-            if (gsconf->u.inet.has_to) {
-                error_setg(&local_err, "Parameter 'to' not supported");
-                goto out;
-            }
-            if (gsconf->u.inet.has_ipv4 || gsconf->u.inet.has_ipv6) {
-                error_setg(&local_err, "Parameters 'ipv4/ipv6' not supported");
-                goto out;
-            }
-            qemu_opts_del(opts);
-        } else {
-            /* create opts info from runtime_unix_opts list */
-            opts = qemu_opts_create(&runtime_unix_opts, NULL, 0, &error_abort);
-            if (!qemu_opts_absorb_qdict(opts, backing_options, errp)) {
-                goto out;
-            }
-
-            ptr = qemu_opt_get(opts, GLUSTER_OPT_PATH);
-            if (!ptr) {
-                ptr = qemu_opt_get(opts, GLUSTER_OPT_SOCKET);
-            } else if (qemu_opt_get(opts, GLUSTER_OPT_SOCKET)) {
-                error_setg(&local_err,
-                           "Conflicting parameters 'path' and 'socket'");
-                error_append_hint(&local_err, GERR_INDEX_HINT, i);
-                goto out;
-            }
-            if (!ptr) {
-                error_setg(&local_err, QERR_MISSING_PARAMETER,
-                           GLUSTER_OPT_PATH);
-                error_append_hint(&local_err, GERR_INDEX_HINT, i);
-                goto out;
-            }
-            gsconf->u.q_unix.path = g_strdup(ptr);
-            qemu_opts_del(opts);
-        }
-
-        QAPI_LIST_APPEND(tail, gsconf);
-        gsconf = NULL;
-
-        qobject_unref(backing_options);
-        backing_options = NULL;
-    }
-
-    return 0;
-
-out:
-    error_propagate(errp, local_err);
-    qapi_free_SocketAddress(gsconf);
-    qemu_opts_del(opts);
-    qobject_unref(backing_options);
-    errno = EINVAL;
-    return -errno;
-}
-
-/* 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) {
-        ret = qemu_gluster_parse_uri(gconf, filename);
-        if (ret < 0) {
-            error_setg(errp, "invalid URI %s", filename);
-            error_append_hint(errp, "Usage: file=gluster[+transport]://"
-                                    "[host[:port]]volume/path[?socket=...]"
-                                    "[,file.debug=N]"
-                                    "[,file.logfile=/path/filename.log]\n");
-            return ret;
-        }
-    } else {
-        ret = qemu_gluster_parse_json(gconf, options, errp);
-        if (ret < 0) {
-            error_append_hint(errp, "Usage: "
-                             "-drive driver=qcow2,file.driver=gluster,"
-                             "file.volume=testvol,file.path=/path/a.qcow2"
-                             "[,file.debug=9]"
-                             "[,file.logfile=/path/filename.log],"
-                             "file.server.0.type=inet,"
-                             "file.server.0.host=1.2.3.4,"
-                             "file.server.0.port=24007,"
-                             "file.server.1.transport=unix,"
-                             "file.server.1.path=/var/run/glusterd.socket ..."
-                             "\n");
-            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);
-}
-
-/*
- * AIO callback routine called from GlusterFS thread.
- */
-static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret,
-#ifdef CONFIG_GLUSTERFS_IOCB_HAS_STAT
-                                 struct glfs_stat *pre, struct glfs_stat *post,
-#endif
-                                 void *arg)
-{
-    GlusterAIOCB *acb = (GlusterAIOCB *)arg;
-
-    if (!ret || ret == acb->size) {
-        acb->ret = 0; /* Success */
-    } else if (ret < 0) {
-        acb->ret = -errno; /* Read/Write failed */
-    } else {
-        acb->ret = -EIO; /* Partial read/write - fail it */
-    }
-
-    /*
-     * Safe to call: The coroutine will yield exactly once awaiting this
-     * scheduling, and the context is its own context, so it will be scheduled
-     * once it does yield.
-     *
-     * (aio_co_wake() would call qemu_get_current_aio_context() to check whether
-     * we are in the same context, but we are not in a qemu thread, so we cannot
-     * do that.  Use aio_co_schedule() directly.)
-     */
-    aio_co_schedule(qemu_coroutine_get_aio_context(acb->coroutine),
-                    acb->coroutine);
-}
-
-static void qemu_gluster_parse_flags(int bdrv_flags, int *open_flags)
-{
-    assert(open_flags != NULL);
-
-    *open_flags |= O_BINARY;
-
-    if (bdrv_flags & BDRV_O_RDWR) {
-        *open_flags |= O_RDWR;
-    } else {
-        *open_flags |= O_RDONLY;
-    }
-
-    if ((bdrv_flags & BDRV_O_NOCACHE)) {
-        *open_flags |= O_DIRECT;
-    }
-}
-
-/*
- * Do SEEK_DATA/HOLE to detect if it is functional. Older broken versions of
- * gfapi incorrectly return the current offset when SEEK_DATA/HOLE is used.
- * - Corrected versions return -1 and set errno to EINVAL.
- * - Versions that support SEEK_DATA/HOLE correctly, will return -1 and set
- *   errno to ENXIO when SEEK_DATA is called with a position of EOF.
- */
-static bool qemu_gluster_test_seek(struct glfs_fd *fd)
-{
-    off_t ret = 0;
-
-#if defined SEEK_HOLE && defined SEEK_DATA
-    off_t eof;
-
-    eof = glfs_lseek(fd, 0, SEEK_END);
-    if (eof < 0) {
-        /* this should never occur */
-        return false;
-    }
-
-    /* this should always fail with ENXIO if SEEK_DATA is supported */
-    ret = glfs_lseek(fd, eof, SEEK_DATA);
-#endif
-
-    return (ret < 0) && (errno == ENXIO);
-}
-
-static int qemu_gluster_open(BlockDriverState *bs,  QDict *options,
-                             int bdrv_flags, Error **errp)
-{
-    BDRVGlusterState *s = bs->opaque;
-    int open_flags = 0;
-    int ret = 0;
-    BlockdevOptionsGluster *gconf = NULL;
-    QemuOpts *opts;
-    const char *filename, *logfile;
-
-    opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
-    if (!qemu_opts_absorb_qdict(opts, options, errp)) {
-        ret = -EINVAL;
-        goto out;
-    }
-
-    warn_report_once("'gluster' is deprecated");
-
-    filename = qemu_opt_get(opts, GLUSTER_OPT_FILENAME);
-
-    s->debug = qemu_opt_get_number(opts, GLUSTER_OPT_DEBUG,
-                                   GLUSTER_DEBUG_DEFAULT);
-    if (s->debug < 0) {
-        s->debug = 0;
-    } else if (s->debug > GLUSTER_DEBUG_MAX) {
-        s->debug = GLUSTER_DEBUG_MAX;
-    }
-
-    gconf = g_new0(BlockdevOptionsGluster, 1);
-    gconf->debug = s->debug;
-    gconf->has_debug = true;
-
-    logfile = qemu_opt_get(opts, GLUSTER_OPT_LOGFILE);
-    s->logfile = g_strdup(logfile ? logfile : GLUSTER_LOGFILE_DEFAULT);
-
-    gconf->logfile = g_strdup(s->logfile);
-
-    s->glfs = qemu_gluster_init(gconf, filename, options, errp);
-    if (!s->glfs) {
-        ret = -errno;
-        goto out;
-    }
-
-#ifdef CONFIG_GLUSTERFS_XLATOR_OPT
-    /* Without this, if fsync fails for a recoverable reason (for instance,
-     * ENOSPC), gluster will dump its cache, preventing retries.  This means
-     * almost certain data loss.  Not all gluster versions support the
-     * 'resync-failed-syncs-after-fsync' key value, but there is no way to
-     * discover during runtime if it is supported (this api returns success for
-     * unknown key/value pairs) */
-    ret = glfs_set_xlator_option(s->glfs, "*-write-behind",
-                                          "resync-failed-syncs-after-fsync",
-                                          "on");
-    if (ret < 0) {
-        error_setg_errno(errp, errno, "Unable to set xlator key/value pair");
-        ret = -errno;
-        goto out;
-    }
-#endif
-
-    qemu_gluster_parse_flags(bdrv_flags, &open_flags);
-
-    s->fd = glfs_open(s->glfs, gconf->path, open_flags);
-    ret = s->fd ? 0 : -errno;
-
-    if (ret == -EACCES || ret == -EROFS) {
-        /* Try to degrade to read-only, but if it doesn't work, still use the
-         * normal error message. */
-        bdrv_graph_rdlock_main_loop();
-        if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) {
-            open_flags = (open_flags & ~O_RDWR) | O_RDONLY;
-            s->fd = glfs_open(s->glfs, gconf->path, open_flags);
-            ret = s->fd ? 0 : -errno;
-        }
-        bdrv_graph_rdunlock_main_loop();
-    }
-
-    s->supports_seek_data = qemu_gluster_test_seek(s->fd);
-
-out:
-    qemu_opts_del(opts);
-    qapi_free_BlockdevOptionsGluster(gconf);
-    if (!ret) {
-        return ret;
-    }
-    g_free(s->logfile);
-    if (s->fd) {
-        glfs_close(s->fd);
-    }
-
-    glfs_clear_preopened(s->glfs);
-
-    return ret;
-}
-
-static void qemu_gluster_refresh_limits(BlockDriverState *bs, Error **errp)
-{
-    bs->bl.max_transfer = GLUSTER_MAX_TRANSFER;
-    bs->bl.max_pdiscard = MIN(SIZE_MAX, INT64_MAX);
-}
-
-static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
-                                       BlockReopenQueue *queue, Error **errp)
-{
-    int ret = 0;
-    BDRVGlusterState *s;
-    BDRVGlusterReopenState *reop_s;
-    BlockdevOptionsGluster *gconf;
-    int open_flags = 0;
-
-    assert(state != NULL);
-    assert(state->bs != NULL);
-
-    s = state->bs->opaque;
-
-    state->opaque = g_new0(BDRVGlusterReopenState, 1);
-    reop_s = state->opaque;
-
-    qemu_gluster_parse_flags(state->flags, &open_flags);
-
-    gconf = g_new0(BlockdevOptionsGluster, 1);
-    gconf->debug = s->debug;
-    gconf->has_debug = true;
-    gconf->logfile = g_strdup(s->logfile);
-
-    /*
-     * If 'state->bs->exact_filename' is empty, 'state->options' should contain
-     * the JSON parameters already parsed.
-     */
-    if (state->bs->exact_filename[0] != '\0') {
-        reop_s->glfs = qemu_gluster_init(gconf, state->bs->exact_filename, NULL,
-                                         errp);
-    } else {
-        reop_s->glfs = qemu_gluster_init(gconf, NULL, state->options, errp);
-    }
-    if (reop_s->glfs == NULL) {
-        ret = -errno;
-        goto exit;
-    }
-
-#ifdef CONFIG_GLUSTERFS_XLATOR_OPT
-    ret = glfs_set_xlator_option(reop_s->glfs, "*-write-behind",
-                                 "resync-failed-syncs-after-fsync", "on");
-    if (ret < 0) {
-        error_setg_errno(errp, errno, "Unable to set xlator key/value pair");
-        ret = -errno;
-        goto exit;
-    }
-#endif
-
-    reop_s->fd = glfs_open(reop_s->glfs, gconf->path, open_flags);
-    if (reop_s->fd == NULL) {
-        /* reops->glfs will be cleaned up in _abort */
-        ret = -errno;
-        goto exit;
-    }
-
-exit:
-    /* state->opaque will be freed in either the _abort or _commit */
-    qapi_free_BlockdevOptionsGluster(gconf);
-    return ret;
-}
-
-static void qemu_gluster_reopen_commit(BDRVReopenState *state)
-{
-    BDRVGlusterReopenState *reop_s = state->opaque;
-    BDRVGlusterState *s = state->bs->opaque;
-
-
-    /* close the old */
-    if (s->fd) {
-        glfs_close(s->fd);
-    }
-
-    glfs_clear_preopened(s->glfs);
-
-    /* use the newly opened image / connection */
-    s->fd         = reop_s->fd;
-    s->glfs       = reop_s->glfs;
-
-    g_free(state->opaque);
-    state->opaque = NULL;
-}
-
-
-static void qemu_gluster_reopen_abort(BDRVReopenState *state)
-{
-    BDRVGlusterReopenState *reop_s = state->opaque;
-
-    if (reop_s == NULL) {
-        return;
-    }
-
-    if (reop_s->fd) {
-        glfs_close(reop_s->fd);
-    }
-
-    glfs_clear_preopened(reop_s->glfs);
-
-    g_free(state->opaque);
-    state->opaque = NULL;
-}
-
-#ifdef CONFIG_GLUSTERFS_ZEROFILL
-static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs,
-                                                      int64_t offset,
-                                                      int64_t bytes,
-                                                      BdrvRequestFlags flags)
-{
-    int ret;
-    GlusterAIOCB acb;
-    BDRVGlusterState *s = bs->opaque;
-
-    acb.size = bytes;
-    acb.ret = 0;
-    acb.coroutine = qemu_coroutine_self();
-
-    ret = glfs_zerofill_async(s->fd, offset, bytes, gluster_finish_aiocb, &acb);
-    if (ret < 0) {
-        return -errno;
-    }
-
-    qemu_coroutine_yield();
-    return acb.ret;
-}
-#endif
-
-static int qemu_gluster_do_truncate(struct glfs_fd *fd, int64_t offset,
-                                    PreallocMode prealloc, Error **errp)
-{
-    int64_t current_length;
-
-    current_length = glfs_lseek(fd, 0, SEEK_END);
-    if (current_length < 0) {
-        error_setg_errno(errp, errno, "Failed to determine current size");
-        return -errno;
-    }
-
-    if (current_length > offset && prealloc != PREALLOC_MODE_OFF) {
-        error_setg(errp, "Cannot use preallocation for shrinking files");
-        return -ENOTSUP;
-    }
-
-    if (current_length == offset) {
-        return 0;
-    }
-
-    switch (prealloc) {
-#ifdef CONFIG_GLUSTERFS_FALLOCATE
-    case PREALLOC_MODE_FALLOC:
-        if (glfs_fallocate(fd, 0, current_length, offset - current_length)) {
-            error_setg_errno(errp, errno, "Could not preallocate data");
-            return -errno;
-        }
-        break;
-#endif /* CONFIG_GLUSTERFS_FALLOCATE */
-#ifdef CONFIG_GLUSTERFS_ZEROFILL
-    case PREALLOC_MODE_FULL:
-        if (glfs_ftruncate(fd, offset)) {
-            error_setg_errno(errp, errno, "Could not resize file");
-            return -errno;
-        }
-        if (glfs_zerofill(fd, current_length, offset - current_length)) {
-            error_setg_errno(errp, errno, "Could not zerofill the new area");
-            return -errno;
-        }
-        break;
-#endif /* CONFIG_GLUSTERFS_ZEROFILL */
-    case PREALLOC_MODE_OFF:
-        if (glfs_ftruncate(fd, offset)) {
-            error_setg_errno(errp, errno, "Could not resize file");
-            return -errno;
-        }
-        break;
-    default:
-        error_setg(errp, "Unsupported preallocation mode: %s",
-                   PreallocMode_str(prealloc));
-        return -EINVAL;
-    }
-
-    return 0;
-}
-
-static int qemu_gluster_co_create(BlockdevCreateOptions *options,
-                                  Error **errp)
-{
-    BlockdevCreateOptionsGluster *opts = &options->u.gluster;
-    struct glfs *glfs;
-    struct glfs_fd *fd = NULL;
-    int ret = 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 coroutine_fn qemu_gluster_co_create_opts(BlockDriver *drv,
-                                                    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) {
-        gconf->debug = 0;
-    } else if (gconf->debug > GLUSTER_DEBUG_MAX) {
-        gconf->debug = GLUSTER_DEBUG_MAX;
-    }
-    gconf->has_debug = true;
-
-    gconf->logfile = qemu_opt_get_del(opts, GLUSTER_OPT_LOGFILE);
-    if (!gconf->logfile) {
-        gconf->logfile = g_strdup(GLUSTER_LOGFILE_DEFAULT);
-    }
-
-    ret = qemu_gluster_parse(gconf, filename, NULL, errp);
-    if (ret < 0) {
-        goto fail;
-    }
-
-    ret = qemu_gluster_co_create(options, errp);
-    if (ret < 0) {
-        goto fail;
-    }
-
-    ret = 0;
-fail:
-    qapi_free_BlockdevCreateOptions(options);
-    return ret;
-}
-
-static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
-                                           int64_t sector_num, int nb_sectors,
-                                           QEMUIOVector *qiov, int write)
-{
-    int ret;
-    GlusterAIOCB acb;
-    BDRVGlusterState *s = bs->opaque;
-    size_t size = nb_sectors * BDRV_SECTOR_SIZE;
-    off_t offset = sector_num * BDRV_SECTOR_SIZE;
-
-    acb.size = size;
-    acb.ret = 0;
-    acb.coroutine = qemu_coroutine_self();
-
-    if (write) {
-        ret = glfs_pwritev_async(s->fd, qiov->iov, qiov->niov, offset, 0,
-                                 gluster_finish_aiocb, &acb);
-    } else {
-        ret = glfs_preadv_async(s->fd, qiov->iov, qiov->niov, offset, 0,
-                                gluster_finish_aiocb, &acb);
-    }
-
-    if (ret < 0) {
-        return -errno;
-    }
-
-    qemu_coroutine_yield();
-    return acb.ret;
-}
-
-static coroutine_fn int qemu_gluster_co_truncate(BlockDriverState *bs,
-                                                 int64_t offset,
-                                                 bool exact,
-                                                 PreallocMode prealloc,
-                                                 BdrvRequestFlags flags,
-                                                 Error **errp)
-{
-    BDRVGlusterState *s = bs->opaque;
-    return qemu_gluster_do_truncate(s->fd, offset, prealloc, errp);
-}
-
-static coroutine_fn int qemu_gluster_co_readv(BlockDriverState *bs,
-                                              int64_t sector_num,
-                                              int nb_sectors,
-                                              QEMUIOVector *qiov)
-{
-    return qemu_gluster_co_rw(bs, sector_num, nb_sectors, qiov, 0);
-}
-
-static coroutine_fn int qemu_gluster_co_writev(BlockDriverState *bs,
-                                               int64_t sector_num,
-                                               int nb_sectors,
-                                               QEMUIOVector *qiov,
-                                               int flags)
-{
-    return qemu_gluster_co_rw(bs, sector_num, nb_sectors, qiov, 1);
-}
-
-static void qemu_gluster_close(BlockDriverState *bs)
-{
-    BDRVGlusterState *s = bs->opaque;
-
-    g_free(s->logfile);
-    if (s->fd) {
-        glfs_close(s->fd);
-        s->fd = NULL;
-    }
-    glfs_clear_preopened(s->glfs);
-}
-
-static coroutine_fn int qemu_gluster_co_flush_to_disk(BlockDriverState *bs)
-{
-    int ret;
-    GlusterAIOCB acb;
-    BDRVGlusterState *s = bs->opaque;
-
-    acb.size = 0;
-    acb.ret = 0;
-    acb.coroutine = qemu_coroutine_self();
-
-    ret = glfs_fsync_async(s->fd, gluster_finish_aiocb, &acb);
-    if (ret < 0) {
-        ret = -errno;
-        goto error;
-    }
-
-    qemu_coroutine_yield();
-    if (acb.ret < 0) {
-        ret = acb.ret;
-        goto error;
-    }
-
-    return acb.ret;
-
-error:
-    /* Some versions of Gluster (3.5.6 -> 3.5.8?) will not retain its cache
-     * after a fsync failure, so we have no way of allowing the guest to safely
-     * continue.  Gluster versions prior to 3.5.6 don't retain the cache
-     * either, but will invalidate the fd on error, so this is again our only
-     * option.
-     *
-     * The 'resync-failed-syncs-after-fsync' xlator option for the
-     * write-behind cache will cause later gluster versions to retain its
-     * cache after error, so long as the fd remains open.  However, we
-     * currently have no way of knowing if this option is supported.
-     *
-     * TODO: Once gluster provides a way for us to determine if the option
-     * is supported, bypass the closure and setting drv to NULL.  */
-    qemu_gluster_close(bs);
-    bs->drv = NULL;
-    return ret;
-}
-
-#ifdef CONFIG_GLUSTERFS_DISCARD
-static coroutine_fn int qemu_gluster_co_pdiscard(BlockDriverState *bs,
-                                                 int64_t offset, int64_t bytes)
-{
-    int ret;
-    GlusterAIOCB acb;
-    BDRVGlusterState *s = bs->opaque;
-
-    assert(bytes <= SIZE_MAX); /* rely on max_pdiscard */
-
-    acb.size = 0;
-    acb.ret = 0;
-    acb.coroutine = qemu_coroutine_self();
-
-    ret = glfs_discard_async(s->fd, offset, bytes, gluster_finish_aiocb, &acb);
-    if (ret < 0) {
-        return -errno;
-    }
-
-    qemu_coroutine_yield();
-    return acb.ret;
-}
-#endif
-
-static int64_t coroutine_fn qemu_gluster_co_getlength(BlockDriverState *bs)
-{
-    BDRVGlusterState *s = bs->opaque;
-    int64_t ret;
-
-    ret = glfs_lseek(s->fd, 0, SEEK_END);
-    if (ret < 0) {
-        return -errno;
-    } else {
-        return ret;
-    }
-}
-
-static int64_t coroutine_fn
-qemu_gluster_co_get_allocated_file_size(BlockDriverState *bs)
-{
-    BDRVGlusterState *s = bs->opaque;
-    struct stat st;
-    int ret;
-
-    ret = glfs_fstat(s->fd, &st);
-    if (ret < 0) {
-        return -errno;
-    } else {
-        return st.st_blocks * 512;
-    }
-}
-
-/*
- * Find allocation range in @bs around offset @start.
- * May change underlying file descriptor's file offset.
- * If @start is not in a hole, store @start in @data, and the
- * beginning of the next hole in @hole, and return 0.
- * If @start is in a non-trailing hole, store @start in @hole and the
- * beginning of the next non-hole in @data, and return 0.
- * If @start is in a trailing hole or beyond EOF, return -ENXIO.
- * If we can't find out, return a negative errno other than -ENXIO.
- *
- * (Shamefully copied from file-posix.c, only minuscule adaptions.)
- */
-static int find_allocation(BlockDriverState *bs, off_t start,
-                           off_t *data, off_t *hole)
-{
-    BDRVGlusterState *s = bs->opaque;
-
-    if (!s->supports_seek_data) {
-        goto exit;
-    }
-
-#if defined SEEK_HOLE && defined SEEK_DATA
-    off_t offs;
-
-    /*
-     * SEEK_DATA cases:
-     * D1. offs == start: start is in data
-     * D2. offs > start: start is in a hole, next data at offs
-     * D3. offs < 0, errno = ENXIO: either start is in a trailing hole
-     *                              or start is beyond EOF
-     *     If the latter happens, the file has been truncated behind
-     *     our back since we opened it.  All bets are off then.
-     *     Treating like a trailing hole is simplest.
-     * D4. offs < 0, errno != ENXIO: we learned nothing
-     */
-    offs = glfs_lseek(s->fd, start, SEEK_DATA);
-    if (offs < 0) {
-        return -errno;          /* D3 or D4 */
-    }
-
-    if (offs < start) {
-        /* This is not a valid return by lseek().  We are safe to just return
-         * -EIO in this case, and we'll treat it like D4. Unfortunately some
-         *  versions of gluster server will return offs < start, so an assert
-         *  here will unnecessarily abort QEMU. */
-        return -EIO;
-    }
-
-    if (offs > start) {
-        /* D2: in hole, next data at offs */
-        *hole = start;
-        *data = offs;
-        return 0;
-    }
-
-    /* D1: in data, end not yet known */
-
-    /*
-     * SEEK_HOLE cases:
-     * H1. offs == start: start is in a hole
-     *     If this happens here, a hole has been dug behind our back
-     *     since the previous lseek().
-     * H2. offs > start: either start is in data, next hole at offs,
-     *                   or start is in trailing hole, EOF at offs
-     *     Linux treats trailing holes like any other hole: offs ==
-     *     start.  Solaris seeks to EOF instead: offs > start (blech).
-     *     If that happens here, a hole has been dug behind our back
-     *     since the previous lseek().
-     * H3. offs < 0, errno = ENXIO: start is beyond EOF
-     *     If this happens, the file has been truncated behind our
-     *     back since we opened it.  Treat it like a trailing hole.
-     * H4. offs < 0, errno != ENXIO: we learned nothing
-     *     Pretend we know nothing at all, i.e. "forget" about D1.
-     */
-    offs = glfs_lseek(s->fd, start, SEEK_HOLE);
-    if (offs < 0) {
-        return -errno;          /* D1 and (H3 or H4) */
-    }
-
-    if (offs < start) {
-        /* This is not a valid return by lseek().  We are safe to just return
-         * -EIO in this case, and we'll treat it like H4. Unfortunately some
-         *  versions of gluster server will return offs < start, so an assert
-         *  here will unnecessarily abort QEMU. */
-        return -EIO;
-    }
-
-    if (offs > start) {
-        /*
-         * D1 and H2: either in data, next hole at offs, or it was in
-         * data but is now in a trailing hole.  In the latter case,
-         * all bets are off.  Treating it as if it there was data all
-         * the way to EOF is safe, so simply do that.
-         */
-        *data = start;
-        *hole = offs;
-        return 0;
-    }
-
-    /* D1 and H1 */
-    return -EBUSY;
-#endif
-
-exit:
-    return -ENOTSUP;
-}
-
-/*
- * Returns the allocation status of the specified offset.
- *
- * The block layer guarantees 'offset' and 'bytes' are within bounds.
- *
- * 'pnum' is set to the number of bytes (including and immediately following
- * the specified offset) that are known to be in the same
- * allocated/unallocated state.
- *
- * 'bytes' is a soft cap for 'pnum'.  If the information is free, 'pnum' may
- * well exceed it.
- *
- * (Based on raw_co_block_status() from file-posix.c.)
- */
-static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs,
-                                                     unsigned int mode,
-                                                     int64_t offset,
-                                                     int64_t bytes,
-                                                     int64_t *pnum,
-                                                     int64_t *map,
-                                                     BlockDriverState **file)
-{
-    BDRVGlusterState *s = bs->opaque;
-    off_t data = 0, hole = 0;
-    int ret = -EINVAL;
-
-    assert(QEMU_IS_ALIGNED(offset | bytes, bs->bl.request_alignment));
-
-    if (!s->fd) {
-        return ret;
-    }
-
-    if (!(mode & BDRV_WANT_ZERO)) {
-        *pnum = bytes;
-        *map = offset;
-        *file = bs;
-        return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
-    }
-
-    ret = find_allocation(bs, offset, &data, &hole);
-    if (ret == -ENXIO) {
-        /* Trailing hole */
-        *pnum = bytes;
-        ret = BDRV_BLOCK_ZERO;
-    } else if (ret < 0) {
-        /* No info available, so pretend there are no holes */
-        *pnum = bytes;
-        ret = BDRV_BLOCK_DATA;
-    } else if (data == offset) {
-        /* On a data extent, compute bytes to the end of the extent,
-         * possibly including a partial sector at EOF. */
-        *pnum = hole - offset;
-
-        /*
-         * We are not allowed to return partial sectors, though, so
-         * round up if necessary.
-         */
-        if (!QEMU_IS_ALIGNED(*pnum, bs->bl.request_alignment)) {
-            int64_t file_length = qemu_gluster_co_getlength(bs);
-            if (file_length > 0) {
-                /* Ignore errors, this is just a safeguard */
-                assert(hole == file_length);
-            }
-            *pnum = ROUND_UP(*pnum, bs->bl.request_alignment);
-        }
-
-        ret = BDRV_BLOCK_DATA;
-    } else {
-        /* On a hole, compute bytes to the beginning of the next extent.  */
-        assert(hole == offset);
-        *pnum = data - offset;
-        ret = BDRV_BLOCK_ZERO;
-    }
-
-    *map = offset;
-    *file = bs;
-
-    return ret | BDRV_BLOCK_OFFSET_VALID;
-}
-
-
-static const char *const gluster_strong_open_opts[] = {
-    GLUSTER_OPT_VOLUME,
-    GLUSTER_OPT_PATH,
-    GLUSTER_OPT_TYPE,
-    GLUSTER_OPT_SERVER_PATTERN,
-    GLUSTER_OPT_HOST,
-    GLUSTER_OPT_PORT,
-    GLUSTER_OPT_TO,
-    GLUSTER_OPT_IPV4,
-    GLUSTER_OPT_IPV6,
-    GLUSTER_OPT_SOCKET,
-
-    NULL
-};
-
-static BlockDriver bdrv_gluster = {
-    .format_name                  = "gluster",
-    .protocol_name                = "gluster",
-    .instance_size                = sizeof(BDRVGlusterState),
-    .bdrv_open                    = qemu_gluster_open,
-    .bdrv_reopen_prepare          = qemu_gluster_reopen_prepare,
-    .bdrv_reopen_commit           = qemu_gluster_reopen_commit,
-    .bdrv_reopen_abort            = qemu_gluster_reopen_abort,
-    .bdrv_close                   = qemu_gluster_close,
-    .bdrv_co_create               = qemu_gluster_co_create,
-    .bdrv_co_create_opts          = qemu_gluster_co_create_opts,
-    .bdrv_co_getlength            = qemu_gluster_co_getlength,
-    .bdrv_co_get_allocated_file_size = qemu_gluster_co_get_allocated_file_size,
-    .bdrv_co_truncate             = qemu_gluster_co_truncate,
-    .bdrv_co_readv                = qemu_gluster_co_readv,
-    .bdrv_co_writev               = qemu_gluster_co_writev,
-    .bdrv_co_flush_to_disk        = qemu_gluster_co_flush_to_disk,
-#ifdef CONFIG_GLUSTERFS_DISCARD
-    .bdrv_co_pdiscard             = qemu_gluster_co_pdiscard,
-#endif
-#ifdef CONFIG_GLUSTERFS_ZEROFILL
-    .bdrv_co_pwrite_zeroes        = qemu_gluster_co_pwrite_zeroes,
-#endif
-    .bdrv_co_block_status         = qemu_gluster_co_block_status,
-    .bdrv_refresh_limits          = qemu_gluster_refresh_limits,
-    .create_opts                  = &qemu_gluster_create_opts,
-    .strong_runtime_opts          = gluster_strong_open_opts,
-};
-
-static BlockDriver bdrv_gluster_tcp = {
-    .format_name                  = "gluster",
-    .protocol_name                = "gluster+tcp",
-    .instance_size                = sizeof(BDRVGlusterState),
-    .bdrv_open                    = qemu_gluster_open,
-    .bdrv_reopen_prepare          = qemu_gluster_reopen_prepare,
-    .bdrv_reopen_commit           = qemu_gluster_reopen_commit,
-    .bdrv_reopen_abort            = qemu_gluster_reopen_abort,
-    .bdrv_close                   = qemu_gluster_close,
-    .bdrv_co_create               = qemu_gluster_co_create,
-    .bdrv_co_create_opts          = qemu_gluster_co_create_opts,
-    .bdrv_co_getlength            = qemu_gluster_co_getlength,
-    .bdrv_co_get_allocated_file_size = qemu_gluster_co_get_allocated_file_size,
-    .bdrv_co_truncate             = qemu_gluster_co_truncate,
-    .bdrv_co_readv                = qemu_gluster_co_readv,
-    .bdrv_co_writev               = qemu_gluster_co_writev,
-    .bdrv_co_flush_to_disk        = qemu_gluster_co_flush_to_disk,
-#ifdef CONFIG_GLUSTERFS_DISCARD
-    .bdrv_co_pdiscard             = qemu_gluster_co_pdiscard,
-#endif
-#ifdef CONFIG_GLUSTERFS_ZEROFILL
-    .bdrv_co_pwrite_zeroes        = qemu_gluster_co_pwrite_zeroes,
-#endif
-    .bdrv_co_block_status         = qemu_gluster_co_block_status,
-    .bdrv_refresh_limits          = qemu_gluster_refresh_limits,
-    .create_opts                  = &qemu_gluster_create_opts,
-    .strong_runtime_opts          = gluster_strong_open_opts,
-};
-
-static BlockDriver bdrv_gluster_unix = {
-    .format_name                  = "gluster",
-    .protocol_name                = "gluster+unix",
-    .instance_size                = sizeof(BDRVGlusterState),
-    .bdrv_open                    = qemu_gluster_open,
-    .bdrv_reopen_prepare          = qemu_gluster_reopen_prepare,
-    .bdrv_reopen_commit           = qemu_gluster_reopen_commit,
-    .bdrv_reopen_abort            = qemu_gluster_reopen_abort,
-    .bdrv_close                   = qemu_gluster_close,
-    .bdrv_co_create               = qemu_gluster_co_create,
-    .bdrv_co_create_opts          = qemu_gluster_co_create_opts,
-    .bdrv_co_getlength            = qemu_gluster_co_getlength,
-    .bdrv_co_get_allocated_file_size = qemu_gluster_co_get_allocated_file_size,
-    .bdrv_co_truncate             = qemu_gluster_co_truncate,
-    .bdrv_co_readv                = qemu_gluster_co_readv,
-    .bdrv_co_writev               = qemu_gluster_co_writev,
-    .bdrv_co_flush_to_disk        = qemu_gluster_co_flush_to_disk,
-#ifdef CONFIG_GLUSTERFS_DISCARD
-    .bdrv_co_pdiscard             = qemu_gluster_co_pdiscard,
-#endif
-#ifdef CONFIG_GLUSTERFS_ZEROFILL
-    .bdrv_co_pwrite_zeroes        = qemu_gluster_co_pwrite_zeroes,
-#endif
-    .bdrv_co_block_status         = qemu_gluster_co_block_status,
-    .bdrv_refresh_limits          = qemu_gluster_refresh_limits,
-    .create_opts                  = &qemu_gluster_create_opts,
-    .strong_runtime_opts          = gluster_strong_open_opts,
-};
-
-static void bdrv_gluster_init(void)
-{
-    bdrv_register(&bdrv_gluster_unix);
-    bdrv_register(&bdrv_gluster_tcp);
-    bdrv_register(&bdrv_gluster);
-}
-
-block_init(bdrv_gluster_init);
diff --git a/tests/qtest/modules-test.c b/tests/qtest/modules-test.c
index be2575ae6d7..040251c11ec 100644
--- a/tests/qtest/modules-test.c
+++ b/tests/qtest/modules-test.c
@@ -22,9 +22,6 @@ int main(int argc, char *argv[])
 #ifdef CONFIG_CURL
         "block-", "curl",
 #endif
-#ifdef CONFIG_GLUSTERFS
-        "block-", "gluster",
-#endif
 #ifdef CONFIG_LIBISCSI
         "block-", "iscsi",
 #endif
diff --git a/MAINTAINERS b/MAINTAINERS
index eda1e84268a..ba6055619bd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4268,12 +4268,6 @@ L: qemu-block@nongnu.org
 S: Odd Fixes
 F: block/curl.c
 
-GLUSTER
-L: qemu-block@nongnu.org
-L: integration@gluster.org
-S: Odd Fixes
-F: block/gluster.c
-
 Null Block Driver
 M: Fam Zheng <fam@euphon.net>
 L: qemu-block@nongnu.org
diff --git a/block/meson.build b/block/meson.build
index 34b1b2a3063..bc419aebf08 100644
--- a/block/meson.build
+++ b/block/meson.build
@@ -109,7 +109,6 @@ modsrc = []
 foreach m : [
   [blkio, 'blkio', files('blkio.c')],
   [curl, 'curl', files('curl.c')],
-  [glusterfs, 'gluster', files('gluster.c')],
   [libiscsi, 'iscsi', files('iscsi.c')],
   [libnfs, 'nfs', files('nfs.c')],
   [libssh, 'ssh', files('ssh.c')],
diff --git a/meson.build b/meson.build
index 37060c030ed..70613bf4afc 100644
--- a/meson.build
+++ b/meson.build
@@ -1662,43 +1662,6 @@ if not get_option('rbd').auto() or have_block
   endif
 endif
 
-glusterfs = not_found
-glusterfs_ftruncate_has_stat = false
-glusterfs_iocb_has_stat = false
-if not get_option('glusterfs').auto() or have_block
-  glusterfs = dependency('glusterfs-api', version: '>=3',
-                         required: get_option('glusterfs'),
-                         method: 'pkg-config')
-  if glusterfs.found()
-    glusterfs_ftruncate_has_stat = cc.links('''
-      #include <glusterfs/api/glfs.h>
-
-      int
-      main(void)
-      {
-          /* new glfs_ftruncate() passes two additional args */
-          return glfs_ftruncate(NULL, 0, NULL, NULL);
-      }
-    ''', dependencies: glusterfs)
-    glusterfs_iocb_has_stat = cc.links('''
-      #include <glusterfs/api/glfs.h>
-
-      /* new glfs_io_cbk() passes two additional glfs_stat structs */
-      static void
-      glusterfs_iocb(glfs_fd_t *fd, ssize_t ret, struct glfs_stat *prestat, struct glfs_stat *poststat, void *data)
-      {}
-
-      int
-      main(void)
-      {
-          glfs_io_cbk iocb = &glusterfs_iocb;
-          iocb(NULL, 0 , NULL, NULL, NULL);
-          return 0;
-      }
-    ''', dependencies: glusterfs)
-  endif
-endif
-
 hv_balloon = false
 if get_option('hv_balloon').allowed() and have_system
   if cc.links('''
@@ -2478,15 +2441,6 @@ config_host_data.set('CONFIG_CURL', curl.found())
 config_host_data.set('CONFIG_CURSES', curses.found())
 config_host_data.set('CONFIG_GBM', gbm.found())
 config_host_data.set('CONFIG_GIO', gio.found())
-config_host_data.set('CONFIG_GLUSTERFS', glusterfs.found())
-if glusterfs.found()
-  config_host_data.set('CONFIG_GLUSTERFS_XLATOR_OPT', glusterfs.version().version_compare('>=4'))
-  config_host_data.set('CONFIG_GLUSTERFS_DISCARD', glusterfs.version().version_compare('>=5'))
-  config_host_data.set('CONFIG_GLUSTERFS_FALLOCATE', glusterfs.version().version_compare('>=6'))
-  config_host_data.set('CONFIG_GLUSTERFS_ZEROFILL', glusterfs.version().version_compare('>=6'))
-  config_host_data.set('CONFIG_GLUSTERFS_FTRUNCATE_HAS_STAT', glusterfs_ftruncate_has_stat)
-  config_host_data.set('CONFIG_GLUSTERFS_IOCB_HAS_STAT', glusterfs_iocb_has_stat)
-endif
 config_host_data.set('CONFIG_GTK', gtk.found())
 config_host_data.set('CONFIG_VTE', vte.found())
 config_host_data.set('CONFIG_HEXAGON_IDEF_PARSER', get_option('hexagon_idef_parser'))
@@ -5014,7 +4968,6 @@ if host_os == 'windows'
   endif
 endif
 summary_info += {'seccomp support':   seccomp}
-summary_info += {'GlusterFS support': glusterfs}
 summary_info += {'hv-balloon support': hv_balloon}
 summary_info += {'TPM support':       have_tpm}
 summary_info += {'IGVM support':      igvm}
diff --git a/scripts/ci/setup/debian/debian-13-ppc64le.yaml b/scripts/ci/setup/debian/debian-13-ppc64le.yaml
index b16d6d58f8e..e64321357da 100644
--- a/scripts/ci/setup/debian/debian-13-ppc64le.yaml
+++ b/scripts/ci/setup/debian/debian-13-ppc64le.yaml
@@ -50,7 +50,6 @@ packages:
   - libgbm-dev
   - libgcrypt20-dev
   - libglib2.0-dev
-  - libglusterfs-dev
   - libgnutls28-dev
   - libgtk-3-dev
   - libgtk-vnc-2.0-dev
diff --git a/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml b/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml
index b58fcda0fa3..12b0e38a220 100644
--- a/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml
+++ b/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml
@@ -50,7 +50,6 @@ packages:
   - libgbm-dev
   - libgcrypt20-dev
   - libglib2.0-dev
-  - libglusterfs-dev
   - libgnutls28-dev
   - libgtk-3-dev
   - libgtk-vnc-2.0-dev
diff --git a/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml b/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml
index fa439db4ca1..56299f4cc2b 100644
--- a/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml
+++ b/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml
@@ -50,7 +50,6 @@ packages:
   - libgbm-dev
   - libgcrypt20-dev
   - libglib2.0-dev
-  - libglusterfs-dev
   - libgnutls28-dev
   - libgtk-3-dev
   - libgtk-vnc-2.0-dev
diff --git a/scripts/coverity-scan/coverity-scan.docker b/scripts/coverity-scan/coverity-scan.docker
index a349578526d..93e558c8623 100644
--- a/scripts/coverity-scan/coverity-scan.docker
+++ b/scripts/coverity-scan/coverity-scan.docker
@@ -61,7 +61,6 @@ exec "$@"' > /usr/bin/nosync && \
                glib2-static \
                glibc-langpack-en \
                glibc-static \
-               glusterfs-api-devel \
                gnutls-devel \
                gtk3-devel \
                hostname \
diff --git a/scripts/coverity-scan/run-coverity-scan b/scripts/coverity-scan/run-coverity-scan
index 9b89a3303f5..2f9ccd5e44b 100755
--- a/scripts/coverity-scan/run-coverity-scan
+++ b/scripts/coverity-scan/run-coverity-scan
@@ -427,7 +427,7 @@ echo "Configuring..."
     --enable-libiscsi --enable-seccomp \
     --enable-tpm --enable-libssh --enable-lzo --enable-snappy --enable-bzip2 \
     --enable-numa --enable-rdma --enable-smartcard --enable-virglrenderer \
-    --enable-mpath --enable-glusterfs \
+    --enable-mpath \
     --enable-virtfs --enable-zstd
 
 echo "Running cov-build..."
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 23c960b2482..c003985047c 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -121,7 +121,6 @@ meson_options_help() {
   printf "%s\n" '  gcrypt          libgcrypt cryptography support'
   printf "%s\n" '  gettext         Localization of the GTK+ user interface'
   printf "%s\n" '  gio             use libgio for D-Bus support'
-  printf "%s\n" '  glusterfs       Glusterfs block device driver'
   printf "%s\n" '  gnutls          GNUTLS cryptography support'
   printf "%s\n" '  gtk             GTK+ user interface'
   printf "%s\n" '  guest-agent     Build QEMU Guest Agent'
@@ -330,8 +329,6 @@ _meson_option_parse() {
     --disable-gettext) printf "%s" -Dgettext=disabled ;;
     --enable-gio) printf "%s" -Dgio=enabled ;;
     --disable-gio) printf "%s" -Dgio=disabled ;;
-    --enable-glusterfs) printf "%s" -Dglusterfs=enabled ;;
-    --disable-glusterfs) printf "%s" -Dglusterfs=disabled ;;
     --enable-gnutls) printf "%s" -Dgnutls=enabled ;;
     --disable-gnutls) printf "%s" -Dgnutls=disabled ;;
     --enable-gtk) printf "%s" -Dgtk=enabled ;;
diff --git a/tests/docker/dockerfiles/debian-amd64-cross.docker b/tests/docker/dockerfiles/debian-amd64-cross.docker
index 6fad808e1b6..35c593502fc 100644
--- a/tests/docker/dockerfiles/debian-amd64-cross.docker
+++ b/tests/docker/dockerfiles/debian-amd64-cross.docker
@@ -108,7 +108,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
                       libgbm-dev:amd64 \
                       libgcrypt20-dev:amd64 \
                       libglib2.0-dev:amd64 \
-                      libglusterfs-dev:amd64 \
                       libgnutls28-dev:amd64 \
                       libgtk-3-dev:amd64 \
                       libgtk-vnc-2.0-dev:amd64 \
diff --git a/tests/docker/dockerfiles/debian-arm64-cross.docker b/tests/docker/dockerfiles/debian-arm64-cross.docker
index 889d8a1a755..d188d538365 100644
--- a/tests/docker/dockerfiles/debian-arm64-cross.docker
+++ b/tests/docker/dockerfiles/debian-arm64-cross.docker
@@ -108,7 +108,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
                       libgbm-dev:arm64 \
                       libgcrypt20-dev:arm64 \
                       libglib2.0-dev:arm64 \
-                      libglusterfs-dev:arm64 \
                       libgnutls28-dev:arm64 \
                       libgtk-3-dev:arm64 \
                       libgtk-vnc-2.0-dev:arm64 \
diff --git a/tests/docker/dockerfiles/debian-mips64el-cross.docker b/tests/docker/dockerfiles/debian-mips64el-cross.docker
index 90a2ef15574..d139c10c555 100644
--- a/tests/docker/dockerfiles/debian-mips64el-cross.docker
+++ b/tests/docker/dockerfiles/debian-mips64el-cross.docker
@@ -106,7 +106,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
                       libgbm-dev:mips64el \
                       libgcrypt20-dev:mips64el \
                       libglib2.0-dev:mips64el \
-                      libglusterfs-dev:mips64el \
                       libgnutls28-dev:mips64el \
                       libgtk-3-dev:mips64el \
                       libgtk-vnc-2.0-dev:mips64el \
diff --git a/tests/docker/dockerfiles/debian-mipsel-cross.docker b/tests/docker/dockerfiles/debian-mipsel-cross.docker
index b7e36b3d974..2cfc33e8249 100644
--- a/tests/docker/dockerfiles/debian-mipsel-cross.docker
+++ b/tests/docker/dockerfiles/debian-mipsel-cross.docker
@@ -106,7 +106,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
                       libgbm-dev:mipsel \
                       libgcrypt20-dev:mipsel \
                       libglib2.0-dev:mipsel \
-                      libglusterfs-dev:mipsel \
                       libgnutls28-dev:mipsel \
                       libgtk-3-dev:mipsel \
                       libgtk-vnc-2.0-dev:mipsel \
diff --git a/tests/docker/dockerfiles/debian-ppc64el-cross.docker b/tests/docker/dockerfiles/debian-ppc64el-cross.docker
index a70fbee0c1d..7198036380b 100644
--- a/tests/docker/dockerfiles/debian-ppc64el-cross.docker
+++ b/tests/docker/dockerfiles/debian-ppc64el-cross.docker
@@ -108,7 +108,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
                       libgbm-dev:ppc64el \
                       libgcrypt20-dev:ppc64el \
                       libglib2.0-dev:ppc64el \
-                      libglusterfs-dev:ppc64el \
                       libgnutls28-dev:ppc64el \
                       libgtk-3-dev:ppc64el \
                       libgtk-vnc-2.0-dev:ppc64el \
diff --git a/tests/docker/dockerfiles/debian-riscv64-cross.docker b/tests/docker/dockerfiles/debian-riscv64-cross.docker
index 9ada5ecce0d..eb49da9781a 100644
--- a/tests/docker/dockerfiles/debian-riscv64-cross.docker
+++ b/tests/docker/dockerfiles/debian-riscv64-cross.docker
@@ -108,7 +108,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
                       libgbm-dev:riscv64 \
                       libgcrypt20-dev:riscv64 \
                       libglib2.0-dev:riscv64 \
-                      libglusterfs-dev:riscv64 \
                       libgnutls28-dev:riscv64 \
                       libgtk-3-dev:riscv64 \
                       libgtk-vnc-2.0-dev:riscv64 \
diff --git a/tests/docker/dockerfiles/debian-s390x-cross.docker b/tests/docker/dockerfiles/debian-s390x-cross.docker
index a1de94ff9aa..f4c7896a75f 100644
--- a/tests/docker/dockerfiles/debian-s390x-cross.docker
+++ b/tests/docker/dockerfiles/debian-s390x-cross.docker
@@ -108,7 +108,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
                       libgbm-dev:s390x \
                       libgcrypt20-dev:s390x \
                       libglib2.0-dev:s390x \
-                      libglusterfs-dev:s390x \
                       libgnutls28-dev:s390x \
                       libgtk-3-dev:s390x \
                       libgtk-vnc-2.0-dev:s390x \
diff --git a/tests/docker/dockerfiles/debian.docker b/tests/docker/dockerfiles/debian.docker
index c34923b253d..85b78f7e5f8 100644
--- a/tests/docker/dockerfiles/debian.docker
+++ b/tests/docker/dockerfiles/debian.docker
@@ -56,7 +56,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
                       libgbm-dev \
                       libgcrypt20-dev \
                       libglib2.0-dev \
-                      libglusterfs-dev \
                       libgnutls28-dev \
                       libgtk-3-dev \
                       libgtk-vnc-2.0-dev \
diff --git a/tests/docker/dockerfiles/fedora-rust-nightly.docker b/tests/docker/dockerfiles/fedora-rust-nightly.docker
index 8766f952ac8..5e88354f133 100644
--- a/tests/docker/dockerfiles/fedora-rust-nightly.docker
+++ b/tests/docker/dockerfiles/fedora-rust-nightly.docker
@@ -50,7 +50,6 @@ exec "$@"\n' > /usr/bin/nosync && \
                        glib2-static \
                        glibc-langpack-en \
                        glibc-static \
-                       glusterfs-api-devel \
                        gnutls-devel \
                        gtk-vnc2-devel \
                        gtk3-devel \
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
index ec787aa7027..393ac0cce73 100644
--- a/tests/docker/dockerfiles/fedora.docker
+++ b/tests/docker/dockerfiles/fedora.docker
@@ -50,7 +50,6 @@ exec "$@"\n' > /usr/bin/nosync && \
                        glib2-static \
                        glibc-langpack-en \
                        glibc-static \
-                       glusterfs-api-devel \
                        gnutls-devel \
                        gtk-vnc2-devel \
                        gtk3-devel \
diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker
index 66e90fa3634..4b126b7e7de 100644
--- a/tests/docker/dockerfiles/opensuse-leap.docker
+++ b/tests/docker/dockerfiles/opensuse-leap.docker
@@ -34,7 +34,6 @@ RUN zypper update -y && \
            glib2-devel \
            glibc-locale \
            glibc-static \
-           glusterfs-devel \
            gtk-vnc-devel \
            gtk3-devel \
            hostname \
diff --git a/tests/docker/dockerfiles/ubuntu2204.docker b/tests/docker/dockerfiles/ubuntu2204.docker
index fb5b03e7a1b..4617bbe1f65 100644
--- a/tests/docker/dockerfiles/ubuntu2204.docker
+++ b/tests/docker/dockerfiles/ubuntu2204.docker
@@ -55,7 +55,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
                       libgbm-dev \
                       libgcrypt20-dev \
                       libglib2.0-dev \
-                      libglusterfs-dev \
                       libgnutls28-dev \
                       libgtk-3-dev \
                       libgtk-vnc-2.0-dev \
diff --git a/tests/lcitool/projects/qemu.yml b/tests/lcitool/projects/qemu.yml
index 131d9c4ec81..7d185cda3cc 100644
--- a/tests/lcitool/projects/qemu.yml
+++ b/tests/lcitool/projects/qemu.yml
@@ -31,7 +31,6 @@ packages:
  - glib2
  - glib2-native
  - glib2-static
- - glusterfs
  - gnutls
  - gtk3
  - gtk-vnc
-- 
2.54.0



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

* [PULL 09/18] MAINTAINERS: Add myself as maintainer for replication
  2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
                   ` (7 preceding siblings ...)
  2026-05-19 17:03 ` [PULL 08/18] Remove the deprecated glusterfs block driver Kevin Wolf
@ 2026-05-19 17:03 ` Kevin Wolf
  2026-05-19 17:03 ` [PULL 10/18] MAINTAINERS: Rename Replication -> COLO block replication Kevin Wolf
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Kevin Wolf @ 2026-05-19 17:03 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

From: Lukas Straub <lukasstraub2@web.de>

I recently took up maintainership for the orphaned COLO migraion component.
Here I take over maintainership for replication which is another important
component for COLO.

Signed-off-by: Lukas Straub <lukasstraub2@web.de>
Message-ID: <20260425-replication_maintainer-v1-1-f6ab019ff0ca@web.de>
Reviewed-by: Zhang Chen <zhangckid@gmail.com>
Acked-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 MAINTAINERS | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index ba6055619bd..634ceb2abed 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4429,7 +4429,8 @@ F: block/export/vduse-blk.c
 F: block/export/vduse-blk.h
 
 Replication
-S: Orphan
+M: Lukas Straub <lukasstraub2@web.de>
+S: Maintained
 F: replication*
 F: block/replication.c
 F: tests/unit/test-replication.c
-- 
2.54.0



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

* [PULL 10/18] MAINTAINERS: Rename Replication -> COLO block replication
  2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
                   ` (8 preceding siblings ...)
  2026-05-19 17:03 ` [PULL 09/18] MAINTAINERS: Add myself as maintainer for replication Kevin Wolf
@ 2026-05-19 17:03 ` Kevin Wolf
  2026-05-19 17:03 ` [PULL 11/18] block: Create DEFAULT_BLOCK_CONF macro Kevin Wolf
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Kevin Wolf @ 2026-05-19 17:03 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

From: Lukas Straub <lukasstraub2@web.de>

Give it a more descriptive name.

Signed-off-by: Lukas Straub <lukasstraub2@web.de>
Message-ID: <20260425-replication_maintainer-v1-2-f6ab019ff0ca@web.de>
Reviewed-by: Zhang Chen <zhangckid@gmail.com>
Acked-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 MAINTAINERS | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 634ceb2abed..b75f3222f2f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4428,7 +4428,7 @@ F: subprojects/libvduse/
 F: block/export/vduse-blk.c
 F: block/export/vduse-blk.h
 
-Replication
+COLO block replication
 M: Lukas Straub <lukasstraub2@web.de>
 S: Maintained
 F: replication*
-- 
2.54.0



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

* [PULL 11/18] block: Create DEFAULT_BLOCK_CONF macro
  2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
                   ` (9 preceding siblings ...)
  2026-05-19 17:03 ` [PULL 10/18] MAINTAINERS: Rename Replication -> COLO block replication Kevin Wolf
@ 2026-05-19 17:03 ` Kevin Wolf
  2026-05-19 17:03 ` [PULL 12/18] block: Add more defaults to DEFAULT_BLOCK_CONF Kevin Wolf
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Kevin Wolf @ 2026-05-19 17:03 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

The property default values from include/hw/block/block.h were
duplicated in scsi_bus_legacy_handle_cmdline(), allowing them to go out
of sync easily. There doesn't seem a good way to avoid the duplication,
but moving them next to each other in the header file should help to
avoid this problem in the future.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260410152314.86412-2-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 include/hw/block/block.h | 7 +++++++
 hw/scsi/scsi-bus.c       | 7 +------
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/include/hw/block/block.h b/include/hw/block/block.h
index 7dc19d8a453..e0a427039ee 100644
--- a/include/hw/block/block.h
+++ b/include/hw/block/block.h
@@ -51,6 +51,13 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
     return exp;
 }
 
+#define DEFAULT_BLOCK_CONF (BlockConf) {                                \
+    .bootindex = -1,                                                    \
+    .share_rw = false,                                                  \
+    .rerror = BLOCKDEV_ON_ERROR_AUTO,                                   \
+    .werror = BLOCKDEV_ON_ERROR_AUTO,                                   \
+}
+
 #define DEFINE_BLOCK_PROPERTIES_BASE(_state, _conf)                     \
     DEFINE_PROP_ON_OFF_AUTO("backend_defaults", _state,                 \
                             _conf.backend_defaults, ON_OFF_AUTO_AUTO),  \
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index 1a6b181b9d6..dccb2f25b2a 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -485,12 +485,7 @@ void scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
     Location loc;
     DriveInfo *dinfo;
     int unit;
-    BlockConf conf = {
-        .bootindex = -1,
-        .share_rw = false,
-        .rerror = BLOCKDEV_ON_ERROR_AUTO,
-        .werror = BLOCKDEV_ON_ERROR_AUTO,
-    };
+    BlockConf conf = DEFAULT_BLOCK_CONF;
 
     loc_push_none(&loc);
     for (unit = 0; unit <= bus->info->max_target; unit++) {
-- 
2.54.0



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

* [PULL 12/18] block: Add more defaults to DEFAULT_BLOCK_CONF
  2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
                   ` (10 preceding siblings ...)
  2026-05-19 17:03 ` [PULL 11/18] block: Create DEFAULT_BLOCK_CONF macro Kevin Wolf
@ 2026-05-19 17:03 ` Kevin Wolf
  2026-05-19 17:03 ` [PULL 13/18] commit: Drain nodes across all of bdrv_commit() Kevin Wolf
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Kevin Wolf @ 2026-05-19 17:03 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

discard_granularity was missing from this, which means that SCSI disks
created with -drive if=scsi would default to 0 (i.e. disabling discards)
instead of -1, which makes scsi-hd automatically pick a granularity and
is the default of the corresponding qdev property for -device scsi-hd.

This was broken in QEMU 9.0 with commit 3089637.

Also set other fields whose default isn't an obvious 0. These are not
actual bug fixes because ON_OFF_AUTO_AUTO in fact happens to be 0, but
it's better not to rely on the order of enums.

Cc: qemu-stable@nongnu.org
Fixes: 308963746169 ('scsi: Don't ignore most usb-storage properties')
Reported-by: Lexi Winter <ivy@FreeBSD.org>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260410152314.86412-3-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 include/hw/block/block.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/hw/block/block.h b/include/hw/block/block.h
index e0a427039ee..df941df19f2 100644
--- a/include/hw/block/block.h
+++ b/include/hw/block/block.h
@@ -53,7 +53,12 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
 
 #define DEFAULT_BLOCK_CONF (BlockConf) {                                \
     .bootindex = -1,                                                    \
+    .backend_defaults = ON_OFF_AUTO_AUTO,                               \
+    .discard_granularity = -1,                                          \
+    .wce = ON_OFF_AUTO_AUTO,                                            \
     .share_rw = false,                                                  \
+    .account_invalid = ON_OFF_AUTO_AUTO,                                \
+    .account_failed = ON_OFF_AUTO_AUTO,                                 \
     .rerror = BLOCKDEV_ON_ERROR_AUTO,                                   \
     .werror = BLOCKDEV_ON_ERROR_AUTO,                                   \
 }
-- 
2.54.0



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

* [PULL 13/18] commit: Drain nodes across all of bdrv_commit()
  2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
                   ` (11 preceding siblings ...)
  2026-05-19 17:03 ` [PULL 12/18] block: Add more defaults to DEFAULT_BLOCK_CONF Kevin Wolf
@ 2026-05-19 17:03 ` Kevin Wolf
  2026-05-19 21:51   ` Michael Tokarev
  2026-05-19 17:03 ` [PULL 14/18] qemu-io: Add 'aio_discard' command Kevin Wolf
                   ` (5 subsequent siblings)
  18 siblings, 1 reply; 29+ messages in thread
From: Kevin Wolf @ 2026-05-19 17:03 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

The whole implementation of bdrv_commit() is only correct if no new
writes come in while it's running: It has only a single loop checking
the allocation status for each block and finally calls bdrv_make_empty()
without checking if that throws away any new changes.

We already have to drain while taking the graph write lock. Just extend
the drained section to all of bdrv_commit() to make sure that we don't
get any inconsistencies.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260427170520.101242-2-kwolf@redhat.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
Tested-by: Denis V. Lunev <den@openvz.org>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/commit.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/block/commit.c b/block/commit.c
index 0d9e1a16d7a..c5e3ef03a21 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -518,6 +518,7 @@ int bdrv_commit(BlockDriverState *bs)
     if (!drv)
         return -ENOMEDIUM;
 
+    bdrv_drain_all_begin();
     bdrv_graph_rdlock_main_loop();
 
     backing_file_bs = bdrv_cow_bs(bs);
@@ -549,6 +550,10 @@ int bdrv_commit(BlockDriverState *bs)
                   BLK_PERM_ALL);
     backing = blk_new(ctx, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
 
+    /* We drained all nodes, but still make requests through BlockBackends */
+    blk_set_disable_request_queuing(src, true);
+    blk_set_disable_request_queuing(backing, true);
+
     ret = blk_insert_bs(src, bs, &local_err);
     if (ret < 0) {
         error_report_err(local_err);
@@ -565,7 +570,7 @@ int bdrv_commit(BlockDriverState *bs)
 
     bdrv_graph_rdunlock_main_loop();
 
-    bdrv_graph_wrlock_drained();
+    bdrv_graph_wrlock();
     bdrv_set_backing_hd(commit_top_bs, backing_file_bs, &error_abort);
     bdrv_set_backing_hd(bs, commit_top_bs, &error_abort);
     bdrv_graph_wrunlock();
@@ -647,7 +652,7 @@ ro_cleanup:
     blk_unref(backing);
 
     bdrv_graph_rdunlock_main_loop();
-    bdrv_graph_wrlock_drained();
+    bdrv_graph_wrlock();
     if (bdrv_cow_bs(bs) != backing_file_bs) {
         bdrv_set_backing_hd(bs, backing_file_bs, &error_abort);
     }
@@ -663,6 +668,7 @@ ro_cleanup:
 
 out:
     bdrv_graph_rdunlock_main_loop();
+    bdrv_drain_all_end();
 
     return ret;
 }
-- 
2.54.0



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

* [PULL 14/18] qemu-io: Add 'aio_discard' command
  2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
                   ` (12 preceding siblings ...)
  2026-05-19 17:03 ` [PULL 13/18] commit: Drain nodes across all of bdrv_commit() Kevin Wolf
@ 2026-05-19 17:03 ` Kevin Wolf
  2026-05-19 17:03 ` [PULL 15/18] qcow2: Fix corruption on discard during write with COW Kevin Wolf
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Kevin Wolf @ 2026-05-19 17:03 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

Testing interactions between multiple requests that include discard
requests require that qemu-io can do the discard asynchronously, like it
already does for reads and writes. To this effect, add an 'aio_discard'
command.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260427170520.101242-3-kwolf@redhat.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
Tested-by: Denis V. Lunev <den@openvz.org>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 qemu-io-cmds.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 115 insertions(+)

diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index f6d077908f2..de4c1966fea 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -2218,6 +2218,120 @@ static int discard_f(BlockBackend *blk, int argc, char **argv)
     return 0;
 }
 
+static void aio_discard_help(void)
+{
+    printf(
+"\n"
+" asynchronously discards a range of bytes from the given offset\n"
+"\n"
+" Example:\n"
+" 'aio_discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n"
+"\n"
+" Discards a segment of the currently open file.\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
+" The discard is performed asynchronously and the aio_flush command must be\n"
+" used to ensure all outstanding aio requests have been completed.\n"
+" Note that due to its asynchronous nature, this command will be\n"
+" considered successful once the request is submitted, independently\n"
+" of potential I/O errors.\n"
+"\n");
+}
+
+static int aio_discard_f(BlockBackend *blk, int argc, char **argv);
+
+static const cmdinfo_t aio_discard_cmd = {
+    .name       = "aio_discard",
+    .cfunc      = aio_discard_f,
+    .perm       = BLK_PERM_WRITE,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cq] off len",
+    .oneline    = "asynchronously discards a number of bytes",
+    .help       = aio_discard_help,
+};
+
+static void aio_discard_done(void *opaque, int ret)
+{
+    struct aio_ctx *ctx = opaque;
+    struct timespec t2;
+
+    clock_gettime(CLOCK_MONOTONIC, &t2);
+
+    if (ret < 0) {
+        printf("aio_discard failed: %s\n", strerror(-ret));
+        block_acct_failed(blk_get_stats(ctx->blk), &ctx->acct);
+        goto out;
+    }
+
+    block_acct_done(blk_get_stats(ctx->blk), &ctx->acct);
+
+    if (ctx->qflag) {
+        goto out;
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, ctx->t1);
+    print_report("discarded ", &t2, ctx->offset, ctx->qiov.size,
+                 ctx->qiov.size, 1, ctx->Cflag);
+out:
+    g_free(ctx);
+}
+
+static int aio_discard_f(BlockBackend *blk, int argc, char **argv)
+{
+    int c, ret;
+    int64_t count;
+    struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
+
+    ctx->blk = blk;
+
+    while ((c = getopt(argc, argv, "Cq")) != -1) {
+        switch (c) {
+        case 'C':
+            ctx->Cflag = true;
+            break;
+        case 'q':
+            ctx->qflag = true;
+            break;
+        default:
+            g_free(ctx);
+            qemuio_command_usage(&aio_discard_cmd);
+            return -EINVAL;
+        }
+    }
+
+    if (optind != argc - 2) {
+        g_free(ctx);
+        qemuio_command_usage(&aio_discard_cmd);
+        return -EINVAL;
+    }
+
+    ctx->offset = cvtnum(argv[optind]);
+    if (ctx->offset < 0) {
+        ret = ctx->offset;
+        print_cvtnum_err(ret, argv[optind]);
+        g_free(ctx);
+        return ret;
+    }
+    optind++;
+
+    count = cvtnum(argv[optind]);
+    if (count < 0) {
+        print_cvtnum_err(count, argv[optind]);
+        g_free(ctx);
+        return count;
+    }
+
+    clock_gettime(CLOCK_MONOTONIC, &ctx->t1);
+    ctx->qiov.size = count;
+    block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
+                     BLOCK_ACCT_UNMAP);
+    blk_aio_pdiscard(blk, ctx->offset, count, aio_discard_done, ctx);
+
+    return 0;
+}
+
 static int alloc_f(BlockBackend *blk, int argc, char **argv)
 {
     BlockDriverState *bs = blk_bs(blk);
@@ -2800,6 +2914,7 @@ static void __attribute((constructor)) init_qemuio_commands(void)
     qemuio_add_command(&length_cmd);
     qemuio_add_command(&info_cmd);
     qemuio_add_command(&discard_cmd);
+    qemuio_add_command(&aio_discard_cmd);
     qemuio_add_command(&alloc_cmd);
     qemuio_add_command(&map_cmd);
     qemuio_add_command(&reopen_cmd);
-- 
2.54.0



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

* [PULL 15/18] qcow2: Fix corruption on discard during write with COW
  2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
                   ` (13 preceding siblings ...)
  2026-05-19 17:03 ` [PULL 14/18] qemu-io: Add 'aio_discard' command Kevin Wolf
@ 2026-05-19 17:03 ` Kevin Wolf
  2026-05-19 17:03 ` [PULL 16/18] iotests/046: Test that discard/write_zeroes wait for dependencies Kevin Wolf
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Kevin Wolf @ 2026-05-19 17:03 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

Most code in qcow2 that accesses (and potentially modifies) L2 tables
does so while holding s->lock.

There is one exception, which is allocating writes. They hold the lock
initially while allocating clusters, but drop it for writing the guest
payload before taking the lock again for updating the L2 tables. This
allows concurrent requests that touch other parts of the image file to
continue in parallel and is an important performance optimisation.

However, this means that other requests that run while the lock is
dropped for writing guest data must synchronise with the list of
allocating requests in s->cluster_allocs and wait if they would overlap.
For writes, this is done in handle_dependencies(), but discard and write
zeros operations neglect to synchronise with s->cluster_allocs.

This means that discard can free a cluster whose L2 entry will already
be modified in qcow2_alloc_cluster_link_l2() by a previously started
write. In the case of a pre-allocated zero cluster that is in the
process of being overwritten, this means that discard can lead to a
situation where the cluster is still mapped (because the write will
restore the L2 entry just without the zero flag), but its refcount has
been decreased, resulting in a corrupted image.

Add the missing synchronisation to qcow2_cluster_discard() and
qcow2_subcluster_zeroize() to fix the problem.

Cc: qemu-stable@nongnu.org
Reported-by: Denis V. Lunev <den@openvz.org>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260427170520.101242-4-kwolf@redhat.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
Tested-by: Denis V. Lunev <den@openvz.org>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/qcow2-cluster.c | 52 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 49 insertions(+), 3 deletions(-)

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index c655bf6df42..8b1e80bd0b3 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1392,6 +1392,9 @@ count_single_write_clusters(BlockDriverState *bs, int nb_clusters,
  * the same cluster. In this case we need to wait until the previous
  * request has completed and updated the L2 table accordingly.
  *
+ * If allow_shortening == true, instead of waiting for a dependency, *cur_bytes
+ * can be shortened so that the cluster allocations don't overlap.
+ *
  * Returns:
  *   0       if there was no dependency. *cur_bytes indicates the number of
  *           bytes from guest_offset that can be read before the next
@@ -1403,7 +1406,9 @@ count_single_write_clusters(BlockDriverState *bs, int nb_clusters,
  */
 static int coroutine_fn handle_dependencies(BlockDriverState *bs,
                                             uint64_t guest_offset,
-                                            uint64_t *cur_bytes, QCowL2Meta **m)
+                                            uint64_t *cur_bytes,
+                                            bool allow_shortening,
+                                            QCowL2Meta **m)
 {
     BDRVQcow2State *s = bs->opaque;
     QCowL2Meta *old_alloc;
@@ -1434,7 +1439,7 @@ static int coroutine_fn handle_dependencies(BlockDriverState *bs,
 
         /* Conflict */
 
-        if (start < old_start) {
+        if (start < old_start && allow_shortening) {
             /* Stop at the start of a running allocation */
             bytes = old_start - start;
         } else {
@@ -1469,6 +1474,29 @@ static int coroutine_fn handle_dependencies(BlockDriverState *bs,
     return 0;
 }
 
+static void coroutine_mixed_fn wait_for_dependencies(BlockDriverState *bs,
+                                                     uint64_t guest_offset,
+                                                     uint64_t bytes)
+{
+    BDRVQcow2State *s = bs->opaque;
+    QCowL2Meta *m = NULL;
+    int ret;
+
+    /*
+     * Discard has some non-coroutine callers (creating internal snapshots and
+     * make empty). They are calling from qemu-img or in a drained section, so
+     * we know that no writes can be in progress.
+     */
+    if (!qemu_in_coroutine()) {
+        assert(QLIST_EMPTY(&s->cluster_allocs));
+        return;
+    }
+
+    do {
+        ret = handle_dependencies(bs, guest_offset, &bytes, false, &m);
+    } while (ret == -EAGAIN);
+}
+
 /*
  * Checks how many already allocated clusters that don't require a new
  * allocation there are at the given guest_offset (up to *bytes).
@@ -1840,7 +1868,7 @@ again:
          *         the right synchronisation between the in-flight request and
          *         the new one.
          */
-        ret = handle_dependencies(bs, start, &cur_bytes, m);
+        ret = handle_dependencies(bs, start, &cur_bytes, true, m);
         if (ret == -EAGAIN) {
             /* Currently handle_dependencies() doesn't yield if we already had
              * an allocation. If it did, we would have to clean up the L2Meta
@@ -2000,6 +2028,15 @@ int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset,
     int64_t cleared;
     int ret;
 
+    /*
+     * If we're touching a cluster for which allocating writes are in flight,
+     * wait for them to complete to avoid conflicting metadata updates.
+     *
+     * We don't need to allocate a QCowL2Meta for the discard operation because
+     * s->lock is held for the duration of the whole operation.
+     */
+    wait_for_dependencies(bs, offset, bytes);
+
     /* Caller must pass aligned values, except at image end */
     assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
     assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) ||
@@ -2160,6 +2197,15 @@ int coroutine_fn qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset,
     int64_t cleared;
     int ret;
 
+    /*
+     * If we're touching a cluster for which allocating writes are in flight,
+     * wait for them to complete to avoid conflicting metadata updates.
+     *
+     * We don't need to allocate a QCowL2Meta for the zeroize operation because
+     * s->lock is held for the duration of the whole operation.
+     */
+    wait_for_dependencies(bs, offset, bytes);
+
     /* If we have to stay in sync with an external data file, zero out
      * s->data_file first. */
     if (data_file_is_raw(bs)) {
-- 
2.54.0



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

* [PULL 16/18] iotests/046: Test that discard/write_zeroes wait for dependencies
  2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
                   ` (14 preceding siblings ...)
  2026-05-19 17:03 ` [PULL 15/18] qcow2: Fix corruption on discard during write with COW Kevin Wolf
@ 2026-05-19 17:03 ` Kevin Wolf
  2026-05-19 17:03 ` [PULL 17/18] block/graph-lock: fix missed wakeup in bdrv_graph_co_rdunlock() Kevin Wolf
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Kevin Wolf @ 2026-05-19 17:03 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

This is a regression test for the bug fixed in the previous commit where
discard and write_zeroes operations wouldn't consider their dependencies
in s->cluster_allocs. Without the fix, this results in a corrupted
image.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260427170520.101242-5-kwolf@redhat.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
Tested-by: Denis V. Lunev <den@openvz.org>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 tests/qemu-iotests/046     | 46 ++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/046.out | 36 +++++++++++++++++++++++++++++
 2 files changed, 82 insertions(+)

diff --git a/tests/qemu-iotests/046 b/tests/qemu-iotests/046
index 4c9ed4d26e1..e03dd401479 100755
--- a/tests/qemu-iotests/046
+++ b/tests/qemu-iotests/046
@@ -184,6 +184,48 @@ aio_write -P 160 0x104000 0x18000
 resume A
 aio_flush
 EOF
+
+# Create a pre-allocated zero cluster, then start a write on it and discard it
+# before the L2 update is made
+cat  <<EOF
+write -P 181 0x120000 0x10000
+write -z 0x120000 0x10000
+
+break write_aio A
+aio_write -P 180 0x120000 0x10000
+wait_break A
+aio_discard 0x120000 0x10000
+resume A
+aio_flush
+EOF
+
+# Create a pre-allocated zero cluster, then start a write on it and a
+# concurrent zero write with MAY_UNMAP before the L2 update is made
+cat  <<EOF
+write -P 181 0x130000 0x10000
+write -z 0x130000 0x10000
+
+break write_aio A
+aio_write -P 180 0x130000 0x10000
+wait_break A
+aio_write -z -u 0x130000 0x10000
+resume A
+aio_flush
+EOF
+
+# Create a pre-allocated zero cluster, then start a write on it and a
+# concurrent zero write without MAY_UNMAP before the L2 update is made
+cat  <<EOF
+write -P 181 0x140000 0x10000
+write -z 0x140000 0x10000
+
+break write_aio A
+aio_write -P 180 0x140000 0x10000
+wait_break A
+aio_write -z 0x140000 0x10000
+resume A
+aio_flush
+EOF
 }
 
 overlay_io | $QEMU_IO blkdebug::"$TEST_IMG" | _filter_qemu_io |\
@@ -264,6 +306,10 @@ verify_io()
     # Undefined content for 0x10c000 0x8000
     echo read -P 160 0x114000 0x8000
     echo read -P 17  0x11c000 0x4000
+
+    echo read -P 0   0x120000 0x10000
+    echo read -P 0   0x130000 0x10000
+    echo read -P 0   0x140000 0x10000
 }
 
 verify_io | $QEMU_IO "$TEST_IMG" | _filter_qemu_io
diff --git a/tests/qemu-iotests/046.out b/tests/qemu-iotests/046.out
index b1a03f40414..6341df335c9 100644
--- a/tests/qemu-iotests/046.out
+++ b/tests/qemu-iotests/046.out
@@ -139,6 +139,36 @@ wrote XXX/XXX bytes at offset XXX
 XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 wrote XXX/XXX bytes at offset XXX
 XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+blkdebug: Suspended request 'A'
+blkdebug: Resuming request 'A'
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+discarded  XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+blkdebug: Suspended request 'A'
+blkdebug: Resuming request 'A'
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+blkdebug: Suspended request 'A'
+blkdebug: Resuming request 'A'
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 
 == Verify image content ==
 read 65536/65536 bytes at offset 0
@@ -239,5 +269,11 @@ read 32768/32768 bytes at offset 1130496
 32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 read 16384/16384 bytes at offset 1163264
 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 65536/65536 bytes at offset 1179648
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 65536/65536 bytes at offset 1245184
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 65536/65536 bytes at offset 1310720
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 No errors were found on the image.
 *** done
-- 
2.54.0



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

* [PULL 17/18] block/graph-lock: fix missed wakeup in bdrv_graph_co_rdunlock()
  2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
                   ` (15 preceding siblings ...)
  2026-05-19 17:03 ` [PULL 16/18] iotests/046: Test that discard/write_zeroes wait for dependencies Kevin Wolf
@ 2026-05-19 17:03 ` Kevin Wolf
  2026-05-19 17:03 ` [PULL 18/18] block: Improve readability in HMP 'info blockstats' output Kevin Wolf
  2026-05-19 20:51 ` [PULL 00/18] Block layer patches Stefan Hajnoczi
  18 siblings, 0 replies; 29+ messages in thread
From: Kevin Wolf @ 2026-05-19 17:03 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

From: "Denis V. Lunev" <den@openvz.org>

tests/qemu-iotests/tests/iothreads-create reproduces the hang on
master under `stress-ng --cpu $(nproc) --timeout 0`.  The iotest's
vm.run_job() times out and qemu stays permanently stuck in
ppoll(timeout=-1) inside bdrv_graph_wrlock_drained -> blk_remove_bs
during qemu_cleanup().  The timing window is narrow on modern
bare-metal hardware and much wider in a VM guest; downstream trees
that still use plain bdrv_graph_wrlock() in blk_remove_bs() hit it
on the first iteration under the same stress.

bdrv_graph_wrlock() zeroes has_writer around its AIO_WAIT_WHILE loop
so that callbacks dispatched by aio_poll() can still take the read
lock on the fast path.  The rdunlock side, however, only kicks a
waiting writer when has_writer is observed set; a reader that drops
its lock inside the polling window silently returns and nothing ever
wakes the writer:

  main thread                         iothread0 coroutine
  -----------                         -------------------
  bdrv_graph_wrlock:                  rdlock held, reader_count=1
    bdrv_drain_all_begin_nopoll
    has_writer = 0
    AIO_WAIT_WHILE_UNLOCKED(
        NULL, reader_count >= 1):
      num_waiters++
      smp_mb
      aio_poll(main_ctx, true)   -->  bdrv_graph_co_rdunlock:
        (ppoll, blocked)                reader_count-- -> 0
                                        smp_mb
                                        read has_writer = 0
                                        skip aio_wait_kick()
                                      return

reader_count is now 0 and num_waiters is still 1, but no BH, fd or
timer on the main AioContext will fire -- the only entity that could
kick just decided it did not have to.  Main stays in ppoll() holding
BQL, so RCU, VCPUs and any iothread path that needs BQL stall behind
it.  The hang is final; no timeout, no forward progress, no recovery
as there is no other source of wake up inside qemu_cleanup().

bdrv_drain_all_begin() does not close the race on its own: it
quiesces in-flight I/O, but graph readers also include non-I/O
coroutines (block-job cleanup, virtio-scsi polling) that drain does
not evict.  The bdrv_graph_wrlock_drained() wrapper narrows the
window but does not eliminate it; every plain bdrv_graph_wrlock()
site is exposed on the same basis.

Drop the has_writer check in bdrv_graph_co_rdunlock() and call
aio_wait_kick() unconditionally.  The helper itself loads num_waiters
atomically and only schedules a dummy BH when a waiter exists, so the
change is a no-op on the no-writer path and closes the missed-wakeup
on the writer path.

Signed-off-by: Denis V. Lunev <den@openvz.org>
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: Hanna Reitz <hreitz@redhat.com>
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Cc: Fiona Ebner <f.ebner@proxmox.com>
Message-ID: <20260424103917.248668-2-den@openvz.org>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/graph-lock.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/block/graph-lock.c b/block/graph-lock.c
index b7319473a17..f2501d75fbe 100644
--- a/block/graph-lock.c
+++ b/block/graph-lock.c
@@ -278,14 +278,12 @@ void coroutine_fn bdrv_graph_co_rdunlock(void)
     smp_mb();
 
     /*
-     * has_writer == 0: this means reader will read reader_count decreased
-     * has_writer == 1: we don't know if writer read reader_count old or
-     *                  new. Therefore, kick again so on next iteration
-     *                  writer will for sure read the updated value.
+     * Always kick: bdrv_graph_wrlock() zeroes has_writer while polling (to
+     * let callbacks take the reader lock via the fast path), so we cannot
+     * rely on has_writer to detect a waiting writer. aio_wait_kick() is a
+     * no-op when no one is waiting, so it is cheap in the common case.
      */
-    if (qatomic_read(&has_writer)) {
-        aio_wait_kick();
-    }
+    aio_wait_kick();
 }
 
 void bdrv_graph_rdlock_main_loop(void)
-- 
2.54.0



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

* [PULL 18/18] block: Improve readability in HMP 'info blockstats' output
  2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
                   ` (16 preceding siblings ...)
  2026-05-19 17:03 ` [PULL 17/18] block/graph-lock: fix missed wakeup in bdrv_graph_co_rdunlock() Kevin Wolf
@ 2026-05-19 17:03 ` Kevin Wolf
  2026-05-19 20:51 ` [PULL 00/18] Block layer patches Stefan Hajnoczi
  18 siblings, 0 replies; 29+ messages in thread
From: Kevin Wolf @ 2026-05-19 17:03 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, stefanha, qemu-devel

Instead of a long line with key=value pairs for each block device,
switch to a tabular form with aligned values. This makes it much easier
to find the relevant information in the output.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260512112759.66038-1-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/monitor/block-hmp-cmds.c | 38 ++++++++++++++++------------------
 1 file changed, 18 insertions(+), 20 deletions(-)

diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
index 1fd28d59eb1..69ade0534f1 100644
--- a/block/monitor/block-hmp-cmds.c
+++ b/block/monitor/block-hmp-cmds.c
@@ -794,30 +794,28 @@ void hmp_info_blockstats(Monitor *mon, const QDict *qdict)
             continue;
         }
 
-        monitor_printf(mon, "%s:", stats->value->device);
-        monitor_printf(mon, " rd_bytes=%" PRId64
-                       " wr_bytes=%" PRId64
-                       " rd_operations=%" PRId64
-                       " wr_operations=%" PRId64
-                       " flush_operations=%" PRId64
-                       " wr_total_time_ns=%" PRId64
-                       " rd_total_time_ns=%" PRId64
-                       " flush_total_time_ns=%" PRId64
-                       " rd_merged=%" PRId64
-                       " wr_merged=%" PRId64
-                       " idle_time_ns=%" PRId64
-                       "\n",
+        monitor_printf(mon, "%s%s: idle_time_ns=%" PRId64 "\n",
+                       stats != stats_list ? "\n" : "",
+                       stats->value->device,
+                       stats->value->stats->idle_time_ns);
+        monitor_printf(mon, "       %24s %16s %24s %10s\n", "bytes",
+                       "operations", "total_time_ns", "merged");
+        monitor_printf(mon, "Read:  %24" PRId64 " %16" PRId64 " %24" PRId64
+                       " %10" PRId64 "\n",
                        stats->value->stats->rd_bytes,
-                       stats->value->stats->wr_bytes,
                        stats->value->stats->rd_operations,
+                       stats->value->stats->rd_total_time_ns,
+                       stats->value->stats->rd_merged);
+        monitor_printf(mon, "Write: %24" PRId64 " %16" PRId64 " %24" PRId64
+                       " %10" PRId64 "\n",
+                       stats->value->stats->wr_bytes,
                        stats->value->stats->wr_operations,
-                       stats->value->stats->flush_operations,
                        stats->value->stats->wr_total_time_ns,
-                       stats->value->stats->rd_total_time_ns,
-                       stats->value->stats->flush_total_time_ns,
-                       stats->value->stats->rd_merged,
-                       stats->value->stats->wr_merged,
-                       stats->value->stats->idle_time_ns);
+                       stats->value->stats->wr_merged);
+        monitor_printf(mon, "Flush: %24s %16" PRId64 " %24" PRId64 "\n",
+                       "",
+                       stats->value->stats->flush_operations,
+                       stats->value->stats->flush_total_time_ns);
     }
 
     qapi_free_BlockStatsList(stats_list);
-- 
2.54.0



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

* Re: [PULL 00/18] Block layer patches
  2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
                   ` (17 preceding siblings ...)
  2026-05-19 17:03 ` [PULL 18/18] block: Improve readability in HMP 'info blockstats' output Kevin Wolf
@ 2026-05-19 20:51 ` Stefan Hajnoczi
  18 siblings, 0 replies; 29+ messages in thread
From: Stefan Hajnoczi @ 2026-05-19 20:51 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: qemu-block, kwolf, stefanha, qemu-devel

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

Applied, thanks.

Please update the changelog at https://wiki.qemu.org/ChangeLog/11.1 for any user-visible changes.

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

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

* Re: [PULL 13/18] commit: Drain nodes across all of bdrv_commit()
  2026-05-19 17:03 ` [PULL 13/18] commit: Drain nodes across all of bdrv_commit() Kevin Wolf
@ 2026-05-19 21:51   ` Michael Tokarev
  0 siblings, 0 replies; 29+ messages in thread
From: Michael Tokarev @ 2026-05-19 21:51 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: stefanha, qemu-devel, Fiona Ebner

On 19.05.2026 20:03, Kevin Wolf wrote:
> The whole implementation of bdrv_commit() is only correct if no new
> writes come in while it's running: It has only a single loop checking
> the allocation status for each block and finally calls bdrv_make_empty()
> without checking if that throws away any new changes.
> 
> We already have to drain while taking the graph write lock. Just extend
> the drained section to all of bdrv_commit() to make sure that we don't
> get any inconsistencies.
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> Message-ID: <20260427170520.101242-2-kwolf@redhat.com>
> Reviewed-by: Denis V. Lunev <den@openvz.org>
> Tested-by: Denis V. Lunev <den@openvz.org>
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>   block/commit.c | 10 ++++++++--
>   1 file changed, 8 insertions(+), 2 deletions(-)

Hi!

Does this change makes sense for 10.0.x qemu stable series too?
It feels like this change should be picked up for 10.0.x (LTS)
series too.

But I need some help with that.  10.0.x has quite different code
in this area..

Can you back-port this change to 10.0.x, or should this one be dropped
from this series?

Thank you!

/mjt

> diff --git a/block/commit.c b/block/commit.c
> index 0d9e1a16d7a..c5e3ef03a21 100644
> --- a/block/commit.c
> +++ b/block/commit.c
> @@ -518,6 +518,7 @@ int bdrv_commit(BlockDriverState *bs)
>       if (!drv)
>           return -ENOMEDIUM;
>   
> +    bdrv_drain_all_begin();
>       bdrv_graph_rdlock_main_loop();
>   
>       backing_file_bs = bdrv_cow_bs(bs);
> @@ -549,6 +550,10 @@ int bdrv_commit(BlockDriverState *bs)
>                     BLK_PERM_ALL);
>       backing = blk_new(ctx, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
>   
> +    /* We drained all nodes, but still make requests through BlockBackends */
> +    blk_set_disable_request_queuing(src, true);
> +    blk_set_disable_request_queuing(backing, true);
> +
>       ret = blk_insert_bs(src, bs, &local_err);
>       if (ret < 0) {
>           error_report_err(local_err);
> @@ -565,7 +570,7 @@ int bdrv_commit(BlockDriverState *bs)
>   
>       bdrv_graph_rdunlock_main_loop();
>   
> -    bdrv_graph_wrlock_drained();
> +    bdrv_graph_wrlock();
>       bdrv_set_backing_hd(commit_top_bs, backing_file_bs, &error_abort);
>       bdrv_set_backing_hd(bs, commit_top_bs, &error_abort);
>       bdrv_graph_wrunlock();
> @@ -647,7 +652,7 @@ ro_cleanup:
>       blk_unref(backing);
>   
>       bdrv_graph_rdunlock_main_loop();
> -    bdrv_graph_wrlock_drained();
> +    bdrv_graph_wrlock();
>       if (bdrv_cow_bs(bs) != backing_file_bs) {
>           bdrv_set_backing_hd(bs, backing_file_bs, &error_abort);
>       }
> @@ -663,6 +668,7 @@ ro_cleanup:
>   
>   out:
>       bdrv_graph_rdunlock_main_loop();
> +    bdrv_drain_all_end();
>   
>       return ret;
>   }



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

end of thread, other threads:[~2026-05-19 21:52 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-19 17:02 [PULL 00/18] Block layer patches Kevin Wolf
2026-05-19 17:03 ` [PULL 01/18] blkdebug: Add 'delay-ns' option Kevin Wolf
2026-05-19 17:03 ` [PULL 02/18] block: Add blk_co_start/end_request() and BDRV_REQ_NO_QUEUE Kevin Wolf
2026-05-19 17:03 ` [PULL 03/18] block: Add flags parameter to blk_*_pdiscard() Kevin Wolf
2026-05-19 17:03 ` [PULL 04/18] ide: Minimal fix for deadlock between TRIM and drain Kevin Wolf
2026-05-19 17:03 ` [PULL 05/18] ide: Clean up ide_trim_co_entry() to be idiomatic coroutine code Kevin Wolf
2026-05-19 17:03 ` [PULL 06/18] ide-test: Factor out wait_dma_completion() Kevin Wolf
2026-05-19 17:03 ` [PULL 07/18] ide-test: Test reset during TRIM Kevin Wolf
2026-05-19 17:03 ` [PULL 08/18] Remove the deprecated glusterfs block driver Kevin Wolf
2026-05-19 17:03 ` [PULL 09/18] MAINTAINERS: Add myself as maintainer for replication Kevin Wolf
2026-05-19 17:03 ` [PULL 10/18] MAINTAINERS: Rename Replication -> COLO block replication Kevin Wolf
2026-05-19 17:03 ` [PULL 11/18] block: Create DEFAULT_BLOCK_CONF macro Kevin Wolf
2026-05-19 17:03 ` [PULL 12/18] block: Add more defaults to DEFAULT_BLOCK_CONF Kevin Wolf
2026-05-19 17:03 ` [PULL 13/18] commit: Drain nodes across all of bdrv_commit() Kevin Wolf
2026-05-19 21:51   ` Michael Tokarev
2026-05-19 17:03 ` [PULL 14/18] qemu-io: Add 'aio_discard' command Kevin Wolf
2026-05-19 17:03 ` [PULL 15/18] qcow2: Fix corruption on discard during write with COW Kevin Wolf
2026-05-19 17:03 ` [PULL 16/18] iotests/046: Test that discard/write_zeroes wait for dependencies Kevin Wolf
2026-05-19 17:03 ` [PULL 17/18] block/graph-lock: fix missed wakeup in bdrv_graph_co_rdunlock() Kevin Wolf
2026-05-19 17:03 ` [PULL 18/18] block: Improve readability in HMP 'info blockstats' output Kevin Wolf
2026-05-19 20:51 ` [PULL 00/18] Block layer patches Stefan Hajnoczi
  -- strict thread matches above, loose matches on Subject: below --
2025-10-29 12:06 Kevin Wolf
2025-10-31  9:25 ` Richard Henderson
2023-05-17 16:50 Kevin Wolf
2022-09-30 16:52 Kevin Wolf
2022-10-03 23:02 ` Stefan Hajnoczi
2022-06-09 17:21 Kevin Wolf
2022-06-09 20:18 ` Richard Henderson
2022-06-13 17:04   ` Kevin Wolf

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.