Commit 465bee1d authored by Peter Lieven's avatar Peter Lieven Committed by Kevin Wolf
Browse files

block: optimize zero writes with bdrv_write_zeroes



this patch tries to optimize zero write requests
by automatically using bdrv_write_zeroes if it is
supported by the format.

This significantly speeds up file system initialization and
should speed zero write test used to test backend storage
performance.

I ran the following 2 tests on my internal SSD with a
50G QCOW2 container and on an attached iSCSI storage.

a) mkfs.ext4 -E lazy_itable_init=0,lazy_journal_init=0 /dev/vdX

QCOW2         [off]     [on]     [unmap]
-----
runtime:       14secs    1.1secs  1.1secs
filesize:      937M      18M      18M

iSCSI         [off]     [on]     [unmap]
----
runtime:       9.3s      0.9s     0.9s

b) dd if=/dev/zero of=/dev/vdX bs=1M oflag=direct

QCOW2         [off]     [on]     [unmap]
-----
runtime:       246secs   18secs   18secs
filesize:      51G       192K     192K
throughput:    203M/s    2.3G/s   2.3G/s

iSCSI*        [off]     [on]     [unmap]
----
runtime:       8mins     45secs   33secs
throughput:    106M/s    1.2G/s   1.6G/s
allocated:     100%      100%     0%

* The storage was connected via an 1Gbit interface.
  It seems to internally handle writing zeroes
  via WRITESAME16 very fast.

Signed-off-by: default avatarPeter Lieven <pl@kamp.de>
Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
parent 82a402e9
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -3289,6 +3289,15 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,

    ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);

    if (!ret && bs->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF &&
        !(flags & BDRV_REQ_ZERO_WRITE) && drv->bdrv_co_write_zeroes &&
        qemu_iovec_is_zero(qiov)) {
        flags |= BDRV_REQ_ZERO_WRITE;
        if (bs->detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP) {
            flags |= BDRV_REQ_MAY_UNMAP;
        }
    }

    if (ret < 0) {
        /* Do nothing, write notifier decided to fail this request */
    } else if (flags & BDRV_REQ_ZERO_WRITE) {
+1 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs)
    }

    info->backing_file_depth = bdrv_get_backing_file_depth(bs);
    info->detect_zeroes = bs->detect_zeroes;

    if (bs->io_limits_enabled) {
        ThrottleConfig cfg;
+24 −0
Original line number Diff line number Diff line
@@ -343,6 +343,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
    QemuOpts *opts;
    const char *id;
    bool has_driver_specific_opts;
    BlockdevDetectZeroesOptions detect_zeroes;
    BlockDriver *drv = NULL;

    /* Check common options by copying from bs_opts to opts, all other options
@@ -471,6 +472,24 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
        }
    }

    detect_zeroes =
        parse_enum_option(BlockdevDetectZeroesOptions_lookup,
                          qemu_opt_get(opts, "detect-zeroes"),
                          BLOCKDEV_DETECT_ZEROES_OPTIONS_MAX,
                          BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
                          &error);
    if (error) {
        error_propagate(errp, error);
        goto early_err;
    }

    if (detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
        !(bdrv_flags & BDRV_O_UNMAP)) {
        error_setg(errp, "setting detect-zeroes to unmap is not allowed "
                         "without setting discard operation to unmap");
        goto early_err;
    }

    /* init */
    dinfo = g_malloc0(sizeof(*dinfo));
    dinfo->id = g_strdup(qemu_opts_id(opts));
@@ -481,6 +500,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
    }
    dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
    dinfo->bdrv->read_only = ro;
    dinfo->bdrv->detect_zeroes = detect_zeroes;
    dinfo->refcount = 1;
    if (serial != NULL) {
        dinfo->serial = g_strdup(serial);
@@ -2474,6 +2494,10 @@ QemuOptsList qemu_common_drive_opts = {
            .name = "copy-on-read",
            .type = QEMU_OPT_BOOL,
            .help = "copy read data from backing file into image file",
        },{
            .name = "detect-zeroes",
            .type = QEMU_OPT_STRING,
            .help = "try to optimize zero writes (off, on, unmap)",
        },
        { /* end of list */ }
    },
+5 −0
Original line number Diff line number Diff line
@@ -341,6 +341,11 @@ void hmp_info_block(Monitor *mon, const QDict *qdict)
                           info->value->inserted->backing_file_depth);
        }

        if (info->value->inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) {
            monitor_printf(mon, "    Detect zeroes:    %s\n",
                           BlockdevDetectZeroesOptions_lookup[info->value->inserted->detect_zeroes]);
        }

        if (info->value->inserted->bps
            || info->value->inserted->bps_rd
            || info->value->inserted->bps_wr
+1 −0
Original line number Diff line number Diff line
@@ -364,6 +364,7 @@ struct BlockDriverState {
    BlockJob *job;

    QDict *options;
    BlockdevDetectZeroesOptions detect_zeroes;
};

int get_tmp_filename(char *filename, int size);
Loading