Filters cannot compress data themselves but they have to implement .bdrv_co_pwritev_compressed() still (or they cannot forward compressed writes). Therefore, checking whether bs->drv->bdrv_co_pwritev_compressed is non-NULL is not sufficient to know whether the node can actually handle compressed writes. This function looks down the filter chain to see whether there is a non-filter that can actually convert the compressed writes into compressed data (and thus normal writes).
Signed-off-by: Max Reitz <mre...@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsement...@virtuozzo.com> --- include/block/block.h | 1 + block.c | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/include/block/block.h b/include/block/block.h index 9cfe77abaf..6ba853fb90 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -487,6 +487,7 @@ BlockDriverState *bdrv_next(BdrvNextIterator *it); void bdrv_next_cleanup(BdrvNextIterator *it); BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs); +bool bdrv_supports_compressed_writes(BlockDriverState *bs); void bdrv_iterate_format(void (*it)(void *opaque, const char *name), void *opaque, bool read_only); const char *bdrv_get_node_name(const BlockDriverState *bs); diff --git a/block.c b/block.c index 415c555bf5..029c809a8e 100644 --- a/block.c +++ b/block.c @@ -4696,6 +4696,28 @@ bool bdrv_is_sg(BlockDriverState *bs) return bs->sg; } +/** + * Return whether the given node supports compressed writes. + */ +bool bdrv_supports_compressed_writes(BlockDriverState *bs) +{ + BlockDriverState *filtered = bdrv_filtered_rw_bs(bs); + + if (!bs->drv || !bs->drv->bdrv_co_pwritev_compressed) { + return false; + } + + if (filtered) { + /* + * Filters can only forward compressed writes, so we have to + * check the child. + */ + return bdrv_supports_compressed_writes(filtered); + } + + return true; +} + const char *bdrv_get_format_name(BlockDriverState *bs) { return bs->drv ? bs->drv->format_name : NULL; -- 2.21.0