qemu/tests/test-block-iothread.c
<<
>>
Prefs
   1/*
   2 * Block tests for iothreads
   3 *
   4 * Copyright (c) 2018 Kevin Wolf <kwolf@redhat.com>
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "qemu/osdep.h"
  26#include "block/block.h"
  27#include "block/blockjob_int.h"
  28#include "sysemu/block-backend.h"
  29#include "qapi/error.h"
  30#include "iothread.h"
  31
  32static int coroutine_fn bdrv_test_co_prwv(BlockDriverState *bs,
  33                                          uint64_t offset, uint64_t bytes,
  34                                          QEMUIOVector *qiov, int flags)
  35{
  36    return 0;
  37}
  38
  39static int coroutine_fn bdrv_test_co_pdiscard(BlockDriverState *bs,
  40                                              int64_t offset, int bytes)
  41{
  42    return 0;
  43}
  44
  45static int coroutine_fn
  46bdrv_test_co_truncate(BlockDriverState *bs, int64_t offset,
  47                      PreallocMode prealloc, Error **errp)
  48{
  49    return 0;
  50}
  51
  52static int coroutine_fn bdrv_test_co_block_status(BlockDriverState *bs,
  53                                                  bool want_zero,
  54                                                  int64_t offset, int64_t count,
  55                                                  int64_t *pnum, int64_t *map,
  56                                                  BlockDriverState **file)
  57{
  58    *pnum = count;
  59    return 0;
  60}
  61
  62static BlockDriver bdrv_test = {
  63    .format_name            = "test",
  64    .instance_size          = 1,
  65
  66    .bdrv_co_preadv         = bdrv_test_co_prwv,
  67    .bdrv_co_pwritev        = bdrv_test_co_prwv,
  68    .bdrv_co_pdiscard       = bdrv_test_co_pdiscard,
  69    .bdrv_co_truncate       = bdrv_test_co_truncate,
  70    .bdrv_co_block_status   = bdrv_test_co_block_status,
  71};
  72
  73static void test_sync_op_pread(BdrvChild *c)
  74{
  75    uint8_t buf[512];
  76    int ret;
  77
  78    /* Success */
  79    ret = bdrv_pread(c, 0, buf, sizeof(buf));
  80    g_assert_cmpint(ret, ==, 512);
  81
  82    /* Early error: Negative offset */
  83    ret = bdrv_pread(c, -2, buf, sizeof(buf));
  84    g_assert_cmpint(ret, ==, -EIO);
  85}
  86
  87static void test_sync_op_pwrite(BdrvChild *c)
  88{
  89    uint8_t buf[512];
  90    int ret;
  91
  92    /* Success */
  93    ret = bdrv_pwrite(c, 0, buf, sizeof(buf));
  94    g_assert_cmpint(ret, ==, 512);
  95
  96    /* Early error: Negative offset */
  97    ret = bdrv_pwrite(c, -2, buf, sizeof(buf));
  98    g_assert_cmpint(ret, ==, -EIO);
  99}
 100
 101static void test_sync_op_blk_pread(BlockBackend *blk)
 102{
 103    uint8_t buf[512];
 104    int ret;
 105
 106    /* Success */
 107    ret = blk_pread(blk, 0, buf, sizeof(buf));
 108    g_assert_cmpint(ret, ==, 512);
 109
 110    /* Early error: Negative offset */
 111    ret = blk_pread(blk, -2, buf, sizeof(buf));
 112    g_assert_cmpint(ret, ==, -EIO);
 113}
 114
 115static void test_sync_op_blk_pwrite(BlockBackend *blk)
 116{
 117    uint8_t buf[512];
 118    int ret;
 119
 120    /* Success */
 121    ret = blk_pwrite(blk, 0, buf, sizeof(buf), 0);
 122    g_assert_cmpint(ret, ==, 512);
 123
 124    /* Early error: Negative offset */
 125    ret = blk_pwrite(blk, -2, buf, sizeof(buf), 0);
 126    g_assert_cmpint(ret, ==, -EIO);
 127}
 128
 129static void test_sync_op_load_vmstate(BdrvChild *c)
 130{
 131    uint8_t buf[512];
 132    int ret;
 133
 134    /* Error: Driver does not support snapshots */
 135    ret = bdrv_load_vmstate(c->bs, buf, 0, sizeof(buf));
 136    g_assert_cmpint(ret, ==, -ENOTSUP);
 137}
 138
 139static void test_sync_op_save_vmstate(BdrvChild *c)
 140{
 141    uint8_t buf[512];
 142    int ret;
 143
 144    /* Error: Driver does not support snapshots */
 145    ret = bdrv_save_vmstate(c->bs, buf, 0, sizeof(buf));
 146    g_assert_cmpint(ret, ==, -ENOTSUP);
 147}
 148
 149static void test_sync_op_pdiscard(BdrvChild *c)
 150{
 151    int ret;
 152
 153    /* Normal success path */
 154    c->bs->open_flags |= BDRV_O_UNMAP;
 155    ret = bdrv_pdiscard(c, 0, 512);
 156    g_assert_cmpint(ret, ==, 0);
 157
 158    /* Early success: UNMAP not supported */
 159    c->bs->open_flags &= ~BDRV_O_UNMAP;
 160    ret = bdrv_pdiscard(c, 0, 512);
 161    g_assert_cmpint(ret, ==, 0);
 162
 163    /* Early error: Negative offset */
 164    ret = bdrv_pdiscard(c, -2, 512);
 165    g_assert_cmpint(ret, ==, -EIO);
 166}
 167
 168static void test_sync_op_blk_pdiscard(BlockBackend *blk)
 169{
 170    int ret;
 171
 172    /* Early success: UNMAP not supported */
 173    ret = blk_pdiscard(blk, 0, 512);
 174    g_assert_cmpint(ret, ==, 0);
 175
 176    /* Early error: Negative offset */
 177    ret = blk_pdiscard(blk, -2, 512);
 178    g_assert_cmpint(ret, ==, -EIO);
 179}
 180
 181static void test_sync_op_truncate(BdrvChild *c)
 182{
 183    int ret;
 184
 185    /* Normal success path */
 186    ret = bdrv_truncate(c, 65536, PREALLOC_MODE_OFF, NULL);
 187    g_assert_cmpint(ret, ==, 0);
 188
 189    /* Early error: Negative offset */
 190    ret = bdrv_truncate(c, -2, PREALLOC_MODE_OFF, NULL);
 191    g_assert_cmpint(ret, ==, -EINVAL);
 192
 193    /* Error: Read-only image */
 194    c->bs->read_only = true;
 195    c->bs->open_flags &= ~BDRV_O_RDWR;
 196
 197    ret = bdrv_truncate(c, 65536, PREALLOC_MODE_OFF, NULL);
 198    g_assert_cmpint(ret, ==, -EACCES);
 199
 200    c->bs->read_only = false;
 201    c->bs->open_flags |= BDRV_O_RDWR;
 202}
 203
 204static void test_sync_op_block_status(BdrvChild *c)
 205{
 206    int ret;
 207    int64_t n;
 208
 209    /* Normal success path */
 210    ret = bdrv_is_allocated(c->bs, 0, 65536, &n);
 211    g_assert_cmpint(ret, ==, 0);
 212
 213    /* Early success: No driver support */
 214    bdrv_test.bdrv_co_block_status = NULL;
 215    ret = bdrv_is_allocated(c->bs, 0, 65536, &n);
 216    g_assert_cmpint(ret, ==, 1);
 217
 218    /* Early success: bytes = 0 */
 219    ret = bdrv_is_allocated(c->bs, 0, 0, &n);
 220    g_assert_cmpint(ret, ==, 0);
 221
 222    /* Early success: Offset > image size*/
 223    ret = bdrv_is_allocated(c->bs, 0x1000000, 0x1000000, &n);
 224    g_assert_cmpint(ret, ==, 0);
 225}
 226
 227static void test_sync_op_flush(BdrvChild *c)
 228{
 229    int ret;
 230
 231    /* Normal success path */
 232    ret = bdrv_flush(c->bs);
 233    g_assert_cmpint(ret, ==, 0);
 234
 235    /* Early success: Read-only image */
 236    c->bs->read_only = true;
 237    c->bs->open_flags &= ~BDRV_O_RDWR;
 238
 239    ret = bdrv_flush(c->bs);
 240    g_assert_cmpint(ret, ==, 0);
 241
 242    c->bs->read_only = false;
 243    c->bs->open_flags |= BDRV_O_RDWR;
 244}
 245
 246static void test_sync_op_blk_flush(BlockBackend *blk)
 247{
 248    BlockDriverState *bs = blk_bs(blk);
 249    int ret;
 250
 251    /* Normal success path */
 252    ret = blk_flush(blk);
 253    g_assert_cmpint(ret, ==, 0);
 254
 255    /* Early success: Read-only image */
 256    bs->read_only = true;
 257    bs->open_flags &= ~BDRV_O_RDWR;
 258
 259    ret = blk_flush(blk);
 260    g_assert_cmpint(ret, ==, 0);
 261
 262    bs->read_only = false;
 263    bs->open_flags |= BDRV_O_RDWR;
 264}
 265
 266static void test_sync_op_check(BdrvChild *c)
 267{
 268    BdrvCheckResult result;
 269    int ret;
 270
 271    /* Error: Driver does not implement check */
 272    ret = bdrv_check(c->bs, &result, 0);
 273    g_assert_cmpint(ret, ==, -ENOTSUP);
 274}
 275
 276static void test_sync_op_invalidate_cache(BdrvChild *c)
 277{
 278    /* Early success: Image is not inactive */
 279    bdrv_invalidate_cache(c->bs, NULL);
 280}
 281
 282
 283typedef struct SyncOpTest {
 284    const char *name;
 285    void (*fn)(BdrvChild *c);
 286    void (*blkfn)(BlockBackend *blk);
 287} SyncOpTest;
 288
 289const SyncOpTest sync_op_tests[] = {
 290    {
 291        .name   = "/sync-op/pread",
 292        .fn     = test_sync_op_pread,
 293        .blkfn  = test_sync_op_blk_pread,
 294    }, {
 295        .name   = "/sync-op/pwrite",
 296        .fn     = test_sync_op_pwrite,
 297        .blkfn  = test_sync_op_blk_pwrite,
 298    }, {
 299        .name   = "/sync-op/load_vmstate",
 300        .fn     = test_sync_op_load_vmstate,
 301    }, {
 302        .name   = "/sync-op/save_vmstate",
 303        .fn     = test_sync_op_save_vmstate,
 304    }, {
 305        .name   = "/sync-op/pdiscard",
 306        .fn     = test_sync_op_pdiscard,
 307        .blkfn  = test_sync_op_blk_pdiscard,
 308    }, {
 309        .name   = "/sync-op/truncate",
 310        .fn     = test_sync_op_truncate,
 311    }, {
 312        .name   = "/sync-op/block_status",
 313        .fn     = test_sync_op_block_status,
 314    }, {
 315        .name   = "/sync-op/flush",
 316        .fn     = test_sync_op_flush,
 317        .blkfn  = test_sync_op_blk_flush,
 318    }, {
 319        .name   = "/sync-op/check",
 320        .fn     = test_sync_op_check,
 321    }, {
 322        .name   = "/sync-op/invalidate_cache",
 323        .fn     = test_sync_op_invalidate_cache,
 324    },
 325};
 326
 327/* Test synchronous operations that run in a different iothread, so we have to
 328 * poll for the coroutine there to return. */
 329static void test_sync_op(const void *opaque)
 330{
 331    const SyncOpTest *t = opaque;
 332    IOThread *iothread = iothread_new();
 333    AioContext *ctx = iothread_get_aio_context(iothread);
 334    BlockBackend *blk;
 335    BlockDriverState *bs;
 336    BdrvChild *c;
 337
 338    blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
 339    bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
 340    bs->total_sectors = 65536 / BDRV_SECTOR_SIZE;
 341    blk_insert_bs(blk, bs, &error_abort);
 342    c = QLIST_FIRST(&bs->parents);
 343
 344    blk_set_aio_context(blk, ctx);
 345    aio_context_acquire(ctx);
 346    t->fn(c);
 347    if (t->blkfn) {
 348        t->blkfn(blk);
 349    }
 350    aio_context_release(ctx);
 351    blk_set_aio_context(blk, qemu_get_aio_context());
 352
 353    bdrv_unref(bs);
 354    blk_unref(blk);
 355}
 356
 357int main(int argc, char **argv)
 358{
 359    int i;
 360
 361    bdrv_init();
 362    qemu_init_main_loop(&error_abort);
 363
 364    g_test_init(&argc, &argv, NULL);
 365
 366    for (i = 0; i < ARRAY_SIZE(sync_op_tests); i++) {
 367        const SyncOpTest *t = &sync_op_tests[i];
 368        g_test_add_data_func(t->name, t, test_sync_op);
 369    }
 370
 371    return g_test_run();
 372}
 373